///|
/// Compresses `input` into one whole Zstandard frame. `level` and
/// `checksum` are as for `Encoder`; the frame states its content size, and
/// the parameters are chosen for it, so a small input declares a small
/// window (a single-segment frame, whose window is its content).
pub fn compress(
input : BytesView,
level~ : Int32 = DEFAULT_LEVEL,
checksum~ : Bool = true,
) -> Bytes {
let encoder = Encoder(
level~,
checksum~,
content_size=input.length().to_int64(),
)
// A block is never larger than its input and its 3-byte header, and the
// frame adds at most 18 header and 4 checksum bytes; one block more
// allows for an empty last block.
let n = input.length()
let blocks = n / encoder.block_max.max(1) + 2
let bound = n.to_int64() + 3L * blocks.to_int64() + 22L
encode_whole(encoder, input, bound.min(0x7fffffffL).to_int())
}
///|
/// Encodes all of `input` with `Finish` into one array of `capacity`
/// bytes, grown if the frame does not fit, and trims it with one copy.
fn encode_whole(
encoder : Encoder,
input : BytesView,
capacity : Int32,
) -> Bytes {
let mut out = FixedArray::make(capacity.max(1), b'\x00')
let mut pos = 0
let mut rest = input
for ;; {
// The input is exactly the content size given, so the step never
// raises.
let status = try! encoder.step(rest, out.mut_view(start=pos), action=Finish)
rest = rest[encoder.last_consumed():]
pos += encoder.last_produced()
if status is Done {
return if pos == out.length() {
// The array is not used again.
out.unsafe_reinterpret_as_bytes()
} else {
Bytes::from_array(out[:pos])
}
}
// Only NeedMoreOutput comes before Done under Finish: the array is
// full.
let grown = FixedArray::make(out.length() * 2, b'\x00')
FixedArray::unsafe_blit(grown, 0, out, 0, pos)
out = grown
}
}