use crate::errors::{Error, Result};
use crate::message::MessageWrite;
use byteorder::{ByteOrder, LittleEndian as LE};
#[cfg(feature = "std")]
use byteorder::WriteBytesExt;
pub struct Writer<W: WriterBackend> {
inner: W,
}
impl<W: WriterBackend> Writer<W> {
pub fn new(w: W) -> Writer<W> {
Writer { inner: w }
}
pub fn write_u8(&mut self, byte: u8) -> Result<()> {
self.inner.pb_write_u8(byte)
}
pub fn write_varint(&mut self, mut v: u64) -> Result<()> {
while v > 0x7F {
self.inner.pb_write_u8(((v as u8) & 0x7F) | 0x80)?;
v >>= 7;
}
self.inner.pb_write_u8(v as u8)
}
#[cfg_attr(std, inline(always))]
pub fn write_tag(&mut self, tag: u32) -> Result<()> {
self.write_varint(tag as u64)
}
#[cfg_attr(std, inline(always))]
pub fn write_int32(&mut self, v: i32) -> Result<()> {
self.write_varint(v as u64)
}
#[cfg_attr(std, inline(always))]
pub fn write_int64(&mut self, v: i64) -> Result<()> {
self.write_varint(v as u64)
}
#[cfg_attr(std, inline(always))]
pub fn write_uint32(&mut self, v: u32) -> Result<()> {
self.write_varint(v as u64)
}
#[cfg_attr(std, inline(always))]
pub fn write_uint64(&mut self, v: u64) -> Result<()> {
self.write_varint(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_sint32(&mut self, v: i32) -> Result<()> {
self.write_varint(((v << 1) ^ (v >> 31)) as u64)
}
#[cfg_attr(std, inline(always))]
pub fn write_sint64(&mut self, v: i64) -> Result<()> {
self.write_varint(((v << 1) ^ (v >> 63)) as u64)
}
#[cfg_attr(std, inline(always))]
pub fn write_fixed64(&mut self, v: u64) -> Result<()> {
self.inner.pb_write_u64(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_fixed32(&mut self, v: u32) -> Result<()> {
self.inner.pb_write_u32(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_sfixed64(&mut self, v: i64) -> Result<()> {
self.inner.pb_write_i64(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_sfixed32(&mut self, v: i32) -> Result<()> {
self.inner.pb_write_i32(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_float(&mut self, v: f32) -> Result<()> {
self.inner.pb_write_f32(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_double(&mut self, v: f64) -> Result<()> {
self.inner.pb_write_f64(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_bool(&mut self, v: bool) -> Result<()> {
self.inner.pb_write_u8(if v { 1 } else { 0 })
}
#[cfg_attr(std, inline(always))]
pub fn write_enum(&mut self, v: i32) -> Result<()> {
self.write_int32(v)
}
#[cfg_attr(std, inline(always))]
pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
self.write_varint(bytes.len() as u64)?;
self.inner.pb_write_all(bytes)
}
#[cfg_attr(std, inline(always))]
pub fn write_string(&mut self, s: &str) -> Result<()> {
self.write_bytes(s.as_bytes())
}
pub fn write_packed<M, F, S>(&mut self, v: &[M], mut write: F, size: &S) -> Result<()>
where
F: FnMut(&mut Self, &M) -> Result<()>,
S: Fn(&M) -> usize,
{
if v.is_empty() {
return Ok(());
}
let len: usize = v.iter().map(|m| size(m)).sum();
self.write_varint(len as u64)?;
for m in v {
write(self, m)?;
}
Ok(())
}
#[cfg_attr(std, inline)]
pub fn write_packed_fixed<M>(&mut self, v: &[M]) -> Result<()> {
let len = v.len() * ::core::mem::size_of::<M>();
let bytes = unsafe { ::core::slice::from_raw_parts(v.as_ptr() as *const u8, len) };
self.write_bytes(bytes)
}
#[cfg_attr(std, inline)]
pub fn write_message<M: MessageWrite>(&mut self, m: &M) -> Result<()> {
let len = m.get_size();
self.write_varint(len as u64)?;
m.write_message(self)
}
#[cfg_attr(std, inline)]
pub fn write_with_tag<F>(&mut self, tag: u32, mut write: F) -> Result<()>
where
F: FnMut(&mut Self) -> Result<()>,
{
self.write_tag(tag)?;
write(self)
}
pub fn write_packed_with_tag<M, F, S>(
&mut self,
tag: u32,
v: &[M],
mut write: F,
size: &S,
) -> Result<()>
where
F: FnMut(&mut Self, &M) -> Result<()>,
S: Fn(&M) -> usize,
{
if v.is_empty() {
return Ok(());
}
self.write_tag(tag)?;
let len: usize = v.iter().map(|m| size(m)).sum();
self.write_varint(len as u64)?;
for m in v {
write(self, m)?;
}
Ok(())
}
pub fn write_packed_fixed_with_tag<M>(&mut self, tag: u32, v: &[M]) -> Result<()> {
if v.is_empty() {
return Ok(());
}
self.write_tag(tag)?;
let len = ::core::mem::size_of::<M>() * v.len();
let bytes = unsafe { ::core::slice::from_raw_parts(v.as_ptr() as *const u8, len) };
self.write_bytes(bytes)
}
pub fn write_packed_fixed_size_with_tag<M>(
&mut self,
tag: u32,
v: &[M],
item_size: usize,
) -> Result<()> {
if v.is_empty() {
return Ok(());
}
self.write_tag(tag)?;
let len = v.len() * item_size;
let bytes =
unsafe { ::core::slice::from_raw_parts(v as *const [M] as *const M as *const u8, len) };
self.write_bytes(bytes)
}
pub fn write_map<FK, FV>(
&mut self,
size: usize,
tag_key: u32,
mut write_key: FK,
tag_val: u32,
mut write_val: FV,
) -> Result<()>
where
FK: FnMut(&mut Self) -> Result<()>,
FV: FnMut(&mut Self) -> Result<()>,
{
self.write_varint(size as u64)?;
self.write_tag(tag_key)?;
write_key(self)?;
self.write_tag(tag_val)?;
write_val(self)
}
}
#[cfg(feature = "std")]
pub fn serialize_into_vec<M: MessageWrite>(message: &M) -> Result<Vec<u8>> {
let len = message.get_size();
let mut v = Vec::with_capacity(crate::sizeofs::sizeof_len(len));
{
let mut writer = Writer::new(&mut v);
writer.write_message(message)?;
}
Ok(v)
}
pub fn serialize_into_slice<M: MessageWrite>(message: &M, out: &mut [u8]) -> Result<()> {
let len = message.get_size();
if out.len() < crate::sizeofs::sizeof_len(len) {
return Err(Error::OutputBufferTooSmall);
}
{
let mut writer = Writer::new(BytesWriter::new(out));
writer.write_message(message)?;
}
Ok(())
}
pub trait WriterBackend {
fn pb_write_u8(&mut self, x: u8) -> Result<()>;
fn pb_write_u32(&mut self, x: u32) -> Result<()>;
fn pb_write_i32(&mut self, x: i32) -> Result<()>;
fn pb_write_f32(&mut self, x: f32) -> Result<()>;
fn pb_write_u64(&mut self, x: u64) -> Result<()>;
fn pb_write_i64(&mut self, x: i64) -> Result<()>;
fn pb_write_f64(&mut self, x: f64) -> Result<()>;
fn pb_write_all(&mut self, buf: &[u8]) -> Result<()>;
}
pub struct BytesWriter<'a> {
buf: &'a mut [u8],
cursor: usize,
}
impl<'a> BytesWriter<'a> {
pub fn new(buf: &'a mut [u8]) -> BytesWriter<'a> {
BytesWriter { buf, cursor: 0 }
}
}
impl<'a> WriterBackend for BytesWriter<'a> {
#[cfg_attr(std, inline(always))]
fn pb_write_u8(&mut self, x: u8) -> Result<()> {
if self.buf.len() - self.cursor < 1 {
Err(Error::UnexpectedEndOfBuffer)
} else {
self.buf[self.cursor] = x;
self.cursor += 1;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_u32(&mut self, x: u32) -> Result<()> {
if self.buf.len() - self.cursor < 4 {
Err(Error::UnexpectedEndOfBuffer)
} else {
LE::write_u32(&mut self.buf[self.cursor..], x);
self.cursor += 4;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_i32(&mut self, x: i32) -> Result<()> {
if self.buf.len() - self.cursor < 4 {
Err(Error::UnexpectedEndOfBuffer)
} else {
LE::write_i32(&mut self.buf[self.cursor..], x);
self.cursor += 4;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_f32(&mut self, x: f32) -> Result<()> {
if self.buf.len() - self.cursor < 4 {
Err(Error::UnexpectedEndOfBuffer)
} else {
LE::write_f32(&mut self.buf[self.cursor..], x);
self.cursor += 4;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_u64(&mut self, x: u64) -> Result<()> {
if self.buf.len() - self.cursor < 8 {
Err(Error::UnexpectedEndOfBuffer)
} else {
LE::write_u64(&mut self.buf[self.cursor..], x);
self.cursor += 8;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_i64(&mut self, x: i64) -> Result<()> {
if self.buf.len() - self.cursor < 8 {
Err(Error::UnexpectedEndOfBuffer)
} else {
LE::write_i64(&mut self.buf[self.cursor..], x);
self.cursor += 8;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_f64(&mut self, x: f64) -> Result<()> {
if self.buf.len() - self.cursor < 8 {
Err(Error::UnexpectedEndOfBuffer)
} else {
LE::write_f64(&mut self.buf[self.cursor..], x);
self.cursor += 8;
Ok(())
}
}
#[cfg_attr(std, inline(always))]
fn pb_write_all(&mut self, buf: &[u8]) -> Result<()> {
if self.buf.len() - self.cursor < buf.len() {
Err(Error::UnexpectedEndOfBuffer)
} else {
self.buf[self.cursor..(self.cursor + buf.len())].copy_from_slice(buf);
self.cursor += buf.len();
Ok(())
}
}
}
#[cfg(feature = "std")]
impl<W: std::io::Write> WriterBackend for W {
#[inline(always)]
fn pb_write_u8(&mut self, x: u8) -> Result<()> {
self.write_u8(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_u32(&mut self, x: u32) -> Result<()> {
self.write_u32::<LE>(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_i32(&mut self, x: i32) -> Result<()> {
self.write_i32::<LE>(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_f32(&mut self, x: f32) -> Result<()> {
self.write_f32::<LE>(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_u64(&mut self, x: u64) -> Result<()> {
self.write_u64::<LE>(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_i64(&mut self, x: i64) -> Result<()> {
self.write_i64::<LE>(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_f64(&mut self, x: f64) -> Result<()> {
self.write_f64::<LE>(x).map_err(|e| e.into())
}
#[inline(always)]
fn pb_write_all(&mut self, buf: &[u8]) -> Result<()> {
self.write_all(buf).map_err(|e| e.into())
}
}
#[test]
fn test_issue_222() {
struct TestMsg {}
impl MessageWrite for TestMsg {
fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
let bytes = [0x08u8, 0x96u8, 0x01u8];
for b in bytes {
w.write_u8(b)?;
}
Ok(())
}
fn get_size(&self) -> usize {
3 }
}
let msg = TestMsg {};
let v = serialize_into_vec(&msg).unwrap();
assert_eq!(v.len(), v.capacity());
let mut buf_len_2 = vec![0x00u8, 0x00u8];
let mut buf_len_3 = vec![0x00u8, 0x00u8, 0x00u8];
let mut buf_len_4 = vec![0x00u8, 0x00u8, 0x00u8, 0x00u8];
assert!(matches!(
serialize_into_slice(&msg, buf_len_2.as_mut_slice()),
Err(Error::OutputBufferTooSmall)
));
assert!(matches!(
serialize_into_slice(&msg, buf_len_3.as_mut_slice()),
Err(Error::OutputBufferTooSmall)
));
assert!(matches!(
serialize_into_slice(&msg, buf_len_4.as_mut_slice()),
Ok(())
));
}