extern crate alloc;
use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::marker::PhantomData;
use facet_core::{Def, ScalarType, Shape};
use facet_format::{
DynamicValueEncoding, DynamicValueTag, EnumVariantEncoding, FormatSerializer, MapEncoding,
SerializeError as FormatSerializeError, StructFieldMode, serialize_root,
serialize_value_with_shape,
};
use facet_reflect::Peek;
use crate::error::SerializeError;
use crate::raw_postcard;
pub trait Writer {
fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError>;
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError>;
}
impl Writer for Vec<u8> {
fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
self.push(byte);
Ok(())
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
self.extend_from_slice(bytes);
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Segment<'a> {
Staged { offset: usize, len: usize },
Reference { bytes: &'a [u8] },
}
#[derive(Debug, Clone)]
pub struct ScatterPlan<'a> {
staging: Vec<u8>,
segments: Vec<Segment<'a>>,
total_size: usize,
}
impl<'a> ScatterPlan<'a> {
pub const fn total_size(&self) -> usize {
self.total_size
}
pub fn staging(&self) -> &[u8] {
&self.staging
}
pub fn segments(&self) -> &[Segment<'a>] {
&self.segments
}
pub fn write_into(&self, dest: &mut [u8]) -> Result<(), SerializeError> {
if dest.len() != self.total_size {
return Err(SerializeError::Custom(alloc::format!(
"destination length mismatch: expected {}, got {}",
self.total_size,
dest.len()
)));
}
let mut cursor = 0usize;
for segment in &self.segments {
match segment {
Segment::Staged { offset, len } => {
let src = &self.staging[*offset..*offset + *len];
dest[cursor..cursor + *len].copy_from_slice(src);
cursor += *len;
}
Segment::Reference { bytes } => {
dest[cursor..cursor + bytes.len()].copy_from_slice(bytes);
cursor += bytes.len();
}
}
}
debug_assert_eq!(cursor, self.total_size);
Ok(())
}
}
struct ScatterBuilder<'a> {
staging: Vec<u8>,
segments: Vec<Segment<'a>>,
total_size: usize,
}
impl<'a> ScatterBuilder<'a> {
const fn new() -> Self {
Self {
staging: Vec::new(),
segments: Vec::new(),
total_size: 0,
}
}
fn finish(self) -> ScatterPlan<'a> {
ScatterPlan {
staging: self.staging,
segments: self.segments,
total_size: self.total_size,
}
}
fn push_staged_segment(&mut self, offset: usize, len: usize) {
if len == 0 {
return;
}
if let Some(Segment::Staged {
offset: prev_offset,
len: prev_len,
}) = self.segments.last_mut()
&& *prev_offset + *prev_len == offset
{
*prev_len += len;
return;
}
self.segments.push(Segment::Staged { offset, len });
}
fn push_reference_segment(&mut self, bytes: &[u8]) {
if bytes.is_empty() {
return;
}
#[allow(unsafe_code)]
let bytes: &'a [u8] = unsafe { core::mem::transmute(bytes) };
self.total_size += bytes.len();
self.segments.push(Segment::Reference { bytes });
}
}
impl Writer for ScatterBuilder<'_> {
fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
let offset = self.staging.len();
self.staging.push(byte);
self.total_size += 1;
self.push_staged_segment(offset, 1);
Ok(())
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
if bytes.is_empty() {
return Ok(());
}
let offset = self.staging.len();
self.staging.extend_from_slice(bytes);
self.total_size += bytes.len();
self.push_staged_segment(offset, bytes.len());
Ok(())
}
}
struct CopyWriter<'a, W: Writer + ?Sized> {
inner: &'a mut W,
}
impl<'a, W: Writer + ?Sized> CopyWriter<'a, W> {
const fn new(inner: &'a mut W) -> Self {
Self { inner }
}
}
impl<W: Writer + ?Sized> Writer for CopyWriter<'_, W> {
fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
self.inner.write_byte(byte)
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
self.inner.write_bytes(bytes)
}
}
trait PostcardWriter<'a>: Writer {
fn write_referenced_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError>;
}
impl<'a, W: Writer + ?Sized> PostcardWriter<'a> for CopyWriter<'_, W> {
fn write_referenced_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
self.inner.write_bytes(bytes)
}
}
impl<'a> PostcardWriter<'a> for ScatterBuilder<'a> {
fn write_referenced_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
self.push_reference_segment(bytes);
Ok(())
}
}
pub fn to_vec<'facet, T>(value: &T) -> Result<Vec<u8>, SerializeError>
where
T: facet_core::Facet<'facet>,
{
let mut buffer = Vec::new();
to_writer_fallible(value, &mut buffer)?;
Ok(buffer)
}
pub fn to_writer_fallible<'facet, T, W>(value: &T, writer: &mut W) -> Result<(), SerializeError>
where
T: facet_core::Facet<'facet>,
W: Writer,
{
let peek = Peek::new(value);
let mut serializer = PostcardSerializer::new(CopyWriter::new(writer));
serialize_root(&mut serializer, peek).map_err(map_format_error)
}
pub fn peek_to_vec(peek: Peek<'_, '_>) -> Result<Vec<u8>, SerializeError> {
let mut buffer = Vec::new();
let mut serializer = PostcardSerializer::new(CopyWriter::new(&mut buffer));
serialize_root(&mut serializer, peek).map_err(map_format_error)?;
Ok(buffer)
}
pub fn to_scatter_plan<'a, T>(value: &'a T) -> Result<ScatterPlan<'a>, SerializeError>
where
T: facet_core::Facet<'a> + ?Sized,
{
peek_to_scatter_plan(Peek::new(value))
}
pub fn peek_to_scatter_plan<'input, 'facet>(
peek: Peek<'input, 'facet>,
) -> Result<ScatterPlan<'input>, SerializeError> {
let mut serializer = PostcardSerializer::new(ScatterBuilder::new());
serialize_root(&mut serializer, peek).map_err(map_format_error)?;
Ok(serializer.into_writer().finish())
}
pub fn to_vec_with_shape<'facet, T>(
value: &T,
target_shape: &'static Shape,
) -> Result<Vec<u8>, SerializeError>
where
T: facet_core::Facet<'facet>,
{
let mut buffer = Vec::new();
let peek = Peek::new(value);
let mut serializer = PostcardSerializer::new(CopyWriter::new(&mut buffer));
serialize_value_with_shape(&mut serializer, peek, target_shape).map_err(map_format_error)?;
Ok(buffer)
}
fn map_format_error(error: FormatSerializeError<SerializeError>) -> SerializeError {
match error {
FormatSerializeError::Backend(err) => err,
FormatSerializeError::Reflect(err) => SerializeError::Custom(alloc::format!("{err}")),
FormatSerializeError::Unsupported(message) => SerializeError::Custom(message.into_owned()),
FormatSerializeError::Internal(message) => SerializeError::Custom(message.into_owned()),
}
}
fn has_trailing_attr(field: Option<&facet_core::Field>) -> bool {
field.is_some_and(|f| f.has_builtin_attr("trailing"))
}
struct PostcardSerializer<'a, W> {
writer: W,
_marker: PhantomData<&'a ()>,
}
impl<'a, W> PostcardSerializer<'a, W> {
const fn new(writer: W) -> Self {
Self {
writer,
_marker: PhantomData,
}
}
fn into_writer(self) -> W {
self.writer
}
fn write_str(&mut self, s: &str) -> Result<(), SerializeError>
where
W: Writer,
{
write_varint(s.len() as u64, &mut self.writer)?;
self.writer.write_bytes(s.as_bytes())
}
fn write_str_borrowed(&mut self, s: &str) -> Result<(), SerializeError>
where
W: PostcardWriter<'a>,
{
write_varint(s.len() as u64, &mut self.writer)?;
self.writer.write_referenced_bytes(s.as_bytes())
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError>
where
W: Writer,
{
write_varint(bytes.len() as u64, &mut self.writer)?;
self.writer.write_bytes(bytes)
}
fn write_bytes_borrowed(&mut self, bytes: &[u8]) -> Result<(), SerializeError>
where
W: PostcardWriter<'a>,
{
write_varint(bytes.len() as u64, &mut self.writer)?;
self.writer.write_referenced_bytes(bytes)
}
fn write_byte_array_borrowed(&mut self, bytes: &[u8]) -> Result<(), SerializeError>
where
W: PostcardWriter<'a>,
{
self.writer.write_referenced_bytes(bytes)
}
fn write_dynamic_tag(&mut self, tag: DynamicValueTag) -> Result<(), SerializeError>
where
W: Writer,
{
let byte = match tag {
DynamicValueTag::Null => 0,
DynamicValueTag::Bool => 1,
DynamicValueTag::I64 => 2,
DynamicValueTag::U64 => 3,
DynamicValueTag::F64 => 4,
DynamicValueTag::String => 5,
DynamicValueTag::Bytes => 6,
DynamicValueTag::Array => 7,
DynamicValueTag::Object => 8,
DynamicValueTag::DateTime => 9,
};
self.writer.write_byte(byte)
}
}
impl<'a, W: PostcardWriter<'a>> FormatSerializer for PostcardSerializer<'a, W> {
type Error = SerializeError;
fn begin_struct(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn field_key(&mut self, _key: &str) -> Result<(), Self::Error> {
Err(SerializeError::Custom(
"postcard does not support named fields".into(),
))
}
fn end_struct(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn begin_seq(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn end_seq(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn scalar(&mut self, scalar: facet_format::ScalarValue<'_>) -> Result<(), Self::Error> {
match scalar {
facet_format::ScalarValue::Null | facet_format::ScalarValue::Unit => Ok(()),
facet_format::ScalarValue::Bool(v) => self.writer.write_byte(if v { 1 } else { 0 }),
facet_format::ScalarValue::Char(c) => {
let mut buf = [0u8; 4];
let s = c.encode_utf8(&mut buf);
self.write_str(s)
}
facet_format::ScalarValue::I64(n) => write_varint_signed(n, &mut self.writer),
facet_format::ScalarValue::U64(n) => write_varint(n, &mut self.writer),
facet_format::ScalarValue::I128(n) => write_varint_signed_i128(n, &mut self.writer),
facet_format::ScalarValue::U128(n) => write_varint_u128(n, &mut self.writer),
facet_format::ScalarValue::F64(n) => self.writer.write_bytes(&n.to_le_bytes()),
facet_format::ScalarValue::Str(s) => match s {
Cow::Borrowed(s) => self.write_str_borrowed(s),
Cow::Owned(s) => self.write_str(&s),
},
facet_format::ScalarValue::Bytes(bytes) => match bytes {
Cow::Borrowed(bytes) => self.write_bytes_borrowed(bytes),
Cow::Owned(bytes) => self.write_bytes(&bytes),
},
}
}
fn struct_field_mode(&self) -> StructFieldMode {
StructFieldMode::Unnamed
}
fn map_encoding(&self) -> MapEncoding {
MapEncoding::Pairs
}
fn enum_variant_encoding(&self) -> EnumVariantEncoding {
EnumVariantEncoding::Index
}
fn is_self_describing(&self) -> bool {
false
}
fn dynamic_value_encoding(&self) -> DynamicValueEncoding {
DynamicValueEncoding::Tagged
}
fn dynamic_value_tag(&mut self, tag: DynamicValueTag) -> Result<(), Self::Error> {
self.write_dynamic_tag(tag)
}
fn begin_seq_with_len(&mut self, len: usize) -> Result<(), Self::Error> {
write_varint(len as u64, &mut self.writer)
}
fn begin_map_with_len(&mut self, len: usize) -> Result<(), Self::Error> {
write_varint(len as u64, &mut self.writer)
}
fn end_map(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn typed_scalar(
&mut self,
scalar_type: ScalarType,
value: Peek<'_, '_>,
) -> Result<(), Self::Error> {
match scalar_type {
ScalarType::Unit => Ok(()),
ScalarType::Bool => {
let v = *value.get::<bool>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get bool: {}", e))
})?;
self.writer.write_byte(if v { 1 } else { 0 })
}
ScalarType::Char => {
let c = *value.get::<char>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get char: {}", e))
})?;
let mut buf = [0u8; 4];
let s = c.encode_utf8(&mut buf);
self.write_str(s)
}
ScalarType::Str | ScalarType::String | ScalarType::CowStr => {
let s = value
.as_str()
.ok_or_else(|| SerializeError::Custom("Failed to get string value".into()))?;
self.write_str_borrowed(s)
}
ScalarType::F32 => {
let v = *value.get::<f32>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get f32: {}", e))
})?;
self.writer.write_bytes(&v.to_le_bytes())
}
ScalarType::F64 => {
let v = *value.get::<f64>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get f64: {}", e))
})?;
self.writer.write_bytes(&v.to_le_bytes())
}
ScalarType::U8 => {
let v = *value.get::<u8>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get u8: {}", e))
})?;
self.writer.write_byte(v)
}
ScalarType::U16 => {
let v = *value.get::<u16>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get u16: {}", e))
})?;
write_varint(v as u64, &mut self.writer)
}
ScalarType::U32 => {
let v = *value.get::<u32>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get u32: {}", e))
})?;
write_varint(v as u64, &mut self.writer)
}
ScalarType::U64 => {
let v = *value.get::<u64>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get u64: {}", e))
})?;
write_varint(v, &mut self.writer)
}
ScalarType::U128 => {
let v = *value.get::<u128>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get u128: {}", e))
})?;
write_varint_u128(v, &mut self.writer)
}
ScalarType::USize => {
let v = *value.get::<usize>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get usize: {}", e))
})?;
write_varint(v as u64, &mut self.writer)
}
ScalarType::I8 => {
let v = *value.get::<i8>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get i8: {}", e))
})?;
self.writer.write_byte(v as u8)
}
ScalarType::I16 => {
let v = *value.get::<i16>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get i16: {}", e))
})?;
write_varint_signed(v as i64, &mut self.writer)
}
ScalarType::I32 => {
let v = *value.get::<i32>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get i32: {}", e))
})?;
write_varint_signed(v as i64, &mut self.writer)
}
ScalarType::I64 => {
let v = *value.get::<i64>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get i64: {}", e))
})?;
write_varint_signed(v, &mut self.writer)
}
ScalarType::I128 => {
let v = *value.get::<i128>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get i128: {}", e))
})?;
write_varint_signed_i128(v, &mut self.writer)
}
ScalarType::ISize => {
let v = *value.get::<isize>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get isize: {}", e))
})?;
write_varint_signed(v as i64, &mut self.writer)
}
#[cfg(feature = "net")]
ScalarType::SocketAddr => {
let v = *value.get::<core::net::SocketAddr>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get SocketAddr: {}", e))
})?;
self.write_str(&v.to_string())
}
#[cfg(feature = "net")]
ScalarType::IpAddr => {
let v = *value.get::<core::net::IpAddr>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get IpAddr: {}", e))
})?;
self.write_str(&v.to_string())
}
#[cfg(feature = "net")]
ScalarType::Ipv4Addr => {
let v = *value.get::<core::net::Ipv4Addr>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get Ipv4Addr: {}", e))
})?;
self.write_str(&v.to_string())
}
#[cfg(feature = "net")]
ScalarType::Ipv6Addr => {
let v = *value.get::<core::net::Ipv6Addr>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get Ipv6Addr: {}", e))
})?;
self.write_str(&v.to_string())
}
_ => Err(SerializeError::Custom(alloc::format!(
"Unsupported scalar type: {:?}",
scalar_type
))),
}
}
fn begin_option_some(&mut self) -> Result<(), Self::Error> {
self.writer.write_byte(1)
}
fn serialize_none(&mut self) -> Result<(), Self::Error> {
self.writer.write_byte(0)
}
fn begin_enum_variant(
&mut self,
variant_index: usize,
_variant_name: &'static str,
) -> Result<(), Self::Error> {
write_varint(variant_index as u64, &mut self.writer)
}
fn serialize_byte_sequence(&mut self, bytes: &[u8]) -> Result<bool, Self::Error> {
self.write_bytes_borrowed(bytes)?;
Ok(true)
}
fn serialize_byte_array(&mut self, bytes: &[u8]) -> Result<bool, Self::Error> {
self.write_byte_array_borrowed(bytes)?;
Ok(true)
}
fn serialize_opaque_scalar(
&mut self,
shape: &'static facet_core::Shape,
value: Peek<'_, '_>,
) -> Result<bool, Self::Error> {
self.serialize_opaque_scalar_with_field(None, shape, value)
}
fn serialize_opaque_scalar_with_field(
&mut self,
field: Option<&facet_core::Field>,
shape: &'static facet_core::Shape,
value: Peek<'_, '_>,
) -> Result<bool, Self::Error> {
if value.scalar_type().is_some() {
return Ok(false);
}
if let Some(adapter) = shape.opaque_adapter {
let mapped = unsafe { (adapter.serialize)(value.data()) };
if let Some(bytes) =
unsafe { raw_postcard::try_decode_passthrough_bytes(mapped.ptr, mapped.shape) }
{
if has_trailing_attr(field) {
self.writer.write_referenced_bytes(bytes)?;
} else {
self.write_bytes_borrowed(bytes)?;
}
} else {
let mapped_peek = unsafe { Peek::unchecked_new(mapped.ptr, mapped.shape) };
if has_trailing_attr(field) {
serialize_root(self, mapped_peek).map_err(map_format_error)?;
} else {
let mut bytes = Vec::new();
let mut mapped_serializer =
PostcardSerializer::new(CopyWriter::new(&mut bytes));
serialize_root(&mut mapped_serializer, mapped_peek)
.map_err(map_format_error)?;
self.write_bytes(&bytes)?;
}
}
return Ok(true);
}
#[cfg(feature = "camino")]
if shape.is_type::<camino::Utf8PathBuf>() {
use camino::Utf8PathBuf;
let path = value.get::<Utf8PathBuf>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get Utf8PathBuf: {}", e))
})?;
self.write_str(path.as_str())?;
return Ok(true);
}
#[cfg(feature = "camino")]
if shape.id == facet_core::Shape::id_of::<camino::Utf8Path>() {
use camino::Utf8Path;
let path = value.get::<Utf8Path>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get Utf8Path: {}", e))
})?;
self.write_str(path.as_str())?;
return Ok(true);
}
#[cfg(feature = "uuid")]
if shape.is_type::<uuid::Uuid>() {
use uuid::Uuid;
let uuid = value
.get::<Uuid>()
.map_err(|e| SerializeError::Custom(alloc::format!("Failed to get Uuid: {}", e)))?;
self.writer.write_bytes(uuid.as_bytes())?;
return Ok(true);
}
#[cfg(feature = "ulid")]
if shape.is_type::<ulid::Ulid>() {
use ulid::Ulid;
let ulid = value
.get::<Ulid>()
.map_err(|e| SerializeError::Custom(alloc::format!("Failed to get Ulid: {}", e)))?;
self.writer.write_bytes(&ulid.to_bytes())?;
return Ok(true);
}
#[cfg(feature = "jiff02")]
if shape.is_type::<jiff::Zoned>() {
use jiff::Zoned;
let zoned = value.get::<Zoned>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get Zoned: {}", e))
})?;
self.write_str(&zoned.to_string())?;
return Ok(true);
}
#[cfg(feature = "jiff02")]
if shape.is_type::<jiff::Timestamp>() {
use jiff::Timestamp;
let ts = value.get::<Timestamp>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get Timestamp: {}", e))
})?;
self.write_str(&ts.to_string())?;
return Ok(true);
}
#[cfg(feature = "jiff02")]
if shape.is_type::<jiff::civil::DateTime>() {
use jiff::civil::DateTime;
let dt = value.get::<DateTime>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get DateTime: {}", e))
})?;
self.write_str(&dt.to_string())?;
return Ok(true);
}
#[cfg(feature = "chrono")]
if shape.is_type::<chrono::DateTime<chrono::Utc>>() {
use chrono::{DateTime, SecondsFormat, Utc};
let dt = value.get::<DateTime<Utc>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get DateTime<Utc>: {}", e))
})?;
self.write_str(&dt.to_rfc3339_opts(SecondsFormat::AutoSi, true))?;
return Ok(true);
}
#[cfg(feature = "chrono")]
if shape.is_type::<chrono::DateTime<chrono::Local>>() {
use chrono::{DateTime, Local, SecondsFormat};
let dt = value.get::<DateTime<Local>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get DateTime<Local>: {}", e))
})?;
self.write_str(&dt.to_rfc3339_opts(SecondsFormat::AutoSi, false))?;
return Ok(true);
}
#[cfg(feature = "chrono")]
if shape.is_type::<chrono::DateTime<chrono::FixedOffset>>() {
use chrono::{DateTime, FixedOffset, SecondsFormat};
let dt = value.get::<DateTime<FixedOffset>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get DateTime<FixedOffset>: {}", e))
})?;
self.write_str(&dt.to_rfc3339_opts(SecondsFormat::AutoSi, false))?;
return Ok(true);
}
#[cfg(feature = "chrono")]
if shape.is_type::<chrono::NaiveDateTime>() {
use chrono::NaiveDateTime;
let dt = value.get::<NaiveDateTime>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get NaiveDateTime: {}", e))
})?;
self.write_str(&dt.format("%Y-%m-%dT%H:%M:%S").to_string())?;
return Ok(true);
}
#[cfg(feature = "chrono")]
if shape.is_type::<chrono::NaiveDate>() {
use chrono::NaiveDate;
let date = value.get::<NaiveDate>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get NaiveDate: {}", e))
})?;
self.write_str(&date.to_string())?;
return Ok(true);
}
#[cfg(feature = "chrono")]
if shape.is_type::<chrono::NaiveTime>() {
use chrono::NaiveTime;
let time = value.get::<NaiveTime>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get NaiveTime: {}", e))
})?;
self.write_str(&time.to_string())?;
return Ok(true);
}
#[cfg(feature = "time")]
if shape.is_type::<time::UtcDateTime>() {
use time::UtcDateTime;
let dt = value.get::<UtcDateTime>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get UtcDateTime: {}", e))
})?;
let s = dt
.format(&time::format_description::well_known::Rfc3339)
.unwrap_or_else(|_| "<invalid>".to_string());
self.write_str(&s)?;
return Ok(true);
}
#[cfg(feature = "time")]
if shape.is_type::<time::OffsetDateTime>() {
use time::OffsetDateTime;
let dt = value.get::<OffsetDateTime>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get OffsetDateTime: {}", e))
})?;
let s = dt
.format(&time::format_description::well_known::Rfc3339)
.unwrap_or_else(|_| "<invalid>".to_string());
self.write_str(&s)?;
return Ok(true);
}
#[cfg(feature = "ordered-float")]
if shape.is_type::<ordered_float::OrderedFloat<f32>>() {
use ordered_float::OrderedFloat;
let val = value.get::<OrderedFloat<f32>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get OrderedFloat<f32>: {}", e))
})?;
self.writer.write_bytes(&val.0.to_le_bytes())?;
return Ok(true);
} else if shape.is_type::<ordered_float::OrderedFloat<f64>>() {
use ordered_float::OrderedFloat;
let val = value.get::<OrderedFloat<f64>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get OrderedFloat<f64>: {}", e))
})?;
self.writer.write_bytes(&val.0.to_le_bytes())?;
return Ok(true);
}
#[cfg(feature = "ordered-float")]
if shape.is_type::<ordered_float::NotNan<f32>>() {
use ordered_float::NotNan;
let val = value.get::<NotNan<f32>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get NotNan<f32>: {}", e))
})?;
self.writer.write_bytes(&val.into_inner().to_le_bytes())?;
return Ok(true);
} else if shape.is_type::<ordered_float::NotNan<f64>>() {
use ordered_float::NotNan;
let val = value.get::<NotNan<f64>>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get NotNan<f64>: {}", e))
})?;
self.writer.write_bytes(&val.into_inner().to_le_bytes())?;
return Ok(true);
}
#[cfg(feature = "bytestring")]
if shape == <bytestring::ByteString as facet_core::Facet>::SHAPE {
let bs = value.get::<bytestring::ByteString>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get ByteString: {}", e))
})?;
self.write_str(bs.as_ref())?;
return Ok(true);
}
#[cfg(feature = "compact_str")]
if shape == <compact_str::CompactString as facet_core::Facet>::SHAPE {
let cs = value.get::<compact_str::CompactString>().map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get CompactString: {}", e))
})?;
self.write_str(cs.as_str())?;
return Ok(true);
}
#[cfg(feature = "smartstring")]
if shape == <smartstring::SmartString<smartstring::LazyCompact> as facet_core::Facet>::SHAPE
{
let ss = value
.get::<smartstring::SmartString<smartstring::LazyCompact>>()
.map_err(|e| {
SerializeError::Custom(alloc::format!("Failed to get SmartString: {}", e))
})?;
self.write_str(ss.as_str())?;
return Ok(true);
}
if shape.inner.is_some() {
return Ok(false);
}
if matches!(shape.def, Def::Scalar) {
if let Some(s) = value.as_str() {
self.write_str(s)?;
return Ok(true);
}
if shape.vtable.has_display() {
let s = alloc::format!("{}", value);
self.write_str(&s)?;
return Ok(true);
}
}
Ok(false)
}
}
fn write_varint<W: Writer>(mut value: u64, writer: &mut W) -> Result<(), SerializeError> {
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
writer.write_byte(byte)?;
if value == 0 {
break;
}
}
Ok(())
}
fn write_varint_u128<W: Writer>(mut value: u128, writer: &mut W) -> Result<(), SerializeError> {
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
writer.write_byte(byte)?;
if value == 0 {
break;
}
}
Ok(())
}
fn write_varint_signed<W: Writer>(value: i64, writer: &mut W) -> Result<(), SerializeError> {
let encoded = ((value << 1) ^ (value >> 63)) as u64;
write_varint(encoded, writer)
}
fn write_varint_signed_i128<W: Writer>(value: i128, writer: &mut W) -> Result<(), SerializeError> {
let encoded = ((value << 1) ^ (value >> 127)) as u128;
write_varint_u128(encoded, writer)
}
#[cfg(test)]
mod tests {
use super::*;
use facet::Facet;
use facet_value::{VArray, VBytes, VNumber, VObject, VString, Value};
use postcard::to_allocvec as postcard_to_vec;
use serde::Serialize;
#[derive(Facet, Serialize, PartialEq, Debug)]
struct SimpleStruct {
a: u32,
b: alloc::string::String,
c: bool,
}
#[test]
fn test_simple_struct() {
facet_testhelpers::setup();
let value = SimpleStruct {
a: 123,
b: "hello".into(),
c: true,
};
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_u8() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct U8Struct {
value: u8,
}
let value = U8Struct { value: 42 };
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_i32() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct I32Struct {
value: i32,
}
let value = I32Struct { value: -100000 };
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_string() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct StringStruct {
value: alloc::string::String,
}
let value = StringStruct {
value: "hello world".into(),
};
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_vec() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct VecStruct {
values: Vec<u32>,
}
let value = VecStruct {
values: alloc::vec![1, 2, 3, 4, 5],
};
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_vec_u8() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct BytesStruct {
data: Vec<u8>,
}
let value = BytesStruct {
data: alloc::vec![0, 1, 2, 3, 4, 5, 255, 128, 64],
};
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let decoded: BytesStruct = crate::from_slice(&facet_bytes).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn test_vec_u8_large() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct LargeBytes {
data: Vec<u8>,
}
let value = LargeBytes {
data: (0..1000).map(|i| (i % 256) as u8).collect(),
};
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let decoded: LargeBytes = crate::from_slice(&facet_bytes).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn test_vec_u8_empty() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct EmptyBytes {
data: Vec<u8>,
}
let value = EmptyBytes {
data: alloc::vec![],
};
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let decoded: EmptyBytes = crate::from_slice(&facet_bytes).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn test_option_some() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct OptionStruct {
value: Option<u32>,
}
let value = OptionStruct { value: Some(42) };
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_option_none() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
struct OptionStruct {
value: Option<u32>,
}
let value = OptionStruct { value: None };
let facet_bytes = to_vec(&value).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_unit_enum() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
#[repr(C)]
enum Color {
Red,
Green,
Blue,
}
let facet_bytes = to_vec(&Color::Red).unwrap();
let postcard_bytes = postcard_to_vec(&Color::Red).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let facet_bytes = to_vec(&Color::Green).unwrap();
let postcard_bytes = postcard_to_vec(&Color::Green).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let facet_bytes = to_vec(&Color::Blue).unwrap();
let postcard_bytes = postcard_to_vec(&Color::Blue).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_tuple_enum() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
#[repr(C)]
enum Value {
Int(i32),
Text(alloc::string::String),
}
let facet_bytes = to_vec(&Value::Int(42)).unwrap();
let postcard_bytes = postcard_to_vec(&Value::Int(42)).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let facet_bytes = to_vec(&Value::Text("hello".into())).unwrap();
let postcard_bytes = postcard_to_vec(&Value::Text("hello".into())).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_struct_enum() {
facet_testhelpers::setup();
#[derive(Facet, Serialize, PartialEq, Debug)]
#[repr(C)]
enum Message {
Quit,
Move { x: i32, y: i32 },
}
let facet_bytes = to_vec(&Message::Quit).unwrap();
let postcard_bytes = postcard_to_vec(&Message::Quit).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
let facet_bytes = to_vec(&Message::Move { x: 10, y: 20 }).unwrap();
let postcard_bytes = postcard_to_vec(&Message::Move { x: 10, y: 20 }).unwrap();
assert_eq!(facet_bytes, postcard_bytes);
}
#[test]
fn test_to_writer_fallible() {
facet_testhelpers::setup();
struct CustomWriter {
buffer: Vec<u8>,
}
impl Writer for CustomWriter {
fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
self.buffer.push(byte);
Ok(())
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
self.buffer.extend_from_slice(bytes);
Ok(())
}
}
let value = SimpleStruct {
a: 123,
b: "hello".into(),
c: true,
};
let mut writer = CustomWriter { buffer: Vec::new() };
to_writer_fallible(&value, &mut writer).unwrap();
let postcard_bytes = postcard_to_vec(&value).unwrap();
assert_eq!(writer.buffer, postcard_bytes);
}
#[test]
fn test_value_roundtrip() {
facet_testhelpers::setup();
let mut array = VArray::new();
array.push(Value::from(VNumber::from_i64(1)));
array.push(Value::from(VString::new("two")));
array.push(Value::TRUE);
let mut object = VObject::new();
object.insert("n", Value::from(VNumber::from_u64(42)));
object.insert("s", Value::from(VString::new("hello")));
object.insert("b", Value::from(VBytes::new(&[1, 2, 3])));
object.insert("a", Value::from(array));
let value = Value::from(object);
let bytes = to_vec(&value).unwrap();
let decoded: Value = crate::from_slice(&bytes).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn test_to_vec_with_shape_struct() {
facet_testhelpers::setup();
#[derive(Debug, Facet, PartialEq, Serialize)]
struct Point {
x: i32,
y: i32,
}
let value: Value = facet_json::from_str(r#"{"x": 10, "y": 20}"#).unwrap();
let bytes = to_vec_with_shape(&value, Point::SHAPE).unwrap();
let expected = to_vec(&Point { x: 10, y: 20 }).unwrap();
assert_eq!(bytes, expected);
let point: Point = crate::from_slice(&bytes).unwrap();
assert_eq!(point, Point { x: 10, y: 20 });
}
#[test]
fn test_to_vec_with_shape_vec() {
facet_testhelpers::setup();
let value: Value = facet_json::from_str(r#"[1, 2, 3, 4, 5]"#).unwrap();
let bytes = to_vec_with_shape(&value, <Vec<i32>>::SHAPE).unwrap();
let expected = to_vec(&alloc::vec![1i32, 2, 3, 4, 5]).unwrap();
assert_eq!(bytes, expected);
let result: Vec<i32> = crate::from_slice(&bytes).unwrap();
assert_eq!(result, alloc::vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_to_vec_with_shape_nested() {
facet_testhelpers::setup();
#[derive(Debug, Facet, PartialEq, Serialize)]
struct Nested {
items: Vec<Item>,
}
#[derive(Debug, Facet, PartialEq, Serialize)]
struct Item {
name: alloc::string::String,
count: u32,
}
let value: Value = facet_json::from_str(
r#"{"items": [{"name": "foo", "count": 10}, {"name": "bar", "count": 20}]}"#,
)
.unwrap();
let bytes = to_vec_with_shape(&value, Nested::SHAPE).unwrap();
let result: Nested = crate::from_slice(&bytes).unwrap();
assert_eq!(
result,
Nested {
items: alloc::vec![
Item {
name: "foo".into(),
count: 10
},
Item {
name: "bar".into(),
count: 20
}
]
}
);
}
#[test]
fn test_to_vec_with_shape_roundtrip() {
facet_testhelpers::setup();
#[derive(Debug, Facet, PartialEq, Serialize)]
struct Config {
name: alloc::string::String,
enabled: bool,
count: u32,
}
let original = Config {
name: "test".into(),
enabled: true,
count: 42,
};
let typed_bytes = to_vec(&original).unwrap();
let value: Value = crate::from_slice_with_shape(&typed_bytes, Config::SHAPE).unwrap();
let value_bytes = to_vec_with_shape(&value, Config::SHAPE).unwrap();
assert_eq!(typed_bytes, value_bytes);
let roundtrip: Config = crate::from_slice(&value_bytes).unwrap();
assert_eq!(roundtrip, original);
}
#[test]
fn test_value_in_tuple() {
facet_testhelpers::setup();
let tuple: (u64, alloc::string::String, Value) =
(42, "hello".into(), Value::from(VNumber::from_i64(123)));
let bytes = to_vec(&tuple).unwrap();
let decoded: (u64, alloc::string::String, Value) = crate::from_slice(&bytes).unwrap();
assert_eq!(decoded.0, 42);
assert_eq!(decoded.1, "hello");
assert_eq!(decoded.2, Value::from(VNumber::from_i64(123)));
}
#[test]
fn test_value_in_struct() {
facet_testhelpers::setup();
#[derive(Debug, Facet, PartialEq)]
struct WithValue {
id: u64,
name: alloc::string::String,
data: Value,
}
let original = WithValue {
id: 1,
name: "test".into(),
data: Value::from(VObject::from_iter([(
"key".to_string(),
Value::from(VString::new("value")),
)])),
};
let bytes = to_vec(&original).unwrap();
let decoded: WithValue = crate::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn test_value_nested_in_struct() {
facet_testhelpers::setup();
#[derive(Debug, Facet, PartialEq)]
struct Outer {
before: u32,
value: Value,
after: u32,
}
let mut obj = VObject::new();
obj.insert("nested", Value::from(VNumber::from_i64(99)));
obj.insert("str", Value::from(VString::new("test")));
let original = Outer {
before: 10,
value: Value::from(obj),
after: 20,
};
let bytes = to_vec(&original).unwrap();
let decoded: Outer = crate::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
let mut arr = VArray::new();
arr.push(Value::from(VNumber::from_i64(1)));
arr.push(Value::from(VString::new("two")));
arr.push(Value::TRUE);
let original = Outer {
before: 100,
value: Value::from(arr),
after: 200,
};
let bytes = to_vec(&original).unwrap();
let decoded: Outer = crate::from_slice(&bytes).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn test_skip_all_unless_truthy_roundtrip() {
facet_testhelpers::setup();
#[derive(Debug, Clone, PartialEq, Facet)]
#[facet(skip_all_unless_truthy)]
pub struct Value {
pub tag: Option<alloc::string::String>,
pub payload: Option<alloc::string::String>,
}
let v = Value {
tag: None,
payload: Some("hello".into()),
};
let bytes = to_vec(&v).expect("serialize");
let v2: Value = crate::from_slice(&bytes).expect("deserialize");
assert_eq!(v, v2);
let v = Value {
tag: None,
payload: None,
};
let bytes = to_vec(&v).expect("serialize");
let v2: Value = crate::from_slice(&bytes).expect("deserialize");
assert_eq!(v, v2);
let v = Value {
tag: Some("mytag".into()),
payload: Some("mypayload".into()),
};
let bytes = to_vec(&v).expect("serialize");
let v2: Value = crate::from_slice(&bytes).expect("deserialize");
assert_eq!(v, v2);
let v = Value {
tag: Some("mytag".into()),
payload: None,
};
let bytes = to_vec(&v).expect("serialize");
let v2: Value = crate::from_slice(&bytes).expect("deserialize");
assert_eq!(v, v2);
}
}