From e681eb3d92d4673f3df4b267d94d3484adbf2e31 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 21 Dec 2023 12:23:26 +1000 Subject: [PATCH] Support buffering simple values without alloc (#183) --- .github/workflows/buffer.yml | 20 + buffer/src/error.rs | 8 +- buffer/src/value.rs | 3212 ++++++++++++++++------------------ serde/src/to_serialize.rs | 74 +- src/data.rs | 21 + 5 files changed, 1635 insertions(+), 1700 deletions(-) diff --git a/.github/workflows/buffer.yml b/.github/workflows/buffer.yml index 63e63289..c43573ed 100644 --- a/.github/workflows/buffer.yml +++ b/.github/workflows/buffer.yml @@ -62,3 +62,23 @@ jobs: - name: Powerset working-directory: ./buffer run: cargo hack check --each-feature --exclude-features std,alloc -Z avoid-dev-deps --target thumbv6m-none-eabi + + miri: + name: Test (Miri) + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + + - name: Install Miri + run: | + rustup toolchain install nightly --component miri + cargo +nightly miri setup + + - name: Default features + working-directory: ./buffer + run: cargo +nightly miri test --lib + + - name: No features + working-directory: ./buffer + run: cargo +nightly miri test --lib --no-default-features diff --git a/buffer/src/error.rs b/buffer/src/error.rs index 1d04a431..9ed88538 100644 --- a/buffer/src/error.rs +++ b/buffer/src/error.rs @@ -15,12 +15,10 @@ enum ErrorKind { InvalidValue { reason: &'static str, }, - #[cfg(feature = "alloc")] OutsideContainer { method: &'static str, }, - #[cfg(not(feature = "alloc"))] - #[allow(dead_code)] + #[allow(dead_code)] // debug builds never reach this variant NoAlloc { method: &'static str, }, @@ -35,11 +33,9 @@ impl fmt::Display for Error { ErrorKind::InvalidValue { reason } => { write!(f, "the value is invalid: {}", reason) } - #[cfg(feature = "alloc")] ErrorKind::OutsideContainer { method } => { write!(f, "expected a fragment while buffering {}", method) } - #[cfg(not(feature = "alloc"))] ErrorKind::NoAlloc { method } => write!(f, "cannot allocate for {}", method), } } @@ -50,7 +46,6 @@ impl Error { Error(ErrorKind::Unsupported { actual, expected }) } - #[cfg(feature = "alloc")] pub(crate) fn outside_container(method: &'static str) -> Self { Error(ErrorKind::OutsideContainer { method }) } @@ -62,7 +57,6 @@ impl Error { Error(ErrorKind::InvalidValue { reason }) } - #[cfg(not(feature = "alloc"))] #[track_caller] pub(crate) fn no_alloc(method: &'static str) -> Self { /* diff --git a/buffer/src/value.rs b/buffer/src/value.rs index 875c44b4..11352332 100644 --- a/buffer/src/value.rs +++ b/buffer/src/value.rs @@ -1,15 +1,103 @@ -use crate::{std::marker::PhantomData, Error}; - -#[cfg(feature = "alloc")] use crate::{ - std::{boxed::Box, mem, vec::Vec}, - BinaryBuf, TextBuf, + std::{ + marker::PhantomData, + mem, + ops::{Deref, DerefMut, Range}, + }, + BinaryBuf, Error, TextBuf, }; use sval_ref::ValueRef as _; -#[cfg(feature = "alloc")] -pub use alloc_support::*; +#[derive(Debug, Clone)] +struct BufMut { + #[cfg(feature = "alloc")] + inner: crate::std::vec::Vec, + #[cfg(not(feature = "alloc"))] + inner: array_vec::ArrayVec, +} + +impl Default for BufMut { + fn default() -> Self { + BufMut { + inner: Default::default(), + } + } +} + +impl Deref for BufMut { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for BufMut { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl BufMut { + fn push(&mut self, value: T) -> Result<(), Error> { + #[cfg(feature = "alloc")] + { + self.inner.push(value); + + Ok(()) + } + #[cfg(not(feature = "alloc"))] + { + self.inner.push(value) + } + } + + fn pop(&mut self) -> Option { + self.inner.pop() + } + + fn clear(&mut self) { + self.inner.clear() + } +} + +#[derive(Debug, Clone)] +struct Buf { + #[cfg(feature = "alloc")] + inner: crate::std::boxed::Box<[T]>, + #[cfg(not(feature = "alloc"))] + inner: array_vec::ArrayVec, +} + +impl Deref for Buf { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for Buf { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl From> for Buf { + fn from(value: BufMut) -> Self { + #[cfg(feature = "alloc")] + { + Buf { + inner: value.inner.into_boxed_slice(), + } + } + #[cfg(not(feature = "alloc"))] + { + Buf { inner: value.inner } + } + } +} /** Buffer arbitrary values into a tree-like structure. @@ -19,11 +107,8 @@ will fail. */ #[derive(Debug)] pub struct ValueBuf<'sval> { - #[cfg(feature = "alloc")] - parts: Vec>, - #[cfg(feature = "alloc")] - stack: Vec, - #[cfg(feature = "alloc")] + parts: BufMut, 1>, + stack: BufMut, is_in_text_or_binary: bool, err: Option, _marker: PhantomData<&'sval ()>, @@ -36,8 +121,7 @@ This type is more compact than `ValueBuf`. */ #[derive(Debug, Clone)] pub struct Value<'sval> { - #[cfg(feature = "alloc")] - parts: Box<[ValuePart<'sval>]>, + parts: Buf, 1>, _marker: PhantomData<&'sval ()>, } @@ -53,11 +137,8 @@ impl<'sval> ValueBuf<'sval> { */ pub fn new() -> Self { ValueBuf { - #[cfg(feature = "alloc")] - parts: Vec::new(), - #[cfg(feature = "alloc")] - stack: Vec::new(), - #[cfg(feature = "alloc")] + parts: Default::default(), + stack: Default::default(), is_in_text_or_binary: false, err: None, _marker: PhantomData, @@ -84,41 +165,25 @@ impl<'sval> ValueBuf<'sval> { Whether or not the contents of the value buffer are complete. */ pub fn is_complete(&self) -> bool { - #[cfg(feature = "alloc")] - { - self.stack.len() == 0 && self.parts.len() > 0 && !self.is_in_text_or_binary - } - #[cfg(not(feature = "alloc"))] - { - true - } + self.stack.len() == 0 && self.parts.len() > 0 && !self.is_in_text_or_binary } /** Clear this buffer so it can be re-used for future values. */ pub fn clear(&mut self) { - #[cfg(feature = "alloc")] - { - let ValueBuf { - parts, - stack, - is_in_text_or_binary, - err, - _marker, - } = self; - - parts.clear(); - stack.clear(); - *is_in_text_or_binary = false; - *err = None; - } - #[cfg(not(feature = "alloc"))] - { - let ValueBuf { err, _marker } = self; + let ValueBuf { + parts, + stack, + is_in_text_or_binary, + err, + _marker, + } = self; - *err = None; - } + parts.clear(); + stack.clear(); + *is_in_text_or_binary = false; + *err = None; } /** @@ -126,8 +191,7 @@ impl<'sval> ValueBuf<'sval> { */ pub fn to_value(&self) -> Value<'sval> { Value { - #[cfg(feature = "alloc")] - parts: self.parts.clone().into_boxed_slice(), + parts: self.parts.clone().into(), _marker: PhantomData, } } @@ -137,8 +201,7 @@ impl<'sval> ValueBuf<'sval> { */ pub fn into_value(self) -> Value<'sval> { Value { - #[cfg(feature = "alloc")] - parts: self.parts.into_boxed_slice(), + parts: self.parts.into(), _marker: PhantomData, } } @@ -161,13 +224,14 @@ impl<'sval> ValueBuf<'sval> { // Re-assign all parts within the value in-place without re-allocating for them // This will take care of converted any actually borrowed data into owned - for part in &mut parts { + for part in parts.iter_mut() { crate::assert_static(part.into_owned_in_place()); } // SAFETY: `parts` no longer contains any data borrowed for `'sval` - let mut parts = - unsafe { mem::transmute::>, Vec>>(parts) }; + let mut parts = unsafe { + mem::transmute::, 1>, BufMut, 1>>(parts) + }; crate::assert_static(&mut parts); crate::assert_static(&mut stack); @@ -184,11 +248,10 @@ impl<'sval> ValueBuf<'sval> { } #[cfg(not(feature = "alloc"))] { - Err(Error::no_alloc("buffered value")) + Err(Error::no_alloc("owned value")) } } - #[cfg(feature = "alloc")] fn try_catch( &mut self, f: impl FnOnce(&mut ValueBuf<'sval>) -> Result<(), Error>, @@ -257,13 +320,13 @@ impl<'sval> Value<'sval> { // Re-assign all parts within the value in-place without re-allocating for them // This will take care of converted any actually borrowed data into owned - for part in &mut *parts { + for part in parts.iter_mut() { crate::assert_static(part.into_owned_in_place()); } // SAFETY: `parts` no longer contains any data borrowed for `'sval` let mut parts = unsafe { - mem::transmute::]>, Box<[ValuePart<'static>]>>(parts) + mem::transmute::, 1>, Buf, 1>>(parts) }; crate::assert_static(&mut parts); @@ -274,7 +337,7 @@ impl<'sval> Value<'sval> { } #[cfg(not(feature = "alloc"))] { - Err(Error::no_alloc("buffered value")) + Err(Error::no_alloc("owned value")) } } } @@ -298,15 +361,7 @@ impl<'a> sval::Value for ValueBuf<'a> { impl<'sval> sval_ref::ValueRef<'sval> for ValueBuf<'sval> { fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { - #[cfg(feature = "alloc")] - { - stream_ref(&self.parts, stream) - } - #[cfg(not(feature = "alloc"))] - { - let _ = stream; - sval::error() - } + stream_ref(&self.parts, stream) } } @@ -318,19 +373,10 @@ impl<'a> sval::Value for Value<'a> { impl<'sval> sval_ref::ValueRef<'sval> for Value<'sval> { fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { - #[cfg(feature = "alloc")] - { - stream_ref(&self.parts, stream) - } - #[cfg(not(feature = "alloc"))] - { - let _ = stream; - sval::error() - } + stream_ref(&self.parts, stream) } } -#[cfg(feature = "alloc")] fn stream_ref<'a, 'sval, S: sval::Stream<'sval> + ?Sized>( parts: &'a [ValuePart<'sval>], stream: &mut S, @@ -345,439 +391,165 @@ fn stream_ref<'a, 'sval, S: sval::Stream<'sval> + ?Sized>( impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { fn null(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::Null); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::Null)) } fn bool(&mut self, value: bool) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::Bool(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::Bool(value))) } fn text_begin(&mut self, _: Option) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::Text(TextBuf::new())); - self.is_in_text_or_binary = true; + self.try_catch(|buf| { + buf.is_in_text_or_binary = true; + buf.push_kind(ValueKind::Text(TextBuf::new())) + })?; - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + Ok(()) } fn text_fragment(&mut self, fragment: &'sval str) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| match buf.current_mut().kind { - ValueKind::Text(ref mut text) => text.push_fragment(fragment), - _ => Err(Error::outside_container("text")), - }) - } - #[cfg(not(feature = "alloc"))] - { - let _ = fragment; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| match buf.current_mut().kind { + ValueKind::Text(ref mut text) => text.push_fragment(fragment), + _ => Err(Error::outside_container("text")), + }) } fn text_fragment_computed(&mut self, fragment: &str) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| match buf.current_mut().kind { - ValueKind::Text(ref mut text) => text.push_fragment_computed(fragment), - _ => Err(Error::outside_container("text")), - }) - } - #[cfg(not(feature = "alloc"))] - { - let _ = fragment; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| match buf.current_mut().kind { + ValueKind::Text(ref mut text) => text.push_fragment_computed(fragment), + _ => Err(Error::outside_container("text")), + }) } fn text_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.is_in_text_or_binary = false; + self.is_in_text_or_binary = false; - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + Ok(()) } fn binary_begin(&mut self, _: Option) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::Binary(BinaryBuf::new())); - self.is_in_text_or_binary = true; - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| { + buf.is_in_text_or_binary = true; + buf.push_kind(ValueKind::Binary(BinaryBuf::new())) + }) } fn binary_fragment(&mut self, fragment: &'sval [u8]) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| match buf.current_mut().kind { - ValueKind::Binary(ref mut binary) => binary.push_fragment(fragment), - _ => Err(Error::outside_container("binary")), - }) - } - #[cfg(not(feature = "alloc"))] - { - let _ = fragment; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| match buf.current_mut().kind { + ValueKind::Binary(ref mut binary) => binary.push_fragment(fragment), + _ => Err(Error::outside_container("binary")), + }) } fn binary_fragment_computed(&mut self, fragment: &[u8]) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| match buf.current_mut().kind { - ValueKind::Binary(ref mut binary) => binary.push_fragment_computed(fragment), - _ => Err(Error::outside_container("binary")), - }) - } - #[cfg(not(feature = "alloc"))] - { - let _ = fragment; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| match buf.current_mut().kind { + ValueKind::Binary(ref mut binary) => binary.push_fragment_computed(fragment), + _ => Err(Error::outside_container("binary")), + }) } fn binary_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.is_in_text_or_binary = false; - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.is_in_text_or_binary = false; + + Ok(()) } fn u8(&mut self, value: u8) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::U8(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::U8(value))) } fn u16(&mut self, value: u16) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::U16(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::U16(value))) } fn u32(&mut self, value: u32) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::U32(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::U32(value))) } fn u64(&mut self, value: u64) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::U64(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::U64(value))) } fn u128(&mut self, value: u128) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::U128(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::U128(value))) } fn i8(&mut self, value: i8) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::I8(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::I8(value))) } fn i16(&mut self, value: i16) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::I16(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::I16(value))) } fn i32(&mut self, value: i32) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::I32(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::I32(value))) } fn i64(&mut self, value: i64) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::I64(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::I64(value))) } fn i128(&mut self, value: i128) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::I128(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::I128(value))) } fn f32(&mut self, value: f32) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::F32(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::F32(value))) } fn f64(&mut self, value: f64) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::F64(value)); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = value; - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_kind(ValueKind::F64(value))) } fn map_begin(&mut self, num_entries_hint: Option) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::Map { + self.try_catch(|buf| { + buf.push_begin(ValueKind::Map { len: 0, num_entries_hint, - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = num_entries_hint; - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn map_key_begin(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::MapKey { len: 0 }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_begin(ValueKind::MapKey { len: 0 })) } fn map_key_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn map_value_begin(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::MapValue { len: 0 }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_begin(ValueKind::MapValue { len: 0 })) } fn map_value_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn map_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn seq_begin(&mut self, num_entries_hint: Option) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::Seq { + self.try_catch(|buf| { + buf.push_begin(ValueKind::Seq { len: 0, num_entries_hint, - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = num_entries_hint; - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn seq_value_begin(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::SeqValue { len: 0 }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_begin(ValueKind::SeqValue { len: 0 })) } fn seq_value_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn seq_end(&mut self) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn enum_begin( @@ -786,22 +558,20 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { label: Option<&sval::Label>, index: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::Enum { + self.try_catch(|buf| { + buf.push_begin(ValueKind::Enum { len: 0, tag: tag.cloned(), index: index.cloned(), - label: label.map(|label| label.to_owned()), - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = (tag, label, index); - self.fail(Error::no_alloc("buffered value")) - } + label: label + .map(|label| { + label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label")) + }) + .transpose()?, + }) + }) } fn enum_end( @@ -810,14 +580,7 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { _: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn tagged_begin( @@ -826,22 +589,20 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { label: Option<&sval::Label>, index: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::Tagged { + self.try_catch(|buf| { + buf.push_begin(ValueKind::Tagged { len: 0, tag: tag.cloned(), index: index.cloned(), - label: label.map(|label| label.to_owned()), - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = (tag, label, index); - self.fail(Error::no_alloc("buffered value")) - } + label: label + .map(|label| { + label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label")) + }) + .transpose()?, + }) + }) } fn tagged_end( @@ -850,14 +611,7 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { _: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn tag( @@ -866,21 +620,19 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { label: Option<&sval::Label>, index: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_kind(ValueKind::Tag { + self.try_catch(|buf| { + buf.push_kind(ValueKind::Tag { tag: tag.cloned(), index: index.cloned(), - label: label.map(|label| label.to_owned()), - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = (tag, label, index); - self.fail(Error::no_alloc("buffered value")) - } + label: label + .map(|label| { + label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label")) + }) + .transpose()?, + }) + }) } fn record_begin( @@ -890,53 +642,37 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { index: Option<&sval::Index>, num_entries: Option, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::Record { + self.try_catch(|buf| { + buf.push_begin(ValueKind::Record { len: 0, tag: tag.cloned(), index: index.cloned(), - label: label.map(|label| label.to_owned()), + label: label + .map(|label| { + label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label")) + }) + .transpose()?, num_entries, - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = (tag, label, index, num_entries); - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn record_value_begin(&mut self, tag: Option<&sval::Tag>, label: &sval::Label) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::RecordValue { + self.try_catch(|buf| { + buf.push_begin(ValueKind::RecordValue { len: 0, tag: tag.cloned(), - label: label.to_owned(), - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = tag; - let _ = label; - self.fail(Error::no_alloc("buffered value")) - } + label: label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label"))?, + }) + }) } fn record_value_end(&mut self, _: Option<&sval::Tag>, _: &sval::Label) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn record_end( @@ -945,14 +681,7 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { _: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn tuple_begin( @@ -962,53 +691,35 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { index: Option<&sval::Index>, num_entries: Option, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::Tuple { + self.try_catch(|buf| { + buf.push_begin(ValueKind::Tuple { len: 0, tag: tag.cloned(), index: index.cloned(), - label: label.map(|label| label.to_owned()), + label: label + .map(|label| { + label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label")) + }) + .transpose()?, num_entries, - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = (tag, label, index, num_entries); - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn tuple_value_begin(&mut self, tag: Option<&sval::Tag>, index: &sval::Index) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::TupleValue { + self.try_catch(|buf| { + buf.push_begin(ValueKind::TupleValue { len: 0, tag: tag.cloned(), index: index.clone(), - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = tag; - let _ = index; - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn tuple_value_end(&mut self, _: Option<&sval::Tag>, _: &sval::Index) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn tuple_end( @@ -1017,14 +728,7 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { _: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn record_tuple_begin( @@ -1034,23 +738,21 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { index: Option<&sval::Index>, num_entries: Option, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::RecordTuple { + self.try_catch(|buf| { + buf.push_begin(ValueKind::RecordTuple { len: 0, tag: tag.cloned(), index: index.cloned(), - label: label.map(|label| label.to_owned()), + label: label + .map(|label| { + label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label")) + }) + .transpose()?, num_entries, - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = (tag, label, index, num_entries); - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn record_tuple_value_begin( @@ -1059,24 +761,16 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { label: &sval::Label, index: &sval::Index, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.push_begin(ValueKind::RecordTupleValue { + self.try_catch(|buf| { + buf.push_begin(ValueKind::RecordTupleValue { len: 0, tag: tag.cloned(), - label: label.to_owned(), + label: label + .try_to_owned() + .map_err(|_| Error::no_alloc("owned label"))?, index: index.clone(), - }); - - Ok(()) - } - #[cfg(not(feature = "alloc"))] - { - let _ = tag; - let _ = label; - let _ = index; - self.fail(Error::no_alloc("buffered value")) - } + }) + }) } fn record_tuple_value_end( @@ -1085,14 +779,7 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { _: &sval::Label, _: &sval::Index, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } fn record_tuple_end( @@ -1101,270 +788,432 @@ impl<'sval> sval::Stream<'sval> for ValueBuf<'sval> { _: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { - #[cfg(feature = "alloc")] - { - self.try_catch(|buf| buf.push_end()) - } - #[cfg(not(feature = "alloc"))] - { - self.fail(Error::no_alloc("buffered value")) - } + self.try_catch(|buf| buf.push_end()) } } -#[cfg(feature = "alloc")] -mod alloc_support { - use super::*; +/** +Buffer a value. +*/ +pub fn stream_to_value<'sval>( + v: &'sval (impl sval::Value + ?Sized), +) -> Result, Error> { + ValueBuf::collect(v) +} - use crate::{ - std::{mem, ops::Range}, - BinaryBuf, TextBuf, - }; +/** +Buffer an owned value. +*/ +pub fn stream_to_value_owned(v: impl sval::Value) -> Result, Error> { + ValueBuf::collect_owned(v) +} - /** - Buffer a value. - */ - pub fn stream_to_value<'sval>( - v: &'sval (impl sval::Value + ?Sized), - ) -> Result, Error> { - ValueBuf::collect(v) +#[repr(transparent)] +struct ValueSlice<'sval>([ValuePart<'sval>]); + +#[derive(Debug, Clone, PartialEq)] +struct ValuePart<'sval> { + kind: ValueKind<'sval>, +} + +#[derive(Debug, Clone, PartialEq)] +enum ValueKind<'sval> { + Null, + Bool(bool), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + U128(u128), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + I128(i128), + F32(f32), + F64(f64), + Text(TextBuf<'sval>), + Binary(BinaryBuf<'sval>), + Map { + len: usize, + num_entries_hint: Option, + }, + MapKey { + len: usize, + }, + MapValue { + len: usize, + }, + Seq { + len: usize, + num_entries_hint: Option, + }, + SeqValue { + len: usize, + }, + Tag { + tag: Option, + label: Option>, + index: Option, + }, + Enum { + len: usize, + tag: Option, + label: Option>, + index: Option, + }, + Tagged { + len: usize, + tag: Option, + label: Option>, + index: Option, + }, + Record { + len: usize, + tag: Option, + label: Option>, + index: Option, + num_entries: Option, + }, + RecordValue { + len: usize, + tag: Option, + label: sval::Label<'static>, + }, + Tuple { + len: usize, + tag: Option, + label: Option>, + index: Option, + num_entries: Option, + }, + TupleValue { + len: usize, + tag: Option, + index: sval::Index, + }, + RecordTuple { + len: usize, + tag: Option, + label: Option>, + index: Option, + num_entries: Option, + }, + RecordTupleValue { + len: usize, + tag: Option, + label: sval::Label<'static>, + index: sval::Index, + }, +} + +impl<'sval> ValueBuf<'sval> { + fn push_kind(&mut self, kind: ValueKind<'sval>) -> Result<(), Error> { + self.parts.push(ValuePart { kind }) + } + + fn push_begin(&mut self, kind: ValueKind<'sval>) -> Result<(), Error> { + self.stack.push(self.parts.len())?; + self.parts.push(ValuePart { kind }) + } + + fn push_end(&mut self) -> Result<(), Error> { + let index = self + .stack + .pop() + .ok_or_else(|| Error::invalid_value("unbalanced calls to `begin` and `end`"))?; + + let len = self.parts.len() - index - 1; + + *match &mut self.parts.get_mut(index).unwrap().kind { + ValueKind::Map { len, .. } => len, + ValueKind::MapKey { len } => len, + ValueKind::MapValue { len } => len, + ValueKind::Seq { len, .. } => len, + ValueKind::SeqValue { len } => len, + ValueKind::Enum { len, .. } => len, + ValueKind::Tagged { len, .. } => len, + ValueKind::Record { len, .. } => len, + ValueKind::RecordValue { len, .. } => len, + ValueKind::Tuple { len, .. } => len, + ValueKind::TupleValue { len, .. } => len, + ValueKind::RecordTuple { len, .. } => len, + ValueKind::RecordTupleValue { len, .. } => len, + ValueKind::Null + | ValueKind::Bool(_) + | ValueKind::U8(_) + | ValueKind::U16(_) + | ValueKind::U32(_) + | ValueKind::U64(_) + | ValueKind::U128(_) + | ValueKind::I8(_) + | ValueKind::I16(_) + | ValueKind::I32(_) + | ValueKind::I64(_) + | ValueKind::I128(_) + | ValueKind::F32(_) + | ValueKind::F64(_) + | ValueKind::Text(_) + | ValueKind::Binary(_) + | ValueKind::Tag { .. } => return Err(Error::invalid_value("can't end at this index")), + } = len; + + Ok(()) + } + + fn current_mut(&mut self) -> &mut ValuePart<'sval> { + self.parts.last_mut().expect("missing current") } +} - /** - Buffer an owned value. - */ - pub fn stream_to_value_owned(v: impl sval::Value) -> Result, Error> { - ValueBuf::collect_owned(v) - } - - #[repr(transparent)] - pub(super) struct ValueSlice<'sval>([ValuePart<'sval>]); - - #[derive(Debug, Clone, PartialEq)] - pub(super) struct ValuePart<'sval> { - pub(super) kind: ValueKind<'sval>, - } - - #[derive(Debug, Clone, PartialEq)] - pub(super) enum ValueKind<'sval> { - Null, - Bool(bool), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - U128(u128), - I8(i8), - I16(i16), - I32(i32), - I64(i64), - I128(i128), - F32(f32), - F64(f64), - Text(TextBuf<'sval>), - Binary(BinaryBuf<'sval>), - Map { - len: usize, - num_entries_hint: Option, - }, - MapKey { - len: usize, - }, - MapValue { - len: usize, - }, - Seq { - len: usize, - num_entries_hint: Option, - }, - SeqValue { - len: usize, - }, - Tag { - tag: Option, - label: Option>, - index: Option, - }, - Enum { - len: usize, - tag: Option, - label: Option>, - index: Option, - }, - Tagged { - len: usize, - tag: Option, - label: Option>, - index: Option, - }, - Record { - len: usize, - tag: Option, - label: Option>, - index: Option, - num_entries: Option, - }, - RecordValue { - len: usize, - tag: Option, - label: sval::Label<'static>, - }, - Tuple { - len: usize, - tag: Option, - label: Option>, - index: Option, - num_entries: Option, - }, - TupleValue { - len: usize, - tag: Option, - index: sval::Index, - }, - RecordTuple { - len: usize, - tag: Option, - label: Option>, - index: Option, - num_entries: Option, - }, - RecordTupleValue { - len: usize, - tag: Option, - label: sval::Label<'static>, - index: sval::Index, - }, +impl<'sval> ValueSlice<'sval> { + fn new<'a>(parts: &'a [ValuePart<'sval>]) -> &'a ValueSlice<'sval> { + unsafe { mem::transmute::<&'a [ValuePart<'sval>], &'a ValueSlice<'sval>>(parts) } } - impl<'sval> ValueBuf<'sval> { - pub(super) fn push_kind(&mut self, kind: ValueKind<'sval>) { - self.parts.push(ValuePart { kind }); - } + fn get(&self, i: usize) -> Option<&ValuePart<'sval>> { + self.0.get(i) + } - pub(super) fn push_begin(&mut self, kind: ValueKind<'sval>) { - self.stack.push(self.parts.len()); - self.parts.push(ValuePart { kind }); + fn slice<'a>(&'a self, range: Range) -> &'a ValueSlice<'sval> { + match self.0.get(range.clone()) { + Some(_) => (), + None => { + panic!("{:?} is out of range for {:?}", range, &self.0); + } } - pub(super) fn push_end(&mut self) -> Result<(), Error> { - let index = self - .stack - .pop() - .ok_or_else(|| Error::invalid_value("unbalanced calls to `begin` and `end`"))?; - - let len = self.parts.len() - index - 1; - - *match &mut self.parts[index].kind { - ValueKind::Map { len, .. } => len, - ValueKind::MapKey { len } => len, - ValueKind::MapValue { len } => len, - ValueKind::Seq { len, .. } => len, - ValueKind::SeqValue { len } => len, - ValueKind::Enum { len, .. } => len, - ValueKind::Tagged { len, .. } => len, - ValueKind::Record { len, .. } => len, - ValueKind::RecordValue { len, .. } => len, - ValueKind::Tuple { len, .. } => len, - ValueKind::TupleValue { len, .. } => len, - ValueKind::RecordTuple { len, .. } => len, - ValueKind::RecordTupleValue { len, .. } => len, - ValueKind::Null - | ValueKind::Bool(_) - | ValueKind::U8(_) - | ValueKind::U16(_) - | ValueKind::U32(_) - | ValueKind::U64(_) - | ValueKind::U128(_) - | ValueKind::I8(_) - | ValueKind::I16(_) - | ValueKind::I32(_) - | ValueKind::I64(_) - | ValueKind::I128(_) - | ValueKind::F32(_) - | ValueKind::F64(_) - | ValueKind::Text(_) - | ValueKind::Binary(_) - | ValueKind::Tag { .. } => { - return Err(Error::invalid_value("can't end at this index")) - } - } = len; + // SAFETY: `&[ValuePart]` and `&ValueSlice` have the same ABI + unsafe { mem::transmute::<&'a [ValuePart<'sval>], &'a ValueSlice<'sval>>(&self.0[range]) } + } +} - Ok(()) +#[cfg(feature = "alloc")] +impl<'sval> ValuePart<'sval> { + fn into_owned_in_place(&mut self) -> &mut ValuePart<'static> { + let ValuePart { kind } = self; + + match kind { + ValueKind::Text(ref mut text) => crate::assert_static(text.into_owned_in_place()), + ValueKind::Binary(ref mut binary) => crate::assert_static(binary.into_owned_in_place()), + ValueKind::Null => (), + ValueKind::Bool(v) => crate::assert_static(v), + ValueKind::U8(v) => crate::assert_static(v), + ValueKind::U16(v) => crate::assert_static(v), + ValueKind::U32(v) => crate::assert_static(v), + ValueKind::U64(v) => crate::assert_static(v), + ValueKind::U128(v) => crate::assert_static(v), + ValueKind::I8(v) => crate::assert_static(v), + ValueKind::I16(v) => crate::assert_static(v), + ValueKind::I32(v) => crate::assert_static(v), + ValueKind::I64(v) => crate::assert_static(v), + ValueKind::I128(v) => crate::assert_static(v), + ValueKind::F32(v) => crate::assert_static(v), + ValueKind::F64(v) => crate::assert_static(v), + ValueKind::Map { + len, + num_entries_hint, + } => { + crate::assert_static(len); + crate::assert_static(num_entries_hint) + } + ValueKind::MapKey { len } => crate::assert_static(len), + ValueKind::MapValue { len } => crate::assert_static(len), + ValueKind::Seq { + len, + num_entries_hint, + } => { + crate::assert_static(len); + crate::assert_static(num_entries_hint) + } + ValueKind::SeqValue { len } => crate::assert_static(len), + ValueKind::Tag { tag, label, index } => { + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index) + } + ValueKind::Enum { + len, + tag, + label, + index, + } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index) + } + ValueKind::Tagged { + len, + tag, + label, + index, + } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index) + } + ValueKind::Record { + len, + tag, + label, + index, + num_entries, + } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index); + crate::assert_static(num_entries) + } + ValueKind::RecordValue { len, tag, label } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label) + } + ValueKind::Tuple { + len, + tag, + label, + index, + num_entries, + } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index); + crate::assert_static(num_entries) + } + ValueKind::TupleValue { len, tag, index } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(index) + } + ValueKind::RecordTuple { + len, + tag, + label, + index, + num_entries, + } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index); + crate::assert_static(num_entries) + } + ValueKind::RecordTupleValue { + len, + tag, + label, + index, + } => { + crate::assert_static(len); + crate::assert_static(tag); + crate::assert_static(label); + crate::assert_static(index) + } } - pub(super) fn current_mut(&mut self) -> &mut ValuePart<'sval> { - self.parts.last_mut().expect("missing current") - } + // SAFETY: `self` no longer contains any data borrowed for `'sval` + unsafe { mem::transmute::<&mut ValuePart<'sval>, &mut ValuePart<'static>>(self) } } +} - impl<'sval> ValueSlice<'sval> { - pub(super) fn new<'a>(parts: &'a [ValuePart<'sval>]) -> &'a ValueSlice<'sval> { - unsafe { mem::transmute::<&'a [ValuePart<'sval>], &'a ValueSlice<'sval>>(parts) } - } +impl<'a> sval::Value for ValueSlice<'a> { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { + self.stream_ref(stream) + } +} - fn get(&self, i: usize) -> Option<&ValuePart<'sval>> { - self.0.get(i) - } +impl<'sval> sval_ref::ValueRef<'sval> for ValueSlice<'sval> { + fn stream_ref<'a, S: sval::Stream<'sval> + ?Sized>(&'a self, stream: &mut S) -> sval::Result { + let mut i = 0; - pub(super) fn slice<'a>(&'a self, range: Range) -> &'a ValueSlice<'sval> { - match self.0.get(range.clone()) { - Some(_) => (), - None => { - panic!("{:?} is out of range for {:?}", range, &self.0); - } - } + fn stream_value<'a, 'sval, S: sval::Stream<'sval> + ?Sized>( + stream: &mut S, + i: &mut usize, + len: usize, + value: &ValueSlice<'sval>, + f: impl FnOnce(&mut S, &ValueSlice<'sval>) -> sval::Result, + ) -> sval::Result { + let value = value.slice({ + let start = *i + 1; + let end = start + len; - // SAFETY: `&[ValuePart]` and `&ValueSlice` have the same ABI - unsafe { - mem::transmute::<&'a [ValuePart<'sval>], &'a ValueSlice<'sval>>(&self.0[range]) - } - } - } + start..end + }); - impl<'sval> ValuePart<'sval> { - pub(super) fn into_owned_in_place(&mut self) -> &mut ValuePart<'static> { - let ValuePart { kind } = self; + f(stream, value)?; - match kind { - ValueKind::Text(ref mut text) => crate::assert_static(text.into_owned_in_place()), - ValueKind::Binary(ref mut binary) => { - crate::assert_static(binary.into_owned_in_place()) - } - ValueKind::Null => (), - ValueKind::Bool(v) => crate::assert_static(v), - ValueKind::U8(v) => crate::assert_static(v), - ValueKind::U16(v) => crate::assert_static(v), - ValueKind::U32(v) => crate::assert_static(v), - ValueKind::U64(v) => crate::assert_static(v), - ValueKind::U128(v) => crate::assert_static(v), - ValueKind::I8(v) => crate::assert_static(v), - ValueKind::I16(v) => crate::assert_static(v), - ValueKind::I32(v) => crate::assert_static(v), - ValueKind::I64(v) => crate::assert_static(v), - ValueKind::I128(v) => crate::assert_static(v), - ValueKind::F32(v) => crate::assert_static(v), - ValueKind::F64(v) => crate::assert_static(v), + *i += len; + + Ok(()) + } + + while let Some(part) = self.get(i) { + let part: &ValuePart<'sval> = part; + match &part.kind { + ValueKind::Null => stream.null()?, + ValueKind::Bool(v) => stream.bool(*v)?, + ValueKind::U8(v) => stream.u8(*v)?, + ValueKind::U16(v) => stream.u16(*v)?, + ValueKind::U32(v) => stream.u32(*v)?, + ValueKind::U64(v) => stream.u64(*v)?, + ValueKind::U128(v) => stream.u128(*v)?, + ValueKind::I8(v) => stream.i8(*v)?, + ValueKind::I16(v) => stream.i16(*v)?, + ValueKind::I32(v) => stream.i32(*v)?, + ValueKind::I64(v) => stream.i64(*v)?, + ValueKind::I128(v) => stream.i128(*v)?, + ValueKind::F32(v) => stream.f32(*v)?, + ValueKind::F64(v) => stream.f64(*v)?, + ValueKind::Text(v) => sval_ref::stream_ref(stream, v)?, + ValueKind::Binary(v) => sval_ref::stream_ref(stream, v)?, ValueKind::Map { len, num_entries_hint, } => { - crate::assert_static(len); - crate::assert_static(num_entries_hint) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.map_begin(*num_entries_hint)?; + sval_ref::stream_ref(stream, body)?; + stream.map_end() + })?; + } + ValueKind::MapKey { len } => { + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.map_key_begin()?; + sval_ref::stream_ref(stream, body)?; + stream.map_key_end() + })?; + } + ValueKind::MapValue { len } => { + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.map_value_begin()?; + sval_ref::stream_ref(stream, body)?; + stream.map_value_end() + })?; } - ValueKind::MapKey { len } => crate::assert_static(len), - ValueKind::MapValue { len } => crate::assert_static(len), ValueKind::Seq { len, num_entries_hint, } => { - crate::assert_static(len); - crate::assert_static(num_entries_hint) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.seq_begin(*num_entries_hint)?; + sval_ref::stream_ref(stream, body)?; + stream.seq_end() + })?; + } + ValueKind::SeqValue { len } => { + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.seq_value_begin()?; + sval_ref::stream_ref(stream, body)?; + stream.seq_value_end() + })?; } - ValueKind::SeqValue { len } => crate::assert_static(len), ValueKind::Tag { tag, label, index } => { - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index) + stream.tag(tag.as_ref(), label.as_ref(), index.as_ref())?; } ValueKind::Enum { len, @@ -1372,10 +1221,11 @@ mod alloc_support { label, index, } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.enum_begin(tag.as_ref(), label.as_ref(), index.as_ref())?; + sval_ref::stream_ref(stream, body)?; + stream.enum_end(tag.as_ref(), label.as_ref(), index.as_ref()) + })?; } ValueKind::Tagged { len, @@ -1383,10 +1233,11 @@ mod alloc_support { label, index, } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.tagged_begin(tag.as_ref(), label.as_ref(), index.as_ref())?; + sval_ref::stream_ref(stream, body)?; + stream.tagged_end(tag.as_ref(), label.as_ref(), index.as_ref()) + })?; } ValueKind::Record { len, @@ -1395,16 +1246,23 @@ mod alloc_support { index, num_entries, } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index); - crate::assert_static(num_entries) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.record_begin( + tag.as_ref(), + label.as_ref(), + index.as_ref(), + *num_entries, + )?; + sval_ref::stream_ref(stream, body)?; + stream.record_end(tag.as_ref(), label.as_ref(), index.as_ref()) + })?; } ValueKind::RecordValue { len, tag, label } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.record_value_begin(tag.as_ref(), label)?; + sval_ref::stream_ref(stream, body)?; + stream.record_value_end(tag.as_ref(), label) + })?; } ValueKind::Tuple { len, @@ -1413,16 +1271,23 @@ mod alloc_support { index, num_entries, } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index); - crate::assert_static(num_entries) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.tuple_begin( + tag.as_ref(), + label.as_ref(), + index.as_ref(), + *num_entries, + )?; + sval_ref::stream_ref(stream, body)?; + stream.tuple_end(tag.as_ref(), label.as_ref(), index.as_ref()) + })?; } ValueKind::TupleValue { len, tag, index } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(index) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.tuple_value_begin(tag.as_ref(), index)?; + sval_ref::stream_ref(stream, body)?; + stream.tuple_value_end(tag.as_ref(), index) + })?; } ValueKind::RecordTuple { len, @@ -1431,11 +1296,16 @@ mod alloc_support { index, num_entries, } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index); - crate::assert_static(num_entries) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.record_tuple_begin( + tag.as_ref(), + label.as_ref(), + index.as_ref(), + *num_entries, + )?; + sval_ref::stream_ref(stream, body)?; + stream.record_tuple_end(tag.as_ref(), label.as_ref(), index.as_ref()) + })?; } ValueKind::RecordTupleValue { len, @@ -1443,934 +1313,952 @@ mod alloc_support { label, index, } => { - crate::assert_static(len); - crate::assert_static(tag); - crate::assert_static(label); - crate::assert_static(index) + stream_value(stream, &mut i, *len, self, |stream, body| { + stream.record_tuple_value_begin(tag.as_ref(), label, index)?; + sval_ref::stream_ref(stream, body)?; + stream.record_tuple_value_end(tag.as_ref(), label, index) + })?; } } - // SAFETY: `self` no longer contains any data borrowed for `'sval` - unsafe { mem::transmute::<&mut ValuePart<'sval>, &mut ValuePart<'static>>(self) } + i += 1; } + + Ok(()) } +} - impl<'a> sval::Value for ValueSlice<'a> { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( - &'sval self, - stream: &mut S, - ) -> sval::Result { - self.stream_ref(stream) - } +#[cfg(not(feature = "alloc"))] +mod array_vec { + use crate::{ + std::{ + fmt, mem, + ops::{Deref, DerefMut}, + }, + Error, + }; + + pub(super) struct ArrayVec { + buf: [mem::MaybeUninit; N], + len: usize, } - impl<'sval> sval_ref::ValueRef<'sval> for ValueSlice<'sval> { - fn stream_ref<'a, S: sval::Stream<'sval> + ?Sized>( - &'a self, - stream: &mut S, - ) -> sval::Result { - let mut i = 0; - - fn stream_value<'a, 'sval, S: sval::Stream<'sval> + ?Sized>( - stream: &mut S, - i: &mut usize, - len: usize, - value: &ValueSlice<'sval>, - f: impl FnOnce(&mut S, &ValueSlice<'sval>) -> sval::Result, - ) -> sval::Result { - let value = value.slice({ - let start = *i + 1; - let end = start + len; + impl Clone for ArrayVec { + fn clone(&self) -> Self { + let mut buf = Self::default(); - start..end - }); + for value in self.iter().cloned() { + buf.push(value).unwrap(); + } - f(stream, value)?; + buf + } + } - *i += len; + impl Default for ArrayVec { + fn default() -> Self { + ArrayVec { + // SAFETY: An array of uninitialized values is valid + buf: unsafe { + mem::MaybeUninit::<[mem::MaybeUninit; N]>::uninit().assume_init() + }, + len: 0, + } + } + } - Ok(()) + impl Drop for ArrayVec { + fn drop(&mut self) { + // SAFETY: Values up to `self.len` are initialized + unsafe { + crate::std::ptr::drop_in_place::<[T]>(&mut **self as *mut [T]); } + } + } - while let Some(part) = self.get(i) { - let part: &ValuePart<'sval> = part; - match &part.kind { - ValueKind::Null => stream.null()?, - ValueKind::Bool(v) => stream.bool(*v)?, - ValueKind::U8(v) => stream.u8(*v)?, - ValueKind::U16(v) => stream.u16(*v)?, - ValueKind::U32(v) => stream.u32(*v)?, - ValueKind::U64(v) => stream.u64(*v)?, - ValueKind::U128(v) => stream.u128(*v)?, - ValueKind::I8(v) => stream.i8(*v)?, - ValueKind::I16(v) => stream.i16(*v)?, - ValueKind::I32(v) => stream.i32(*v)?, - ValueKind::I64(v) => stream.i64(*v)?, - ValueKind::I128(v) => stream.i128(*v)?, - ValueKind::F32(v) => stream.f32(*v)?, - ValueKind::F64(v) => stream.f64(*v)?, - ValueKind::Text(v) => sval_ref::stream_ref(stream, v)?, - ValueKind::Binary(v) => sval_ref::stream_ref(stream, v)?, - ValueKind::Map { - len, - num_entries_hint, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.map_begin(*num_entries_hint)?; - sval_ref::stream_ref(stream, body)?; - stream.map_end() - })?; - } - ValueKind::MapKey { len } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.map_key_begin()?; - sval_ref::stream_ref(stream, body)?; - stream.map_key_end() - })?; - } - ValueKind::MapValue { len } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.map_value_begin()?; - sval_ref::stream_ref(stream, body)?; - stream.map_value_end() - })?; - } - ValueKind::Seq { - len, - num_entries_hint, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.seq_begin(*num_entries_hint)?; - sval_ref::stream_ref(stream, body)?; - stream.seq_end() - })?; - } - ValueKind::SeqValue { len } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.seq_value_begin()?; - sval_ref::stream_ref(stream, body)?; - stream.seq_value_end() - })?; - } - ValueKind::Tag { tag, label, index } => { - stream.tag(tag.as_ref(), label.as_ref(), index.as_ref())?; - } - ValueKind::Enum { - len, - tag, - label, - index, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.enum_begin(tag.as_ref(), label.as_ref(), index.as_ref())?; - sval_ref::stream_ref(stream, body)?; - stream.enum_end(tag.as_ref(), label.as_ref(), index.as_ref()) - })?; - } - ValueKind::Tagged { - len, - tag, - label, - index, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.tagged_begin(tag.as_ref(), label.as_ref(), index.as_ref())?; - sval_ref::stream_ref(stream, body)?; - stream.tagged_end(tag.as_ref(), label.as_ref(), index.as_ref()) - })?; - } - ValueKind::Record { - len, - tag, - label, - index, - num_entries, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.record_begin( - tag.as_ref(), - label.as_ref(), - index.as_ref(), - *num_entries, - )?; - sval_ref::stream_ref(stream, body)?; - stream.record_end(tag.as_ref(), label.as_ref(), index.as_ref()) - })?; - } - ValueKind::RecordValue { len, tag, label } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.record_value_begin(tag.as_ref(), label)?; - sval_ref::stream_ref(stream, body)?; - stream.record_value_end(tag.as_ref(), label) - })?; - } - ValueKind::Tuple { - len, - tag, - label, - index, - num_entries, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.tuple_begin( - tag.as_ref(), - label.as_ref(), - index.as_ref(), - *num_entries, - )?; - sval_ref::stream_ref(stream, body)?; - stream.tuple_end(tag.as_ref(), label.as_ref(), index.as_ref()) - })?; - } - ValueKind::TupleValue { len, tag, index } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.tuple_value_begin(tag.as_ref(), index)?; - sval_ref::stream_ref(stream, body)?; - stream.tuple_value_end(tag.as_ref(), index) - })?; - } - ValueKind::RecordTuple { - len, - tag, - label, - index, - num_entries, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.record_tuple_begin( - tag.as_ref(), - label.as_ref(), - index.as_ref(), - *num_entries, - )?; - sval_ref::stream_ref(stream, body)?; - stream.record_tuple_end(tag.as_ref(), label.as_ref(), index.as_ref()) - })?; - } - ValueKind::RecordTupleValue { - len, - tag, - label, - index, - } => { - stream_value(stream, &mut i, *len, self, |stream, body| { - stream.record_tuple_value_begin(tag.as_ref(), label, index)?; - sval_ref::stream_ref(stream, body)?; - stream.record_tuple_value_end(tag.as_ref(), label, index) - })?; - } - } + impl fmt::Debug for ArrayVec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } + } + + impl Deref for ArrayVec { + type Target = [T]; - i += 1; + fn deref(&self) -> &Self::Target { + let buf = &self.buf[..self.len]; + + // SAFETY: Values up to `self.len` are initialized + unsafe { &*(buf as *const [mem::MaybeUninit] as *const [T]) } + } + } + + impl DerefMut for ArrayVec { + fn deref_mut(&mut self) -> &mut Self::Target { + let buf = &mut self.buf[..self.len]; + + // SAFETY: Values up to `self.len` are initialized + unsafe { &mut *(buf as *mut [mem::MaybeUninit] as *mut [T]) } + } + } + + impl ArrayVec { + pub(super) fn push(&mut self, value: T) -> Result<(), Error> { + if self.len == N { + return Err(Error::no_alloc("vec push")); } + mem::MaybeUninit::write(&mut self.buf[self.len], value); + self.len += 1; + Ok(()) } + + pub(super) fn pop(&mut self) -> Option { + match self.len.checked_sub(1) { + Some(i) => { + self.len = i; + + // SAFETY: The value at `i` is initialized and being moved out of + Some(unsafe { mem::MaybeUninit::assume_init_read(&self.buf[i]) }) + } + None => None, + } + } + + pub(super) fn clear(&mut self) { + *self = Default::default() + } } #[cfg(test)] mod tests { use super::*; - use sval::Stream as _; - use sval_derive_macros::*; + use alloc::rc::Rc; #[test] - fn is_send_sync() { - fn assert() {} + fn push_pop() { + let mut vec = ArrayVec::<_, 2>::default(); - assert::(); - assert::(); - } + assert!(vec.pop().is_none()); - #[test] - fn empty_is_complete() { - assert!(!ValueBuf::new().is_complete()); - } + assert!(vec.push(1).is_ok()); + assert!(vec.push(2).is_ok()); + assert!(vec.push(3).is_err()); - #[test] - fn primitive_is_complete() { - assert!(ValueBuf::collect(&42).unwrap().is_complete()); + assert_eq!(2, vec.pop().unwrap()); + assert_eq!(1, vec.pop().unwrap()); + assert!(vec.pop().is_none()); + + assert!(vec.push(1).is_ok()); + + assert_eq!(1, vec.pop().unwrap()); + assert!(vec.pop().is_none()); } #[test] - fn text_is_complete() { - let mut buf = ValueBuf::new(); + fn destructors() { + let mut vec = ArrayVec::<_, 5>::default(); - buf.text_begin(None).unwrap(); + let a = Rc::new(1); + let b = Rc::new(2); - assert!(!buf.is_complete()); + vec.push(a.clone()).unwrap(); + vec.push(b.clone()).unwrap(); - buf.text_end().unwrap(); + assert_eq!(2, Rc::strong_count(&a)); + assert_eq!(2, Rc::strong_count(&b)); - assert!(buf.is_complete()); - } + drop(vec); - #[test] - fn binary_is_complete() { - let mut buf = ValueBuf::new(); + assert_eq!(1, Rc::strong_count(&a)); + assert_eq!(1, Rc::strong_count(&b)); + } + } +} - buf.binary_begin(None).unwrap(); +#[cfg(test)] +mod tests { + use super::*; - assert!(!buf.is_complete()); + use sval::Stream as _; - buf.binary_end().unwrap(); + #[test] + fn is_send_sync() { + fn assert() {} - assert!(buf.is_complete()); - } + assert::(); + assert::(); + } - #[test] - fn map_is_complete() { - let mut buf = ValueBuf::new(); + #[test] + fn empty_is_complete() { + assert!(!ValueBuf::new().is_complete()); + } - buf.map_begin(None).unwrap(); + #[test] + fn primitive_is_complete() { + assert!(ValueBuf::collect(&42).unwrap().is_complete()); + } - assert!(!buf.is_complete()); + #[test] + fn text_is_complete() { + let mut buf = ValueBuf::new(); - buf.map_end().unwrap(); + buf.text_begin(None).unwrap(); - assert!(buf.is_complete()); - } + assert!(!buf.is_complete()); - #[test] - fn seq_is_complete() { - let mut buf = ValueBuf::new(); + buf.text_end().unwrap(); - buf.seq_begin(None).unwrap(); + assert!(buf.is_complete()); + } - assert!(!buf.is_complete()); + #[test] + fn binary_is_complete() { + let mut buf = ValueBuf::new(); - buf.seq_end().unwrap(); + buf.binary_begin(None).unwrap(); - assert!(buf.is_complete()); - } + assert!(!buf.is_complete()); - #[test] - fn empty() { - use sval_test::{assert_tokens, Token::*}; + buf.binary_end().unwrap(); - assert_tokens(&ValueBuf::new(), &[Null]); - } + assert!(buf.is_complete()); + } - #[test] - fn buffer_primitive() { - for (value, expected) in [ - ( - ValueBuf::collect(&true).unwrap(), - vec![ValuePart { - kind: ValueKind::Bool(true), - }], - ), - ( - ValueBuf::collect(&1i8).unwrap(), - vec![ValuePart { - kind: ValueKind::I8(1), - }], - ), - ( - ValueBuf::collect(&2i16).unwrap(), - vec![ValuePart { - kind: ValueKind::I16(2), - }], - ), - ( - ValueBuf::collect(&3i32).unwrap(), - vec![ValuePart { - kind: ValueKind::I32(3), - }], - ), - ( - ValueBuf::collect(&4i64).unwrap(), - vec![ValuePart { - kind: ValueKind::I64(4), - }], - ), - ( - ValueBuf::collect(&5i128).unwrap(), - vec![ValuePart { - kind: ValueKind::I128(5), - }], - ), - ( - ValueBuf::collect(&1u8).unwrap(), - vec![ValuePart { - kind: ValueKind::U8(1), - }], - ), - ( - ValueBuf::collect(&2u16).unwrap(), - vec![ValuePart { - kind: ValueKind::U16(2), - }], - ), - ( - ValueBuf::collect(&3u32).unwrap(), - vec![ValuePart { - kind: ValueKind::U32(3), - }], - ), - ( - ValueBuf::collect(&4u64).unwrap(), - vec![ValuePart { - kind: ValueKind::U64(4), - }], - ), - ( - ValueBuf::collect(&5u128).unwrap(), - vec![ValuePart { - kind: ValueKind::U128(5), - }], - ), - ( - ValueBuf::collect(&3.14f32).unwrap(), - vec![ValuePart { - kind: ValueKind::F32(3.14), - }], - ), - ( - ValueBuf::collect(&3.1415f64).unwrap(), - vec![ValuePart { - kind: ValueKind::F64(3.1415), - }], - ), - ( - ValueBuf::collect("abc").unwrap(), - vec![ValuePart { - kind: ValueKind::Text(TextBuf::from("abc")), - }], - ), - ( - ValueBuf::collect(sval::BinarySlice::new(b"abc")).unwrap(), - vec![ValuePart { - kind: ValueKind::Binary(BinaryBuf::from(b"abc")), - }], - ), - ] { - assert_eq!(expected, value.parts, "{:?}", value); - } - } + #[test] + fn map_is_complete() { + let mut buf = ValueBuf::new(); - #[test] - fn buffer_option() { - let expected = vec![ValuePart { - kind: ValueKind::Tag { - tag: Some(sval::tags::RUST_OPTION_NONE), - label: Some(sval::Label::new("None")), - index: Some(sval::Index::new(0)), - }, - }]; + buf.map_begin(None).unwrap(); - assert_eq!(expected, ValueBuf::collect(&None::).unwrap().parts); + assert!(!buf.is_complete()); - let expected = vec![ - ValuePart { - kind: ValueKind::Tagged { - len: 1, - tag: Some(sval::tags::RUST_OPTION_SOME), - label: Some(sval::Label::new("Some")), - index: Some(sval::Index::new(1)), - }, - }, - ValuePart { - kind: ValueKind::I32(42), - }, - ]; + buf.map_end().unwrap(); - assert_eq!(expected, ValueBuf::collect(&Some(42i32)).unwrap().parts); - } + assert!(buf.is_complete()); + } - #[test] - fn buffer_map() { - let mut value = ValueBuf::new(); + #[test] + fn seq_is_complete() { + let mut buf = ValueBuf::new(); - value.map_begin(Some(2)).unwrap(); + buf.seq_begin(None).unwrap(); - value.map_key_begin().unwrap(); - value.i32(0).unwrap(); - value.map_key_end().unwrap(); + assert!(!buf.is_complete()); - value.map_value_begin().unwrap(); - value.bool(false).unwrap(); - value.map_value_end().unwrap(); + buf.seq_end().unwrap(); - value.map_key_begin().unwrap(); - value.i32(1).unwrap(); - value.map_key_end().unwrap(); + assert!(buf.is_complete()); + } - value.map_value_begin().unwrap(); - value.bool(true).unwrap(); - value.map_value_end().unwrap(); + #[test] + fn empty() { + use sval_test::{assert_tokens, Token::*}; - value.map_end().unwrap(); + assert_tokens(&ValueBuf::new(), &[Null]); + } - let expected = vec![ - ValuePart { + #[test] + fn buffer_primitive() { + for (value, expected) in [ + ( + ValueBuf::collect(&true).unwrap(), + vec![ValuePart { + kind: ValueKind::Bool(true), + }], + ), + ( + ValueBuf::collect(&1i8).unwrap(), + vec![ValuePart { + kind: ValueKind::I8(1), + }], + ), + ( + ValueBuf::collect(&2i16).unwrap(), + vec![ValuePart { + kind: ValueKind::I16(2), + }], + ), + ( + ValueBuf::collect(&3i32).unwrap(), + vec![ValuePart { + kind: ValueKind::I32(3), + }], + ), + ( + ValueBuf::collect(&4i64).unwrap(), + vec![ValuePart { + kind: ValueKind::I64(4), + }], + ), + ( + ValueBuf::collect(&5i128).unwrap(), + vec![ValuePart { + kind: ValueKind::I128(5), + }], + ), + ( + ValueBuf::collect(&1u8).unwrap(), + vec![ValuePart { + kind: ValueKind::U8(1), + }], + ), + ( + ValueBuf::collect(&2u16).unwrap(), + vec![ValuePart { + kind: ValueKind::U16(2), + }], + ), + ( + ValueBuf::collect(&3u32).unwrap(), + vec![ValuePart { + kind: ValueKind::U32(3), + }], + ), + ( + ValueBuf::collect(&4u64).unwrap(), + vec![ValuePart { + kind: ValueKind::U64(4), + }], + ), + ( + ValueBuf::collect(&5u128).unwrap(), + vec![ValuePart { + kind: ValueKind::U128(5), + }], + ), + ( + ValueBuf::collect(&3.14f32).unwrap(), + vec![ValuePart { + kind: ValueKind::F32(3.14), + }], + ), + ( + ValueBuf::collect(&3.1415f64).unwrap(), + vec![ValuePart { + kind: ValueKind::F64(3.1415), + }], + ), + ( + ValueBuf::collect("abc").unwrap(), + vec![ValuePart { + kind: ValueKind::Text(TextBuf::from("abc")), + }], + ), + ( + ValueBuf::collect(sval::BinarySlice::new(b"abc")).unwrap(), + vec![ValuePart { + kind: ValueKind::Binary(BinaryBuf::from(b"abc")), + }], + ), + ( + ValueBuf::collect(sval::MapSlice::<&str, i32>::new(&[])).unwrap(), + vec![ValuePart { kind: ValueKind::Map { - len: 8, - num_entries_hint: Some(2), + len: 0, + num_entries_hint: Some(0), }, - }, - ValuePart { - kind: ValueKind::MapKey { len: 1 }, - }, - ValuePart { - kind: ValueKind::I32(0), - }, - ValuePart { - kind: ValueKind::MapValue { len: 1 }, - }, - ValuePart { - kind: ValueKind::Bool(false), - }, - ValuePart { - kind: ValueKind::MapKey { len: 1 }, - }, - ValuePart { - kind: ValueKind::I32(1), - }, - ValuePart { - kind: ValueKind::MapValue { len: 1 }, - }, - ValuePart { - kind: ValueKind::Bool(true), - }, - ]; - - assert_eq!(expected, value.parts); + }], + ), + ( + ValueBuf::collect(&[] as &[i32]).unwrap(), + vec![ValuePart { + kind: ValueKind::Seq { + len: 0, + num_entries_hint: Some(0), + }, + }], + ), + ] { + assert_eq!(expected, &*value.parts, "{:?}", value); } + } - #[test] - fn buffer_seq() { - let mut value = ValueBuf::new(); + #[test] + fn buffer_empty_enum() { + let mut buf = ValueBuf::new(); - value.seq_begin(Some(2)).unwrap(); + buf.enum_begin(None, Some(&sval::Label::new("Enum")), None) + .unwrap(); + buf.enum_end(None, Some(&sval::Label::new("Enum")), None) + .unwrap(); + + assert_eq!( + &[ValuePart { + kind: ValueKind::Enum { + len: 0, + tag: None, + label: Some(sval::Label::new("Enum")), + index: None + } + }], + &*buf.parts + ); + } - value.seq_value_begin().unwrap(); - value.bool(false).unwrap(); - value.seq_value_end().unwrap(); + #[test] + fn buffer_empty_record() { + let mut buf = ValueBuf::new(); - value.seq_value_begin().unwrap(); - value.bool(true).unwrap(); - value.seq_value_end().unwrap(); + buf.record_begin(None, Some(&sval::Label::new("Record")), None, Some(0)) + .unwrap(); + buf.record_end(None, Some(&sval::Label::new("Record")), None) + .unwrap(); + + assert_eq!( + &[ValuePart { + kind: ValueKind::Record { + len: 0, + tag: None, + label: Some(sval::Label::new("Record")), + index: None, + num_entries: Some(0) + } + }], + &*buf.parts + ); + } - value.seq_end().unwrap(); + #[test] + fn buffer_empty_tuple() { + let mut buf = ValueBuf::new(); - let expected = vec![ - ValuePart { - kind: ValueKind::Seq { - len: 4, - num_entries_hint: Some(2), - }, - }, - ValuePart { - kind: ValueKind::SeqValue { len: 1 }, - }, - ValuePart { - kind: ValueKind::Bool(false), - }, - ValuePart { - kind: ValueKind::SeqValue { len: 1 }, - }, - ValuePart { - kind: ValueKind::Bool(true), - }, - ]; + buf.tuple_begin(None, Some(&sval::Label::new("Tuple")), None, Some(0)) + .unwrap(); + buf.tuple_end(None, Some(&sval::Label::new("Tuple")), None) + .unwrap(); + + assert_eq!( + &[ValuePart { + kind: ValueKind::Tuple { + len: 0, + tag: None, + label: Some(sval::Label::new("Tuple")), + index: None, + num_entries: Some(0) + } + }], + &*buf.parts + ); + } - assert_eq!(expected, value.parts); - } + #[test] + fn buffer_reuse() { + let mut buf = ValueBuf::new(); - #[test] - fn buffer_record() { - let mut value = ValueBuf::new(); - - value - .record_begin( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - Some(2), - ) - .unwrap(); - - value - .record_value_begin(None, &sval::Label::new("a")) - .unwrap(); - value.bool(false).unwrap(); - value - .record_value_end(None, &sval::Label::new("a")) - .unwrap(); - - value - .record_value_begin(None, &sval::Label::new("b")) - .unwrap(); - value.bool(true).unwrap(); - value - .record_value_end(None, &sval::Label::new("b")) - .unwrap(); - - value - .record_end( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - ) - .unwrap(); - - let expected = vec![ - ValuePart { - kind: ValueKind::Record { - len: 4, - tag: Some(sval::Tag::new("test")), - label: Some(sval::Label::new("A")), - index: Some(sval::Index::new(1)), - num_entries: Some(2), - }, - }, - ValuePart { - kind: ValueKind::RecordValue { - len: 1, - tag: None, - label: sval::Label::new("a"), - }, - }, - ValuePart { - kind: ValueKind::Bool(false), - }, - ValuePart { - kind: ValueKind::RecordValue { - len: 1, - tag: None, - label: sval::Label::new("b"), - }, - }, - ValuePart { - kind: ValueKind::Bool(true), - }, - ]; + buf.i32(42).unwrap(); - assert_eq!(expected, value.parts); - } + assert_eq!( + &*Value::collect(&42i32).unwrap().parts, + &*buf.to_value().parts + ); - #[test] - fn buffer_tuple() { - let mut value = ValueBuf::new(); - - value - .tuple_begin( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - Some(2), - ) - .unwrap(); - - value.tuple_value_begin(None, &sval::Index::new(0)).unwrap(); - value.bool(false).unwrap(); - value.tuple_value_end(None, &sval::Index::new(0)).unwrap(); - - value.tuple_value_begin(None, &sval::Index::new(1)).unwrap(); - value.bool(true).unwrap(); - value.tuple_value_end(None, &sval::Index::new(1)).unwrap(); - - value - .tuple_end( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - ) - .unwrap(); - - let expected = vec![ - ValuePart { - kind: ValueKind::Tuple { - len: 4, - tag: Some(sval::Tag::new("test")), - label: Some(sval::Label::new("A")), - index: Some(sval::Index::new(1)), - num_entries: Some(2), - }, - }, - ValuePart { - kind: ValueKind::TupleValue { - len: 1, - tag: None, - index: sval::Index::new(0), - }, - }, - ValuePart { - kind: ValueKind::Bool(false), - }, - ValuePart { - kind: ValueKind::TupleValue { - len: 1, - tag: None, - index: sval::Index::new(1), - }, - }, - ValuePart { - kind: ValueKind::Bool(true), - }, - ]; + buf.clear(); - assert_eq!(expected, value.parts); - } + buf.bool(true).unwrap(); - #[test] - fn buffer_record_tuple() { - let mut value = ValueBuf::new(); - - value - .record_tuple_begin( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - Some(2), - ) - .unwrap(); - - value - .record_tuple_value_begin(None, &sval::Label::new("a"), &sval::Index::new(0)) - .unwrap(); - value.bool(false).unwrap(); - value - .record_tuple_value_end(None, &sval::Label::new("a"), &sval::Index::new(0)) - .unwrap(); - - value - .record_tuple_value_begin(None, &sval::Label::new("b"), &sval::Index::new(1)) - .unwrap(); - value.bool(true).unwrap(); - value - .record_tuple_value_end(None, &sval::Label::new("b"), &sval::Index::new(1)) - .unwrap(); - - value - .record_tuple_end( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - ) - .unwrap(); - - let expected = vec![ - ValuePart { - kind: ValueKind::RecordTuple { - len: 4, - tag: Some(sval::Tag::new("test")), - label: Some(sval::Label::new("A")), - index: Some(sval::Index::new(1)), - num_entries: Some(2), - }, - }, - ValuePart { - kind: ValueKind::RecordTupleValue { - len: 1, - tag: None, - label: sval::Label::new("a"), - index: sval::Index::new(0), - }, - }, - ValuePart { - kind: ValueKind::Bool(false), - }, - ValuePart { - kind: ValueKind::RecordTupleValue { - len: 1, - tag: None, - label: sval::Label::new("b"), - index: sval::Index::new(1), - }, - }, - ValuePart { - kind: ValueKind::Bool(true), - }, - ]; + assert_eq!( + &*Value::collect(&true).unwrap().parts, + &*buf.to_value().parts + ); + } - assert_eq!(expected, value.parts); + #[test] + fn buffer_invalid() { + struct Kaboom; + + impl sval::Value for Kaboom { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + _: &mut S, + ) -> sval::Result { + sval::error() + } } - #[test] - fn buffer_enum() { - let mut value = ValueBuf::new(); - - value - .enum_begin( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - ) - .unwrap(); - - value - .tag( - None, - Some(&sval::Label::new("B")), - Some(&sval::Index::new(0)), - ) - .unwrap(); - - value - .enum_end( - Some(&sval::Tag::new("test")), - Some(&sval::Label::new("A")), - Some(&sval::Index::new(1)), - ) - .unwrap(); - - let expected = vec![ - ValuePart { - kind: ValueKind::Enum { - len: 1, - tag: Some(sval::Tag::new("test")), - label: Some(sval::Label::new("A")), - index: Some(sval::Index::new(1)), - }, - }, - ValuePart { - kind: ValueKind::Tag { - tag: None, - label: Some(sval::Label::new("B")), - index: Some(sval::Index::new(0)), - }, - }, - ]; + // Ensure we don't panic + let _ = Value::collect(&Kaboom); + let _ = Value::collect_owned(&Kaboom); + } +} + +#[cfg(test)] +#[cfg(feature = "alloc")] +mod alloc_tests { + use super::*; - assert_eq!(expected, value.parts); + use sval::Stream as _; + use sval_derive_macros::*; + + #[test] + fn collect_owned() { + let short_lived = String::from("abc"); + + let buf = ValueBuf::collect_owned(&short_lived).unwrap(); + drop(short_lived); + + match buf.parts[0].kind { + ValueKind::Text(ref text) => { + assert!(text.as_borrowed_str().is_none()); + assert_eq!("abc", text.as_str()); + } + _ => unreachable!(), } + } - #[test] - fn buffer_roundtrip() { - for value_1 in [ - ValueBuf::collect(&42i32).unwrap(), - ValueBuf::collect(&vec![ - vec![], - vec![vec![1, 2, 3], vec![4]], - vec![vec![5, 6], vec![7, 8, 9]], - ]) - .unwrap(), - ValueBuf::collect(&{ - #[derive(Value)] - struct Record { - a: i32, - b: bool, - } - - Record { a: 42, b: true } - }) - .unwrap(), - ValueBuf::collect(&{ - #[derive(Value)] - struct Tuple(i32, bool); - - Tuple(42, true) - }) - .unwrap(), - ValueBuf::collect(&{ - #[derive(Value)] - enum Enum { - A, - } - - Enum::A - }) - .unwrap(), - ] { - let value_2 = ValueBuf::collect(&value_1).unwrap(); - - assert_eq!(value_1.parts, value_2.parts, "{:?}", value_1); + #[test] + fn into_owned() { + let short_lived = String::from("abc"); + + let buf = ValueBuf::collect(&short_lived).unwrap(); + let borrowed_ptr = buf.parts.as_ptr() as *const (); + + let owned = buf.into_owned().unwrap(); + let owned_ptr = owned.parts.as_ptr() as *const (); + drop(short_lived); + + assert!(core::ptr::eq(borrowed_ptr, owned_ptr)); + + match owned.parts[0].kind { + ValueKind::Text(ref text) => { + assert!(text.as_borrowed_str().is_none()); + assert_eq!("abc", text.as_str()); } + _ => unreachable!(), } + } - #[test] - fn buffer_reuse() { - let mut buf = ValueBuf::new(); + #[test] + fn buffer_option() { + let expected = vec![ValuePart { + kind: ValueKind::Tag { + tag: Some(sval::tags::RUST_OPTION_NONE), + label: Some(sval::Label::new("None")), + index: Some(sval::Index::new(0)), + }, + }]; + + assert_eq!(expected, &*ValueBuf::collect(&None::).unwrap().parts); + + let expected = vec![ + ValuePart { + kind: ValueKind::Tagged { + len: 1, + tag: Some(sval::tags::RUST_OPTION_SOME), + label: Some(sval::Label::new("Some")), + index: Some(sval::Index::new(1)), + }, + }, + ValuePart { + kind: ValueKind::I32(42), + }, + ]; - buf.i32(42).unwrap(); + assert_eq!(expected, &*ValueBuf::collect(&Some(42i32)).unwrap().parts); + } - assert_eq!(Value::collect(&42i32).unwrap().parts, buf.to_value().parts); + #[test] + fn buffer_map() { + let mut value = ValueBuf::new(); - buf.clear(); + value.map_begin(Some(2)).unwrap(); - buf.bool(true).unwrap(); + value.map_key_begin().unwrap(); + value.i32(0).unwrap(); + value.map_key_end().unwrap(); - assert_eq!(Value::collect(&true).unwrap().parts, buf.to_value().parts); - } + value.map_value_begin().unwrap(); + value.bool(false).unwrap(); + value.map_value_end().unwrap(); - #[test] - fn buffer_invalid() { - struct Kaboom; - - impl sval::Value for Kaboom { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( - &'sval self, - _: &mut S, - ) -> sval::Result { - sval::error() - } - } + value.map_key_begin().unwrap(); + value.i32(1).unwrap(); + value.map_key_end().unwrap(); - // Ensure we don't panic - let _ = Value::collect(&Kaboom); - let _ = Value::collect_owned(&Kaboom); - } + value.map_value_begin().unwrap(); + value.bool(true).unwrap(); + value.map_value_end().unwrap(); - #[test] - fn into_owned() { - let short_lived = String::from("abc"); + value.map_end().unwrap(); - let buf = ValueBuf::collect(&short_lived).unwrap(); - let borrowed_ptr = buf.parts.as_ptr() as *const (); + let expected = vec![ + ValuePart { + kind: ValueKind::Map { + len: 8, + num_entries_hint: Some(2), + }, + }, + ValuePart { + kind: ValueKind::MapKey { len: 1 }, + }, + ValuePart { + kind: ValueKind::I32(0), + }, + ValuePart { + kind: ValueKind::MapValue { len: 1 }, + }, + ValuePart { + kind: ValueKind::Bool(false), + }, + ValuePart { + kind: ValueKind::MapKey { len: 1 }, + }, + ValuePart { + kind: ValueKind::I32(1), + }, + ValuePart { + kind: ValueKind::MapValue { len: 1 }, + }, + ValuePart { + kind: ValueKind::Bool(true), + }, + ]; + + assert_eq!(expected, &*value.parts); + } - let owned = buf.into_owned().unwrap(); - let owned_ptr = owned.parts.as_ptr() as *const (); - drop(short_lived); + #[test] + fn buffer_seq() { + let mut value = ValueBuf::new(); - assert!(core::ptr::eq(borrowed_ptr, owned_ptr)); + value.seq_begin(Some(2)).unwrap(); - match owned.parts[0].kind { - ValueKind::Text(ref text) => { - assert!(text.as_borrowed_str().is_none()); - assert_eq!("abc", text.as_str()); - } - _ => unreachable!(), - } - } + value.seq_value_begin().unwrap(); + value.bool(false).unwrap(); + value.seq_value_end().unwrap(); - #[test] - fn collect_owned() { - let short_lived = String::from("abc"); + value.seq_value_begin().unwrap(); + value.bool(true).unwrap(); + value.seq_value_end().unwrap(); - let buf = ValueBuf::collect_owned(&short_lived).unwrap(); - drop(short_lived); + value.seq_end().unwrap(); - match buf.parts[0].kind { - ValueKind::Text(ref text) => { - assert!(text.as_borrowed_str().is_none()); - assert_eq!("abc", text.as_str()); - } - _ => unreachable!(), - } - } + let expected = vec![ + ValuePart { + kind: ValueKind::Seq { + len: 4, + num_entries_hint: Some(2), + }, + }, + ValuePart { + kind: ValueKind::SeqValue { len: 1 }, + }, + ValuePart { + kind: ValueKind::Bool(false), + }, + ValuePart { + kind: ValueKind::SeqValue { len: 1 }, + }, + ValuePart { + kind: ValueKind::Bool(true), + }, + ]; + + assert_eq!(expected, &*value.parts); } -} -#[cfg(test)] -#[cfg(not(feature = "alloc"))] -mod no_std_tests { - use super::*; + #[test] + fn buffer_record() { + let mut value = ValueBuf::new(); + + value + .record_begin( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + Some(2), + ) + .unwrap(); + + value + .record_value_begin(None, &sval::Label::new("a")) + .unwrap(); + value.bool(false).unwrap(); + value + .record_value_end(None, &sval::Label::new("a")) + .unwrap(); + + value + .record_value_begin(None, &sval::Label::new("b")) + .unwrap(); + value.bool(true).unwrap(); + value + .record_value_end(None, &sval::Label::new("b")) + .unwrap(); + + value + .record_end( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + ) + .unwrap(); + + let expected = vec![ + ValuePart { + kind: ValueKind::Record { + len: 4, + tag: Some(sval::Tag::new("test")), + label: Some(sval::Label::new("A")), + index: Some(sval::Index::new(1)), + num_entries: Some(2), + }, + }, + ValuePart { + kind: ValueKind::RecordValue { + len: 1, + tag: None, + label: sval::Label::new("a"), + }, + }, + ValuePart { + kind: ValueKind::Bool(false), + }, + ValuePart { + kind: ValueKind::RecordValue { + len: 1, + tag: None, + label: sval::Label::new("b"), + }, + }, + ValuePart { + kind: ValueKind::Bool(true), + }, + ]; - use sval::Stream as _; + assert_eq!(expected, &*value.parts); + } #[test] - fn buffer_reuse() { - let mut buf = ValueBuf::new(); + fn buffer_tuple() { + let mut value = ValueBuf::new(); + + value + .tuple_begin( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + Some(2), + ) + .unwrap(); + + value.tuple_value_begin(None, &sval::Index::new(0)).unwrap(); + value.bool(false).unwrap(); + value.tuple_value_end(None, &sval::Index::new(0)).unwrap(); + + value.tuple_value_begin(None, &sval::Index::new(1)).unwrap(); + value.bool(true).unwrap(); + value.tuple_value_end(None, &sval::Index::new(1)).unwrap(); + + value + .tuple_end( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + ) + .unwrap(); + + let expected = vec![ + ValuePart { + kind: ValueKind::Tuple { + len: 4, + tag: Some(sval::Tag::new("test")), + label: Some(sval::Label::new("A")), + index: Some(sval::Index::new(1)), + num_entries: Some(2), + }, + }, + ValuePart { + kind: ValueKind::TupleValue { + len: 1, + tag: None, + index: sval::Index::new(0), + }, + }, + ValuePart { + kind: ValueKind::Bool(false), + }, + ValuePart { + kind: ValueKind::TupleValue { + len: 1, + tag: None, + index: sval::Index::new(1), + }, + }, + ValuePart { + kind: ValueKind::Bool(true), + }, + ]; - buf.i32(42).unwrap_err(); + assert_eq!(expected, &*value.parts); + } - assert!(buf.err.is_some()); + #[test] + fn buffer_record_tuple() { + let mut value = ValueBuf::new(); + + value + .record_tuple_begin( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + Some(2), + ) + .unwrap(); + + value + .record_tuple_value_begin(None, &sval::Label::new("a"), &sval::Index::new(0)) + .unwrap(); + value.bool(false).unwrap(); + value + .record_tuple_value_end(None, &sval::Label::new("a"), &sval::Index::new(0)) + .unwrap(); + + value + .record_tuple_value_begin(None, &sval::Label::new("b"), &sval::Index::new(1)) + .unwrap(); + value.bool(true).unwrap(); + value + .record_tuple_value_end(None, &sval::Label::new("b"), &sval::Index::new(1)) + .unwrap(); + + value + .record_tuple_end( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + ) + .unwrap(); + + let expected = vec![ + ValuePart { + kind: ValueKind::RecordTuple { + len: 4, + tag: Some(sval::Tag::new("test")), + label: Some(sval::Label::new("A")), + index: Some(sval::Index::new(1)), + num_entries: Some(2), + }, + }, + ValuePart { + kind: ValueKind::RecordTupleValue { + len: 1, + tag: None, + label: sval::Label::new("a"), + index: sval::Index::new(0), + }, + }, + ValuePart { + kind: ValueKind::Bool(false), + }, + ValuePart { + kind: ValueKind::RecordTupleValue { + len: 1, + tag: None, + label: sval::Label::new("b"), + index: sval::Index::new(1), + }, + }, + ValuePart { + kind: ValueKind::Bool(true), + }, + ]; - buf.clear(); + assert_eq!(expected, &*value.parts); + } + + #[test] + fn buffer_enum() { + let mut value = ValueBuf::new(); + + value + .enum_begin( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + ) + .unwrap(); + + value + .tag( + None, + Some(&sval::Label::new("B")), + Some(&sval::Index::new(0)), + ) + .unwrap(); + + value + .enum_end( + Some(&sval::Tag::new("test")), + Some(&sval::Label::new("A")), + Some(&sval::Index::new(1)), + ) + .unwrap(); + + let expected = vec![ + ValuePart { + kind: ValueKind::Enum { + len: 1, + tag: Some(sval::Tag::new("test")), + label: Some(sval::Label::new("A")), + index: Some(sval::Index::new(1)), + }, + }, + ValuePart { + kind: ValueKind::Tag { + tag: None, + label: Some(sval::Label::new("B")), + index: Some(sval::Index::new(0)), + }, + }, + ]; + + assert_eq!(expected, &*value.parts); + } + + #[test] + fn buffer_roundtrip() { + for value_1 in [ + ValueBuf::collect(&42i32).unwrap(), + ValueBuf::collect(&vec![ + vec![], + vec![vec![1, 2, 3], vec![4]], + vec![vec![5, 6], vec![7, 8, 9]], + ]) + .unwrap(), + ValueBuf::collect(&{ + #[derive(Value)] + struct Record { + a: i32, + b: bool, + } + + Record { a: 42, b: true } + }) + .unwrap(), + ValueBuf::collect(&{ + #[derive(Value)] + struct Tuple(i32, bool); + + Tuple(42, true) + }) + .unwrap(), + ValueBuf::collect(&{ + #[derive(Value)] + enum Enum { + A, + } - assert!(buf.err.is_none()); + Enum::A + }) + .unwrap(), + ] { + let value_2 = ValueBuf::collect(&value_1).unwrap(); + + assert_eq!(&*value_1.parts, &*value_2.parts, "{:?}", value_1); + } } } diff --git a/serde/src/to_serialize.rs b/serde/src/to_serialize.rs index c12d9e12..269da50f 100644 --- a/serde/src/to_serialize.rs +++ b/serde/src/to_serialize.rs @@ -180,7 +180,9 @@ impl<'sval, S: serde::Serializer> Stream<'sval> for Serializer { _ => { let name = label .and_then(|label| label.as_static_str()) - .ok_or_else(|| sval_nested::Error::invalid_value("unit label must be static"))?; + .ok_or_else(|| { + sval_nested::Error::invalid_value("unit label must be static") + })?; Ok(self.serializer.serialize_unit_struct(name)) } @@ -201,7 +203,9 @@ impl<'sval, S: serde::Serializer> Stream<'sval> for Serializer { _ => { let name = label .and_then(|label| label.as_static_str()) - .ok_or_else(|| sval_nested::Error::invalid_value("newtype label must be static"))?; + .ok_or_else(|| { + sval_nested::Error::invalid_value("newtype label must be static") + })?; Ok(self .serializer @@ -234,9 +238,9 @@ impl<'sval, S: serde::Serializer> Stream<'sval> for Serializer { match label { Some(label) => { - let name = label - .as_static_str() - .ok_or_else(|| sval_nested::Error::invalid_value("tuple label must be static"))?; + let name = label.as_static_str().ok_or_else(|| { + sval_nested::Error::invalid_value("tuple label must be static") + })?; Ok(SerializeTuple { serializer: self @@ -266,9 +270,9 @@ impl<'sval, S: serde::Serializer> Stream<'sval> for Serializer { match label { Some(label) => { - let name = label - .as_static_str() - .ok_or_else(|| sval_nested::Error::invalid_value("struct label must be static"))?; + let name = label.as_static_str().ok_or_else(|| { + sval_nested::Error::invalid_value("struct label must be static") + })?; Ok(SerializeRecord { serializer: self @@ -491,11 +495,13 @@ impl<'sval, S: serde::Serializer> StreamEnum<'sval> for SerializeEnum { ) -> sval_nested::Result { let variant = label .and_then(|label| label.as_static_str()) - .ok_or_else(|| sval_nested::Error::invalid_value("unit variant label must be static"))?; + .ok_or_else(|| { + sval_nested::Error::invalid_value("unit variant label must be static") + })?; - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| sval_nested::Error::invalid_value("unit variant index must a 32bit value"))?; + let variant_index = index.and_then(|index| index.to_u32()).ok_or_else(|| { + sval_nested::Error::invalid_value("unit variant index must a 32bit value") + })?; Ok(self .serializer @@ -511,11 +517,13 @@ impl<'sval, S: serde::Serializer> StreamEnum<'sval> for SerializeEnum { ) -> sval_nested::Result { let variant = label .and_then(|label| label.as_static_str()) - .ok_or_else(|| sval_nested::Error::invalid_value("newtype variant label must be static"))?; + .ok_or_else(|| { + sval_nested::Error::invalid_value("newtype variant label must be static") + })?; - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| sval_nested::Error::invalid_value("newtype variant index must be a 32bit value"))?; + let variant_index = index.and_then(|index| index.to_u32()).ok_or_else(|| { + sval_nested::Error::invalid_value("newtype variant index must be a 32bit value") + })?; Ok(self.serializer.serialize_newtype_variant( self.name, @@ -534,14 +542,16 @@ impl<'sval, S: serde::Serializer> StreamEnum<'sval> for SerializeEnum { ) -> sval_nested::Result { let variant = label .and_then(|label| label.as_static_str()) - .ok_or_else(|| sval_nested::Error::invalid_value("tuple variant label must be static"))?; + .ok_or_else(|| { + sval_nested::Error::invalid_value("tuple variant label must be static") + })?; - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| sval_nested::Error::invalid_value("tuple variant index must be a 32bit value"))?; + let variant_index = index.and_then(|index| index.to_u32()).ok_or_else(|| { + sval_nested::Error::invalid_value("tuple variant index must be a 32bit value") + })?; - let len = - num_entries.ok_or_else(|| sval_nested::Error::invalid_value("missing tuple variant len"))?; + let len = num_entries + .ok_or_else(|| sval_nested::Error::invalid_value("missing tuple variant len"))?; Ok(SerializeTupleVariant { serializer: self.serializer.serialize_tuple_variant( @@ -562,14 +572,16 @@ impl<'sval, S: serde::Serializer> StreamEnum<'sval> for SerializeEnum { ) -> sval_nested::Result { let variant = label .and_then(|label| label.as_static_str()) - .ok_or_else(|| sval_nested::Error::invalid_value("struct variant label must be static"))?; + .ok_or_else(|| { + sval_nested::Error::invalid_value("struct variant label must be static") + })?; - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| sval_nested::Error::invalid_value("struct variant index must be a 32bit value"))?; + let variant_index = index.and_then(|index| index.to_u32()).ok_or_else(|| { + sval_nested::Error::invalid_value("struct variant index must be a 32bit value") + })?; - let len = - num_entries.ok_or_else(|| sval_nested::Error::invalid_value("missing struct variant len"))?; + let len = num_entries + .ok_or_else(|| sval_nested::Error::invalid_value("missing struct variant len"))?; Ok(SerializeRecordVariant { serializer: self.serializer.serialize_struct_variant( @@ -611,9 +623,9 @@ impl<'sval, S: serde::ser::SerializeStructVariant> StreamRecord<'sval> label: sval::Label, value: V, ) -> sval_nested::Result { - let field = label - .as_static_str() - .ok_or_else(|| sval_nested::Error::invalid_value("struct variant field label must be static"))?; + let field = label.as_static_str().ok_or_else(|| { + sval_nested::Error::invalid_value("struct variant field label must be static") + })?; if let Ok(ref mut serializer) = self.serializer { match serializer.serialize_field(field, &ToSerialize::new(value)) { diff --git a/src/data.rs b/src/data.rs index d4d370fe..0629f1df 100644 --- a/src/data.rs +++ b/src/data.rs @@ -133,6 +133,27 @@ impl<'computed> Label<'computed> { pub const fn tag(&self) -> Option<&Tag> { self.tag.as_ref() } + + /** + Try create an owned label from this one. + + This method will always return `Ok` if the `alloc` feature is enabled. + If the `alloc` feature is not enabled then this method will only return `Ok` + if the underlying value is already `'static`. + */ + #[inline(always)] + pub fn try_to_owned(&self) -> Result> { + #[cfg(feature = "alloc")] + { + Ok(self.to_owned()) + } + #[cfg(not(feature = "alloc"))] + { + self.as_static_str() + .map(Label::new) + .ok_or_else(crate::Error::new) + } + } } impl<'a, 'b> PartialEq> for Label<'a> {