use super::field_iter::{ProtoField, serialize_field};
use super::wire::{
WireType, encode_tag, encode_varint32, encode_varint64, zigzag_encode_i32, zigzag_encode_i64,
};
const MAX_LENGTH_DELIMITED: usize = i32::MAX as usize;
pub struct SerializedMessageWriter {
buf: Vec<u8>,
scope_stack: Vec<usize>,
}
impl SerializedMessageWriter {
pub fn new() -> Self {
SerializedMessageWriter {
buf: Vec::new(),
scope_stack: Vec::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
SerializedMessageWriter {
buf: Vec::with_capacity(capacity),
scope_stack: Vec::new(),
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.buf
}
pub fn finish(self) -> Result<Vec<u8>, crate::RiegeliError> {
if !self.scope_stack.is_empty() {
return Err(crate::RiegeliError::MalformedData(
format!(
"finish() called with {} unclosed length-delimited scope(s)",
self.scope_stack.len()
)
.into(),
));
}
Ok(self.buf)
}
pub fn write_uint64(
&mut self,
field_number: u32,
value: u64,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, value);
Ok(())
}
pub fn write_uint32(
&mut self,
field_number: u32,
value: u32,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, value as u64);
Ok(())
}
pub fn write_int64(
&mut self,
field_number: u32,
value: i64,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, value as u64);
Ok(())
}
pub fn write_int32(
&mut self,
field_number: u32,
value: i32,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, value as i64 as u64);
Ok(())
}
pub fn write_sint32(
&mut self,
field_number: u32,
value: i32,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, zigzag_encode_i32(value) as u64);
Ok(())
}
pub fn write_sint64(
&mut self,
field_number: u32,
value: i64,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, zigzag_encode_i64(value));
Ok(())
}
pub fn write_bool(
&mut self,
field_number: u32,
value: bool,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Varint);
encode_varint64(&mut self.buf, if value { 1 } else { 0 });
Ok(())
}
pub fn write_fixed32(
&mut self,
field_number: u32,
value: u32,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Fixed32);
self.buf.extend_from_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_fixed64(
&mut self,
field_number: u32,
value: u64,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Fixed64);
self.buf.extend_from_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_sfixed32(
&mut self,
field_number: u32,
value: i32,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Fixed32);
self.buf.extend_from_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_sfixed64(
&mut self,
field_number: u32,
value: i64,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Fixed64);
self.buf.extend_from_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_float(
&mut self,
field_number: u32,
value: f32,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Fixed32);
self.buf.extend_from_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_double(
&mut self,
field_number: u32,
value: f64,
) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::Fixed64);
self.buf.extend_from_slice(&value.to_le_bytes());
Ok(())
}
pub fn write_bytes(
&mut self,
field_number: u32,
data: &[u8],
) -> Result<(), crate::RiegeliError> {
if data.len() > MAX_LENGTH_DELIMITED {
return Err(crate::RiegeliError::MalformedData(
format!(
"length-delimited field length {} exceeds 2 GiB limit",
data.len()
)
.into(),
));
}
encode_tag(&mut self.buf, field_number, WireType::LengthDelimited);
encode_varint32(&mut self.buf, data.len() as u32);
self.buf.extend_from_slice(data);
Ok(())
}
pub fn write_string(&mut self, field_number: u32, s: &str) -> Result<(), crate::RiegeliError> {
self.write_bytes(field_number, s.as_bytes())
}
pub fn open_length_delimited(&mut self, field_number: u32) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::LengthDelimited);
self.scope_stack.push(self.buf.len());
Ok(())
}
pub fn close_length_delimited(&mut self) -> Result<(), crate::RiegeliError> {
let content_start = self.scope_stack.pop().ok_or_else(|| {
crate::RiegeliError::MalformedData(
"close_length_delimited() called without matching open".into(),
)
})?;
let content_len = self.buf.len() - content_start;
if content_len > MAX_LENGTH_DELIMITED {
return Err(crate::RiegeliError::MalformedData(
format!(
"length-delimited field length {} exceeds 2 GiB limit",
content_len
)
.into(),
));
}
let mut len_varint = Vec::new();
encode_varint32(&mut len_varint, content_len as u32);
self.buf
.splice(content_start..content_start, len_varint.iter().copied());
Ok(())
}
pub fn write_start_group(&mut self, field_number: u32) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::StartGroup);
Ok(())
}
pub fn write_end_group(&mut self, field_number: u32) -> Result<(), crate::RiegeliError> {
encode_tag(&mut self.buf, field_number, WireType::EndGroup);
Ok(())
}
pub fn write_field(&mut self, field: &ProtoField<'_>) -> Result<(), crate::RiegeliError> {
serialize_field(&mut self.buf, field);
Ok(())
}
}
impl Default for SerializedMessageWriter {
fn default() -> Self {
Self::new()
}
}