use alloc::boxed::Box;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::mem::ManuallyDrop;
use deser_core::State;
use deser_core::ext::{BigInt, Datetime, Decimal, ExtValue, RawInput, Timestamp, Uuid};
use deser_core::ser::SerializeRef;
use deser_core::ser::{self, EventSink, SerializeDriver};
use deser_core::{Atom, ContainerShape, Error, ErrorKind, Event, Serialize};
use crate::copy::extend;
use crate::float::f32_to_f16;
use crate::simple::Simple;
use crate::tag::Tags;
const MAJOR_UNSIGNED: u8 = 0;
const MAJOR_NEGATIVE: u8 = 1;
const MAJOR_BYTES: u8 = 2;
const MAJOR_TEXT: u8 = 3;
const MAJOR_ARRAY: u8 = 4;
const MAJOR_MAP: u8 = 5;
const MAJOR_TAG: u8 = 6;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SerializerConfig {
canonical: bool,
context: deser_core::Context,
}
#[derive(Clone, Copy)]
struct Frame {
remaining: u64,
info: usize,
}
const IS_MAP: usize = 1;
const UNKNOWN_LEN: usize = 2;
impl Frame {
const TOP: Frame = Frame {
remaining: u64::MAX,
info: UNKNOWN_LEN,
};
#[inline(always)]
fn is_map(self) -> bool {
self.info & IS_MAP != 0
}
#[inline(always)]
fn header(self) -> usize {
self.info >> 2
}
}
struct CanonicalMap {
body: usize,
offsets_start: usize,
}
pub(crate) struct Writer {
pub(crate) out: Vec<u8>,
canonical: bool,
frame: Frame,
stack: Vec<Frame>,
maps: Vec<CanonicalMap>,
offsets: Vec<usize>,
insertions: Vec<Insertion>,
open_unknown: usize,
limit: usize,
}
struct Insertion {
offset: usize,
len: u8,
bytes: [u8; 8],
}
impl EventSink for Writer {
#[inline(always)]
fn event(
&mut self,
event: Event<'_>,
_value: SerializeRef<'_>,
state: &mut State,
) -> Result<(), Error> {
Writer::event(self, event, state)
}
#[inline]
fn pause(&mut self) -> bool {
if self.out.len() < self.limit || self.open_unknown > 0 || !self.maps.is_empty() {
return false;
}
self.finish();
true
}
}
impl Writer {
pub(crate) fn new(canonical: bool, out: Vec<u8>) -> Writer {
Writer {
out,
canonical,
frame: Frame::TOP,
stack: Vec::new(),
maps: Vec::new(),
offsets: Vec::new(),
insertions: Vec::new(),
open_unknown: 0,
limit: usize::MAX,
}
}
pub(crate) fn finish(&mut self) {
if !self.insertions.is_empty() {
self.apply_insertions();
self.insertions.clear();
}
}
fn accept_raw(&self, driver: &mut SerializeDriver<'_>) {
if !self.canonical {
driver.state_mut().declare_raw_format(&crate::raw::ID);
}
}
pub(crate) fn drive(
&mut self,
driver: &mut SerializeDriver<'_>,
limit: usize,
) -> Result<bool, Error> {
self.accept_raw(driver);
if limit == usize::MAX {
return self.drive_whole(driver).map(|()| true);
}
self.limit = limit;
let done = driver.drive_until(self)?;
if done {
self.finish();
}
Ok(done)
}
pub(crate) fn drive_whole(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
self.accept_raw(driver);
driver.drive_sink(self)?;
self.finish();
Ok(())
}
#[inline(always)]
fn event(&mut self, event: Event, state: &State) -> Result<(), Error> {
match event {
Event::Atom(atom) => {
self.begin_item(state);
self.write_atom(atom)
}
Event::MapStart(shape) => self.start(true, shape, state),
Event::SeqStart(shape) => self.start(false, shape, state),
Event::MapEnd | Event::SeqEnd => self.end(),
}
}
#[inline(always)]
fn begin_item(&mut self, state: &State) {
self.frame.remaining = self.frame.remaining.wrapping_sub(1);
if self.canonical && self.frame.is_map() {
self.offsets.push(self.out.len());
}
if let Some(tags) = state.event::<Tags>() {
self.write_tags(tags);
}
}
#[cold]
fn write_tags(&mut self, tags: &Tags) {
for &tag in tags.0.iter() {
self.write_head(MAJOR_TAG, tag);
}
}
#[inline(always)]
fn start(&mut self, is_map: bool, shape: ContainerShape, state: &State) -> Result<(), Error> {
self.begin_item(state);
let header = self.out.len();
let major = if is_map { MAJOR_MAP } else { MAJOR_ARRAY };
let mut info = (header << 2) | if is_map { IS_MAP } else { 0 };
let remaining = match shape.len() {
Some(len) => {
self.write_head(major, len as u64);
if is_map { len as u64 * 2 } else { len as u64 }
}
None => {
self.out.push(major << 5);
info |= UNKNOWN_LEN;
self.open_unknown += 1;
u64::MAX
}
};
if self.canonical && is_map {
self.maps.push(CanonicalMap {
body: self.out.len(),
offsets_start: self.offsets.len(),
});
}
self.stack.push(core::mem::replace(
&mut self.frame,
Frame { remaining, info },
));
Ok(())
}
#[inline(always)]
fn end(&mut self) -> Result<(), Error> {
let Some(parent) = self.stack.pop() else {
return Err(Error::new(ErrorKind::InvalidState, "unexpected end"));
};
let frame = core::mem::replace(&mut self.frame, parent);
if frame.remaining == 0 && !self.canonical {
Ok(())
} else {
self.end_slow(frame)
}
}
#[inline(never)]
fn end_slow(&mut self, frame: Frame) -> Result<(), Error> {
let unknown = frame.info & UNKNOWN_LEN != 0;
if !unknown && frame.remaining != 0 {
return Err(Error::new(
ErrorKind::InvalidState,
"number of items does not match the length of the container",
));
}
let items = if unknown {
u64::MAX - frame.remaining
} else {
0
};
if frame.is_map() {
if !items.is_multiple_of(2) {
return Err(Error::new(ErrorKind::InvalidState, "map without value"));
}
if self.canonical {
let map = self.maps.pop().unwrap();
self.sort_entries(&map)?;
}
}
if unknown {
self.open_unknown -= 1;
let count = if frame.is_map() { items / 2 } else { items };
self.patch_length(frame.header(), count);
}
Ok(())
}
fn patch_length(&mut self, header: usize, count: u64) {
let major = self.out[header];
if count < 24 {
self.out[header] = major | count as u8;
return;
}
let mut buf = [0u8; 9];
let head = encode_head(&mut buf, major >> 5, count);
self.out[header] = head[0];
if self.canonical {
let extra = head.len() - 1;
let len = self.out.len();
self.out.resize(len + extra, 0);
self.out.copy_within(header + 1..len, header + 1 + extra);
self.out[header + 1..header + head.len()].copy_from_slice(&head[1..]);
} else {
self.insertions.push(Insertion {
offset: header + 1,
len: head.len() as u8 - 1,
bytes: {
let mut bytes = [0; 8];
bytes[..head.len() - 1].copy_from_slice(&head[1..]);
bytes
},
});
}
}
#[cold]
fn apply_insertions(&mut self) {
self.insertions
.sort_unstable_by_key(|insertion| insertion.offset);
let extra: usize = self.insertions.iter().map(|x| x.len as usize).sum();
let mut src_end = self.out.len();
self.out.resize(src_end + extra, 0);
let mut dst_end = self.out.len();
for insertion in self.insertions.iter().rev() {
let segment = src_end - insertion.offset;
self.out
.copy_within(insertion.offset..src_end, dst_end - segment);
dst_end -= segment + insertion.len as usize;
self.out[dst_end..dst_end + insertion.len as usize]
.copy_from_slice(&insertion.bytes[..insertion.len as usize]);
src_end = insertion.offset;
}
debug_assert_eq!(src_end, dst_end);
}
#[cold]
fn sort_entries(&mut self, map: &CanonicalMap) -> Result<(), Error> {
let offsets = self.offsets.split_off(map.offsets_start);
let body_start = map.body;
let body_end = self.out.len();
let mut entries: Vec<(usize, usize, usize)> = (0..offsets.len())
.step_by(2)
.map(|idx| {
let end = offsets.get(idx + 2).copied().unwrap_or(body_end);
(offsets[idx], offsets[idx + 1], end)
})
.collect();
let out = &self.out;
entries.sort_by(|a, b| out[a.0..a.1].cmp(&out[b.0..b.1]));
if entries
.windows(2)
.any(|pair| out[pair[0].0..pair[0].1] == out[pair[1].0..pair[1].1])
{
return Err(Error::new(ErrorKind::DuplicateKey, "duplicate map key"));
}
let mut body = Vec::with_capacity(body_end - body_start);
for (start, _, end) in entries {
body.extend_from_slice(&out[start..end]);
}
self.out[body_start..body_end].copy_from_slice(&body);
Ok(())
}
#[inline(always)]
fn write_head(&mut self, major: u8, value: u64) {
if value < 24 {
self.out.push(major << 5 | value as u8);
} else {
let mut buf = [0u8; 9];
let head = encode_head(&mut buf, major, value);
extend(&mut self.out, head);
}
}
#[inline(always)]
fn write_atom(&mut self, atom: Atom) -> Result<(), Error> {
let atom = ManuallyDrop::new(atom);
match *atom {
Atom::Null => self.out.push(0xf6),
Atom::Bool(false) => self.out.push(0xf4),
Atom::Bool(true) => self.out.push(0xf5),
Atom::Str(ref val) if val.is_borrowed() => self.write_str(val),
Atom::Bytes(ref val) if val.is_borrowed() => self.write_bytes(val),
Atom::Char(c) => self.write_str(c.encode_utf8(&mut [0u8; 4])),
Atom::U64(val) => self.write_head(MAJOR_UNSIGNED, val),
Atom::I64(val) => self.write_i64(val),
Atom::F64(val) => self.write_f64(val),
Atom::F32(val) => self.write_f32(val),
_ => return self.write_other_atom(ManuallyDrop::into_inner(atom)),
}
Ok(())
}
#[inline(never)]
fn write_other_atom(&mut self, atom: Atom) -> Result<(), Error> {
match atom {
Atom::Str(ref val) | Atom::Lexical(ref val) => self.write_str(val),
Atom::Bytes(ref val) => self.write_bytes(val),
Atom::Ext(ref ext) => return self.write_ext(ext),
Atom::Implicit(ref val) => return self.write_atom(val.value().to_atom()),
_ => return Err(Error::new(ErrorKind::UnsupportedType, "unknown atom")),
}
Ok(())
}
#[inline(always)]
fn write_bytes(&mut self, val: &[u8]) {
self.write_head(MAJOR_BYTES, val.len() as u64);
extend(&mut self.out, val);
}
#[inline(always)]
fn write_str(&mut self, val: &str) {
self.write_head(MAJOR_TEXT, val.len() as u64);
extend(&mut self.out, val.as_bytes());
}
#[inline(always)]
fn write_i64(&mut self, val: i64) {
if val >= 0 {
self.write_head(MAJOR_UNSIGNED, val as u64);
} else {
self.write_head(MAJOR_NEGATIVE, !val as u64);
}
}
#[inline]
fn write_f64(&mut self, val: f64) {
if f64::from(val as f32) == val {
self.write_f32(val as f32);
} else if val.is_nan() {
self.write_nan();
} else {
let mut buf = [0xfb; 9];
buf[1..].copy_from_slice(&val.to_be_bytes());
extend(&mut self.out, &buf);
}
}
#[inline]
fn write_f32(&mut self, val: f32) {
if let Some(half) = f32_to_f16(val) {
let [a, b] = half.to_be_bytes();
extend(&mut self.out, &[0xf9, a, b]);
} else if val.is_nan() {
self.write_nan();
} else {
let mut buf = [0xfa; 5];
buf[1..].copy_from_slice(&val.to_be_bytes());
extend(&mut self.out, &buf);
}
}
#[cold]
fn write_nan(&mut self) {
self.out.extend_from_slice(&[0xf9, 0x7e, 0x00]);
}
#[cold]
fn write_ext(&mut self, ext: &ExtValue) -> Result<(), Error> {
if let Some(raw) = ext.downcast_value_ref::<RawInput>()
&& raw.is_format(&crate::raw::ID)
{
self.out.extend_from_slice(raw.as_bytes());
} else if let Some(&val) = ext.downcast_ref::<u128>() {
self.write_u128(val);
} else if let Some(&val) = ext.downcast_ref::<i128>() {
self.write_i128(val);
} else if let Some(val) = ext.downcast_ref::<BigInt>() {
self.write_bigint(val);
} else if let Some(val) = ext.downcast_ref::<Datetime>() {
if val.offset.is_some() {
self.write_head(MAJOR_TAG, 0);
} else if val.date.is_some() && val.time.is_none() {
self.write_head(MAJOR_TAG, 1004);
}
self.write_str(&val.to_string());
} else if let Some(val) = ext.downcast_ref::<Timestamp>() {
if val.nanosecond == 0 {
self.write_head(MAJOR_TAG, 1);
self.write_i64(val.seconds);
} else if let Some(datetime) = val.to_datetime() {
self.write_head(MAJOR_TAG, 0);
self.write_str(&datetime.to_string());
} else {
self.write_head(MAJOR_TAG, 1);
self.write_f64(val.as_secs_f64());
}
} else if let Some(val) = ext.downcast_ref::<Uuid>() {
self.write_head(MAJOR_TAG, 37);
self.write_bytes(&val.0);
} else if let Some(val) = ext.downcast_ref::<Decimal>() {
let (mantissa, exponent) = val.to_parts();
self.write_head(MAJOR_TAG, 4);
self.write_head(MAJOR_ARRAY, 2);
self.write_i64(exponent);
self.write_bigint(&mantissa);
} else if let Some(&simple) = ext.downcast_ref::<Simple>() {
let value = simple.value();
if value < 24 {
self.out.push(0xe0 | value);
} else {
self.out.extend_from_slice(&[0xf8, value]);
}
} else {
match ext.fallback() {
Atom::Ext(_) => {
return Err(Error::new(
ErrorKind::UnsupportedType,
"unsupported extension value",
));
}
fallback => return self.write_atom(fallback),
}
}
Ok(())
}
fn write_u128(&mut self, val: u128) {
match u64::try_from(val) {
Ok(val) => self.write_head(MAJOR_UNSIGNED, val),
Err(_) => self.write_bignum(2, val),
}
}
fn write_i128(&mut self, val: i128) {
if let Ok(val) = i64::try_from(val) {
self.write_i64(val);
} else if val >= 0 {
self.write_u128(val as u128);
} else {
let magnitude = !val as u128;
match u64::try_from(magnitude) {
Ok(magnitude) => self.write_head(MAJOR_NEGATIVE, magnitude),
Err(_) => self.write_bignum(3, magnitude),
}
}
}
fn write_bigint(&mut self, val: &BigInt) {
if let Some(val) = val.to_i128() {
self.write_i128(val);
} else if let Some(val) = val.to_u128() {
self.write_u128(val);
} else if val.is_negative() {
let mut magnitude = val.significant_magnitude().to_vec();
for byte in magnitude.iter_mut().rev() {
let (value, overflow) = byte.overflowing_sub(1);
*byte = value;
if !overflow {
break;
}
}
let skip = magnitude.iter().take_while(|&&x| x == 0).count();
self.write_head(MAJOR_TAG, 3);
self.write_bytes(&magnitude[skip..]);
} else {
self.write_head(MAJOR_TAG, 2);
self.write_bytes(val.significant_magnitude());
}
}
fn write_bignum(&mut self, tag: u64, val: u128) {
let bytes = val.to_be_bytes();
let skip = (val.leading_zeros() / 8) as usize;
self.write_head(MAJOR_TAG, tag);
self.write_head(MAJOR_BYTES, (bytes.len() - skip) as u64);
self.out.extend_from_slice(&bytes[skip..]);
}
}
#[inline]
fn encode_head(buf: &mut [u8; 9], major: u8, value: u64) -> &[u8] {
let major = major << 5;
if value < 24 {
buf[0] = major | value as u8;
&buf[..1]
} else if value <= u64::from(u8::MAX) {
buf[0] = major | 24;
buf[1] = value as u8;
&buf[..2]
} else if value <= u64::from(u16::MAX) {
buf[0] = major | 25;
buf[1..3].copy_from_slice(&(value as u16).to_be_bytes());
&buf[..3]
} else if value <= u64::from(u32::MAX) {
buf[0] = major | 26;
buf[1..5].copy_from_slice(&(value as u32).to_be_bytes());
&buf[..5]
} else {
buf[0] = major | 27;
buf[1..9].copy_from_slice(&value.to_be_bytes());
&buf[..9]
}
}
impl SerializerConfig {
pub const fn new() -> SerializerConfig {
SerializerConfig {
canonical: false,
context: deser_core::Context::new(),
}
}
pub const fn builder() -> SerializerConfigBuilder {
SerializerConfigBuilder::new()
}
pub const fn into_builder(self) -> SerializerConfigBuilder {
SerializerConfigBuilder { value: self }
}
pub fn set_context(&mut self, context: deser_core::Context) {
self.context = context;
}
pub fn context(&self) -> &deser_core::Context {
&self.context
}
#[inline]
fn apply_context(&self, driver: &mut SerializeDriver<'_>) {
if !self.context.is_empty() {
driver.set_default_context(self.context.clone());
}
}
pub const fn set_canonical(&mut self, yes: bool) {
self.canonical = yes;
}
pub fn to_vec<T: Serialize + ?Sized>(&self, value: &T) -> Result<Vec<u8>, Error> {
self.to_vec_ref(SerializeRef::new(&value))
}
pub fn to_vec_with<F, T: Serialize + ?Sized>(
&self,
value: &T,
setup: F,
) -> Result<Vec<u8>, Error>
where
F: FnOnce(&mut SerializeDriver<'_>),
{
let mut driver = SerializeDriver::new(&value);
setup(&mut driver);
self.apply_context(&mut driver);
self.serialize_driver(&mut driver)
}
fn to_vec_ref(&self, value: SerializeRef<'_>) -> Result<Vec<u8>, Error> {
let mut driver = SerializeDriver::from_ref(value);
self.apply_context(&mut driver);
self.serialize_driver(&mut driver)
}
pub(crate) fn serialize_part(
&self,
item: &mut Option<Box<Writer>>,
driver: &mut SerializeDriver<'_>,
out: &mut Vec<u8>,
limit: usize,
) -> Result<bool, Error> {
let len = out.len();
if item.is_none() && limit == usize::MAX {
let mut writer = Writer::new(self.canonical, core::mem::take(out));
let rv = writer.drive(driver, usize::MAX);
*out = writer.out;
if rv.is_err() {
out.truncate(len);
}
return rv;
}
let adopt = out.is_empty();
let mut writer = item
.take()
.unwrap_or_else(|| Box::new(Writer::new(self.canonical, Vec::new())));
if adopt {
writer.out = core::mem::take(out);
}
let rv = writer.drive(driver, limit);
let output = core::mem::take(&mut writer.out);
if adopt {
*out = output;
} else if rv.is_ok() {
out.extend_from_slice(&output);
}
let done = match rv {
Ok(done) => done,
Err(err) => {
out.truncate(len);
return Err(err);
}
};
if !done {
*item = Some(writer);
}
Ok(done)
}
pub(crate) fn serialize_driver(
&self,
driver: &mut SerializeDriver<'_>,
) -> Result<Vec<u8>, Error> {
let mut writer = Writer::new(self.canonical, Vec::with_capacity(128));
writer.drive_whole(driver)?;
Ok(writer.out)
}
}
#[derive(Debug, Clone)]
#[must_use]
pub struct SerializerConfigBuilder {
value: SerializerConfig,
}
impl SerializerConfigBuilder {
pub const fn new() -> SerializerConfigBuilder {
SerializerConfigBuilder {
value: SerializerConfig::new(),
}
}
pub const fn canonical(mut self, yes: bool) -> SerializerConfigBuilder {
self.value.set_canonical(yes);
self
}
pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
self.value.set_context(context);
self
}
pub const fn build(self) -> SerializerConfig {
let value = unsafe { core::ptr::read(&self.value) };
core::mem::forget(self);
value
}
}
impl Default for SerializerConfigBuilder {
fn default() -> SerializerConfigBuilder {
SerializerConfigBuilder::new()
}
}
pub struct Serializer {
config: SerializerConfig,
out: Vec<u8>,
written: usize,
item: Option<Box<Writer>>,
in_progress: bool,
}
impl Default for Serializer {
fn default() -> Serializer {
Serializer::new()
}
}
impl Clone for Serializer {
fn clone(&self) -> Serializer {
Serializer {
config: self.config.clone(),
out: self.out.clone(),
written: self.written,
item: None,
in_progress: self.in_progress,
}
}
}
impl core::fmt::Debug for Serializer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Serializer")
.field("config", &self.config)
.field("output", &self.out)
.field("written", &self.written)
.field("in_progress", &self.in_progress)
.finish()
}
}
impl Serializer {
pub fn new() -> Serializer {
Serializer::with_config(SerializerConfig::new())
}
pub fn with_config(config: SerializerConfig) -> Serializer {
Serializer {
config,
out: Vec::new(),
written: 0,
item: None,
in_progress: false,
}
}
pub fn config(&self) -> &SerializerConfig {
&self.config
}
pub fn written(&self) -> usize {
self.written
}
pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
ser::Serializer::serialize(self, value)
}
pub fn serialize_with<F, T: Serialize + ?Sized>(
&mut self,
value: &T,
setup: F,
) -> Result<(), Error>
where
F: FnOnce(&mut SerializeDriver<'_>),
{
ser::Serializer::serialize_with(self, value, setup)
}
pub fn output(&self) -> &[u8] {
&self.out
}
pub fn finish(self) -> Vec<u8> {
self.out
}
}
impl ser::Serializer for Serializer {
fn drive(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
if self.in_progress {
return Err(Error::in_progress());
}
ser::StreamSerializer::drive_partial(self, driver, usize::MAX).map(|_| ())
}
}
impl ser::StreamSerializer for Serializer {
fn output(&self) -> &[u8] {
&self.out
}
fn clear_output(&mut self) {
self.out.clear();
}
fn supports_partial(&self) -> bool {
true
}
fn drive_partial(
&mut self,
driver: &mut SerializeDriver<'_>,
limit: usize,
) -> Result<bool, Error> {
if !self.config.context.is_empty() {
driver.set_default_context(self.config.context.clone());
}
if self.item.is_none() && self.in_progress {
return Err(Error::in_progress());
}
if !self
.config
.serialize_part(&mut self.item, driver, &mut self.out, limit)?
{
self.in_progress = true;
return Ok(false);
}
self.in_progress = false;
self.written += 1;
Ok(true)
}
fn in_progress(&self) -> bool {
self.in_progress
}
}
#[cfg(feature = "io")]
impl SerializerConfig {
pub fn writer<W: std::io::Write>(&self, writer: W) -> deser_core::io::Writer<W, Serializer> {
deser_core::io::Writer::new(writer, Serializer::with_config(self.clone()))
}
pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
&self,
writer: W,
value: &T,
) -> Result<(), Error> {
self.writer(writer).write(value)
}
}
#[cfg(feature = "io")]
pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
writer: W,
value: &T,
) -> Result<(), Error> {
SerializerConfig::new().to_writer(writer, value)
}
pub fn to_vec<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>, Error> {
SerializerConfig::new().to_vec(value)
}