nson 0.14.0

NSON is a lightweight data-interchange format like JSON or BSON
Documentation
//! Encode

use core::fmt;

use alloc::string::{String, ToString};
use alloc::vec::Vec;

#[cfg(feature = "std")]
use std::io::{self, Write};

#[cfg(not(feature = "std"))]
use crate::io::{self, Write};

#[cfg(feature = "serde")]
use crate::serde::encode::Encoder;
#[cfg(feature = "serde")]
use serde::ser::Serialize;

use crate::array::Array;
use crate::map::Map;
use crate::value::{Binary, Value};

#[derive(Debug)]
#[non_exhaustive]
pub enum EncodeError {
    IoError(io::Error),
    InvalidKeyLen(usize, String),
    InvalidValueLen(usize, String),
    Unknown(String),
    #[cfg(feature = "serde")]
    Serde(crate::serde::EncodeError),
}

impl From<io::Error> for EncodeError {
    fn from(err: io::Error) -> EncodeError {
        EncodeError::IoError(err)
    }
}

#[cfg(feature = "serde")]
impl From<crate::serde::EncodeError> for EncodeError {
    fn from(err: crate::serde::EncodeError) -> EncodeError {
        EncodeError::Serde(err)
    }
}

impl fmt::Display for EncodeError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EncodeError::IoError(ref inner) => inner.fmt(fmt),
            EncodeError::InvalidKeyLen(ref len, ref desc) => {
                write!(fmt, "Invalid key len: {}, {}", len, desc)
            }
            EncodeError::InvalidValueLen(ref len, ref desc) => {
                write!(fmt, "Invalid value len: {}, {}", len, desc)
            }
            EncodeError::Unknown(ref inner) => inner.fmt(fmt),
            #[cfg(feature = "serde")]
            EncodeError::Serde(ref inner) => inner.fmt(fmt),
        }
    }
}

impl core::error::Error for EncodeError {
    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
        match *self {
            EncodeError::IoError(ref inner) => Some(inner),
            #[cfg(feature = "serde")]
            EncodeError::Serde(ref inner) => Some(inner),
            _ => None,
        }
    }
}

pub type EncodeResult<T> = Result<T, EncodeError>;

#[inline]
pub(crate) fn write_i8(writer: &mut impl Write, val: i8) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_u8(writer: &mut impl Write, val: u8) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_i16(writer: &mut impl Write, val: i16) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_u16(writer: &mut impl Write, val: u16) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_i32(writer: &mut impl Write, val: i32) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_u32(writer: &mut impl Write, val: u32) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_i64(writer: &mut impl Write, val: i64) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_u64(writer: &mut impl Write, val: u64) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_f32(writer: &mut impl Write, val: f32) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

#[inline]
pub(crate) fn write_f64(writer: &mut impl Write, val: f64) -> EncodeResult<()> {
    writer.write_all(&val.to_le_bytes()).map_err(From::from)
}

pub(crate) fn write_key(writer: &mut impl Write, s: &str) -> EncodeResult<()> {
    if s.is_empty() || s.len() >= u8::MAX as usize {
        return Err(EncodeError::InvalidKeyLen(
            s.len(),
            "key len must > 0 and < 255".to_string(),
        ));
    }

    writer.write_all(&[s.len() as u8 + 1])?;
    writer.write_all(s.as_bytes())?;
    Ok(())
}

pub(crate) fn write_string(writer: &mut impl Write, s: &str) -> EncodeResult<()> {
    if s.len() > crate::MAX_NSON_SIZE as usize - 4 {
        return Err(EncodeError::InvalidValueLen(
            s.len(),
            "string len must < MAX_NSON_SIZE - 4".to_string(),
        ));
    }

    write_u32(writer, s.len() as u32 + 4)?;
    writer.write_all(s.as_bytes())?;
    Ok(())
}

pub(crate) fn write_binary(writer: &mut impl Write, binary: &Binary) -> EncodeResult<()> {
    if binary.0.len() > crate::MAX_NSON_SIZE as usize - 4 {
        return Err(EncodeError::InvalidValueLen(
            binary.0.len(),
            "binary len must < MAX_NSON_SIZE - 4".to_string(),
        ));
    }

    write_u32(writer, binary.0.len() as u32 + 4)?;
    writer.write_all(&binary.0)?;
    Ok(())
}

pub fn encode_array(writer: &mut impl Write, array: &Array) -> EncodeResult<()> {
    let len = array.bytes_size();

    if len > crate::MAX_NSON_SIZE as usize {
        return Err(EncodeError::InvalidValueLen(
            len,
            "array len must < MAX_NSON_SIZE".to_string(),
        ));
    }

    write_u32(writer, len as u32)?;

    for val in array.iter() {
        encode_value(writer, val)?;
    }

    writer.write_all(&[0])?;

    Ok(())
}

pub fn encode_map(writer: &mut impl Write, map: &Map) -> EncodeResult<()> {
    let len = map.bytes_size();

    if len > crate::MAX_NSON_SIZE as usize {
        return Err(EncodeError::InvalidValueLen(
            len,
            "map len must < MAX_NSON_SIZE".to_string(),
        ));
    }

    write_u32(writer, len as u32)?;

    for (key, val) in map {
        write_key(writer, key)?;

        encode_value(writer, val)?;
    }

    writer.write_all(&[0])?;

    Ok(())
}

pub fn encode_value(writer: &mut impl Write, val: &Value) -> EncodeResult<()> {
    writer.write_all(&[val.element_type() as u8])?;

    match *val {
        Value::F32(v) => write_f32(writer, v),
        Value::F64(v) => write_f64(writer, v),
        Value::I32(v) => write_i32(writer, v),
        Value::I64(v) => write_i64(writer, v),
        Value::U32(v) => write_u32(writer, v),
        Value::U64(v) => write_u64(writer, v),
        Value::I8(v) => write_i8(writer, v),
        Value::U8(v) => write_u8(writer, v),
        Value::I16(v) => write_i16(writer, v),
        Value::U16(v) => write_u16(writer, v),
        Value::String(ref s) => write_string(writer, s),
        Value::Array(ref a) => encode_array(writer, a),
        Value::Map(ref o) => encode_map(writer, o),
        Value::Bool(b) => writer
            .write_all(&[if b { 0x01 } else { 0x00 }])
            .map_err(From::from),
        Value::Null => Ok(()),
        Value::Binary(ref binary) => write_binary(writer, binary),
        Value::TimeStamp(v) => write_u64(writer, v.0),
        Value::Id(ref id) => writer.write_all(&id.bytes()).map_err(From::from),
    }
}

impl Value {
    pub fn to_bytes(&self) -> EncodeResult<Vec<u8>> {
        let mut buf = Vec::new();
        encode_value(&mut buf, self)?;
        Ok(buf)
    }
}

impl Map {
    pub fn to_bytes(&self) -> EncodeResult<Vec<u8>> {
        let len = self.bytes_size();

        if len > crate::MAX_NSON_SIZE as usize {
            return Err(EncodeError::InvalidValueLen(
                len,
                "map len must < MAX_NSON_SIZE".to_string(),
            ));
        }

        let mut buf = Vec::with_capacity(len);
        write_u32(&mut buf, len as u32)?;

        for (key, val) in self {
            write_key(&mut buf, key)?;

            encode_value(&mut buf, val)?;
        }

        buf.write_all(&[0])?;

        Ok(buf)
    }
}

impl Array {
    pub fn to_bytes(&self) -> EncodeResult<Vec<u8>> {
        let len = self.bytes_size();

        if len > crate::MAX_NSON_SIZE as usize {
            return Err(EncodeError::InvalidValueLen(
                len,
                "array len must < MAX_NSON_SIZE".to_string(),
            ));
        }

        let mut buf = Vec::with_capacity(len);
        write_u32(&mut buf, len as u32)?;

        for val in self.iter() {
            encode_value(&mut buf, val)?;
        }

        buf.write_all(&[0])?;

        Ok(buf)
    }
}

#[cfg(feature = "serde")]
pub fn to_nson<T: Serialize + ?Sized>(value: &T) -> EncodeResult<Value> {
    let ser = Encoder::new();
    value.serialize(ser).map_err(EncodeError::Serde)
}

#[cfg(feature = "serde")]
pub fn to_bytes<T: Serialize + ?Sized>(value: &T) -> EncodeResult<Vec<u8>> {
    let value = to_nson(value)?;
    value.to_bytes()
}

#[cfg(test)]
mod test {
    use crate::decode::decode_map;
    use crate::encode::encode_map;
    use crate::m;

    use alloc::vec::Vec;

    #[cfg(feature = "std")]
    use std::io::Cursor;

    #[cfg(not(feature = "std"))]
    use crate::io::Cursor;

    #[test]
    fn encode() {
        let m = m! {"aa": "bb", "cc": [1, 2, 3, 4]};

        let mut buf: Vec<u8> = Vec::new();

        encode_map(&mut buf, &m).unwrap();

        let mut reader = Cursor::new(buf);

        let m2 = decode_map(&mut reader).unwrap();

        assert_eq!(m, m2);
    }
}