///|
/// 与 Decoder 对称的有界二进制写入器。
pub struct Encoder {
buffer : @buffer.Buffer
mut bit_buffer : UInt
mut bit_count : Int
mut field_path : String
limits : Limits
}
///|
pub fn Encoder::new(limits : Limits) -> Encoder {
{
buffer: @buffer.Buffer(),
bit_buffer: 0U,
bit_count: 0,
field_path: "",
limits,
}
}
///|
pub fn Encoder::path(self : Encoder) -> String {
self.field_path
}
///|
pub fn Encoder::max_collection_length(self : Encoder) -> Int {
self.limits.max_collection_length
}
///|
fn[T] Encoder::with_path(
self : Encoder,
name : String,
action : () -> Result[T, BinError],
) -> Result[T, BinError] {
let previous = self.field_path
self.field_path = if previous == "" { name } else { previous + "." + name }
let result = action()
self.field_path = previous
result
}
///|
fn Encoder::error(
self : Encoder,
kind : ErrorKind,
message : String,
) -> BinError {
BinError::new(kind, self.length(), self.field_path, message)
}
///|
pub fn Encoder::length(self : Encoder) -> Int {
self.buffer.length()
}
///|
fn Encoder::ensure_capacity(
self : Encoder,
additional : Int,
) -> Result[Unit, BinError] {
if additional < 0 ||
self.length() > self.limits.max_output_bytes ||
additional > self.limits.max_output_bytes - self.length() {
Err(self.error(LimitExceeded, "encoded output exceeds max_output_bytes"))
} else {
Ok(())
}
}
///|
fn Encoder::write_zeroes(self : Encoder, count : Int) -> Result[Unit, BinError] {
if self.bit_count != 0 {
return Err(self.error(Misaligned, "operation requires byte alignment"))
}
match self.ensure_capacity(count) {
Err(error) => Err(error)
Ok(_) => {
for _ in 0.. Result[Unit, BinError] {
if self.bit_count != 0 {
return Err(self.error(Misaligned, "operation requires byte alignment"))
}
match self.ensure_capacity(bytes.length()) {
Err(error) => Err(error)
Ok(_) => {
self.buffer.write_bytes(bytes)
Ok(())
}
}
}
///|
pub fn Encoder::write_uint(
self : Encoder,
value : UInt,
width : Int,
endian : Endian,
) -> Result[Unit, BinError] {
guard width == 1 || width == 2 || width == 4 else {
return Err(self.error(Unsupported, "UInt width must be 1, 2, or 4"))
}
if (width == 1 && value > 0xffU) || (width == 2 && value > 0xffffU) {
return Err(
self.error(InvalidValue, "unsigned value does not fit requested width"),
)
}
let output : Array[Byte] = []
match endian {
Big =>
for index = 0; index < width; index = index + 1 {
let shift = (width - index - 1) * 8
output.push((value >> shift).to_byte())
}
Little =>
for index = 0; index < width; index = index + 1 {
output.push((value >> (index * 8)).to_byte())
}
}
self.write_bytes(Bytes::from_array(output)[:])
}
///|
pub fn Encoder::write_uint64(
self : Encoder,
value : UInt64,
endian : Endian,
) -> Result[Unit, BinError] {
let output : Array[Byte] = []
match endian {
Big =>
for index = 0; index < 8; index = index + 1 {
output.push((value >> ((7 - index) * 8)).to_byte())
}
Little =>
for index = 0; index < 8; index = index + 1 {
output.push((value >> (index * 8)).to_byte())
}
}
self.write_bytes(Bytes::from_array(output)[:])
}
///|
pub fn Encoder::write_bits_msb(
self : Encoder,
value : UInt,
width : Int,
) -> Result[Unit, BinError] {
guard width > 0 && width <= 32 else {
return Err(self.error(InvalidValue, "bit width must be in 1..32"))
}
if width < 32 && value >= 1U << width {
return Err(
self.error(InvalidValue, "value does not fit requested bit width"),
)
}
for index = width - 1; index >= 0; index = index - 1 {
self.bit_buffer = (self.bit_buffer << 1) | ((value >> index) & 1U)
self.bit_count = self.bit_count + 1
if self.bit_count == 8 {
match self.ensure_capacity(1) {
Err(error) => return Err(error)
Ok(_) => self.buffer.write_byte(self.bit_buffer.to_byte())
}
self.bit_buffer = 0U
self.bit_count = 0
}
}
Ok(())
}
///|
pub fn Encoder::align_byte(
self : Encoder,
fill_bit? : Bool = false,
) -> Result[Unit, BinError] {
if self.bit_count == 0 {
return Ok(())
}
while self.bit_count < 8 {
self.bit_buffer = (self.bit_buffer << 1) | (if fill_bit { 1U } else { 0U })
self.bit_count = self.bit_count + 1
}
match self.ensure_capacity(1) {
Err(error) => Err(error)
Ok(_) => {
self.buffer.write_byte(self.bit_buffer.to_byte())
self.bit_buffer = 0U
self.bit_count = 0
Ok(())
}
}
}
///|
pub fn Encoder::finish(self : Encoder) -> Result[Bytes, BinError] {
match self.align_byte() {
Err(error) => Err(error)
Ok(_) => Ok(self.buffer.to_bytes())
}
}