diff --git a/.github/workflows/nested.yml b/.github/workflows/nested.yml new file mode 100644 index 00000000..c4c3b710 --- /dev/null +++ b/.github/workflows/nested.yml @@ -0,0 +1,64 @@ +name: nested + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + + - name: Install Rust toolchain + run: rustup default nightly + + - name: Install cargo-hack + run: cargo install cargo-hack + + - name: Powerset + working-directory: ./nested + run: cargo hack test --feature-powerset + + - name: Minimal Versions + working-directory: ./nested + run: cargo hack test --feature-powerset -Z minimal-versions + + bench: + name: Bench + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + + - name: Install Rust toolchain + run: rustup default nightly + + - name: Install cargo-hack + run: cargo install cargo-hack + + - name: Powerset + working-directory: ./nested + run: cargo hack bench --feature-powerset --no-run + + embedded: + name: Build (embedded) + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab + + - name: Install Rust toolchain + run: | + rustup default nightly + rustup target add thumbv6m-none-eabi + + - name: Install cargo-hack + run: cargo install cargo-hack + + - name: Powerset + working-directory: ./nested + run: cargo hack check --each-feature --exclude-features std,alloc -Z avoid-dev-deps --target thumbv6m-none-eabi diff --git a/Cargo.toml b/Cargo.toml index 0ac12b0f..e6bb6b15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "buffer", "fmt", "fmt/test", + "nested", "serde", "serde/test", "json", diff --git a/buffer/src/error.rs b/buffer/src/error.rs index d491440e..1d04a431 100644 --- a/buffer/src/error.rs +++ b/buffer/src/error.rs @@ -12,13 +12,13 @@ enum ErrorKind { actual: &'static str, expected: &'static str, }, + InvalidValue { + reason: &'static str, + }, #[cfg(feature = "alloc")] OutsideContainer { method: &'static str, }, - InvalidValue { - reason: &'static str, - }, #[cfg(not(feature = "alloc"))] #[allow(dead_code)] NoAlloc { @@ -32,13 +32,13 @@ impl fmt::Display for Error { ErrorKind::Unsupported { actual, expected } => { write!(f, "unexpected {}, expected {}", actual, expected) } + ErrorKind::InvalidValue { reason } => { + write!(f, "the value is invalid: {}", reason) + } #[cfg(feature = "alloc")] ErrorKind::OutsideContainer { method } => { write!(f, "expected a fragment while buffering {}", method) } - ErrorKind::InvalidValue { reason } => { - write!(f, "the value being buffered is invalid: {}", reason) - } #[cfg(not(feature = "alloc"))] ErrorKind::NoAlloc { method } => write!(f, "cannot allocate for {}", method), } @@ -55,6 +55,9 @@ impl Error { Error(ErrorKind::OutsideContainer { method }) } + /** + The given value is invalid. + */ pub(crate) fn invalid_value(reason: &'static str) -> Self { Error(ErrorKind::InvalidValue { reason }) } diff --git a/buffer/src/lib.rs b/buffer/src/lib.rs index faea7b4d..62fce9c0 100644 --- a/buffer/src/lib.rs +++ b/buffer/src/lib.rs @@ -9,7 +9,7 @@ Rather than conditionally compile these methods, this library stubs out functionality when an allocator isn't available. */ -#![no_std] +#![cfg_attr(not(test), no_std)] #![deny(missing_docs)] mod error; @@ -20,13 +20,14 @@ extern crate std as libstd; #[cfg(not(feature = "alloc"))] extern crate core as std; -#[cfg(feature = "alloc")] +#[cfg(any(test, feature = "alloc"))] extern crate alloc; #[cfg(feature = "alloc")] extern crate core; #[cfg(feature = "alloc")] mod std { + #[allow(unused_imports)] pub use crate::{ alloc::{borrow, boxed, collections, string, vec}, core::{convert, fmt, hash, marker, mem, ops, result, str}, diff --git a/buffer/src/value.rs b/buffer/src/value.rs index 80d706c8..875c44b4 100644 --- a/buffer/src/value.rs +++ b/buffer/src/value.rs @@ -74,7 +74,9 @@ impl<'sval> ValueBuf<'sval> { match v.stream(&mut buf) { Ok(()) => Ok(buf), - Err(_) => Err(buf.into_err()), + Err(_) => Err(buf + .into_err() + .unwrap_or_else(|| Error::invalid_value("the value itself failed to stream"))), } } @@ -202,9 +204,14 @@ impl<'sval> ValueBuf<'sval> { sval::error() } - fn into_err(self) -> Error { + /** + Take an error produced while attempting to buffer a value. + + This method may return `None` even if streaming failed if a value failed + without ever calling into the buffer. + */ + pub fn into_err(self) -> Option { self.err - .unwrap_or_else(|| Error::invalid_value("the value itself failed to stream")) } } @@ -221,7 +228,9 @@ impl ValueBuf<'static> { // have to be converted into owned anyways match sval::stream_computed(&mut buf, v) { Ok(()) => Ok(buf), - Err(_) => Err(buf.into_err()), + Err(_) => Err(buf + .into_err() + .unwrap_or_else(|| Error::invalid_value("the value itself failed to stream"))), } } } @@ -1662,7 +1671,6 @@ mod alloc_support { #[cfg(test)] mod tests { use super::*; - use crate::std::{string::String, vec}; use sval::Stream as _; use sval_derive_macros::*; diff --git a/flatten/src/record_tuple.rs b/flatten/src/record_tuple.rs index 3b5163d4..04b77f5f 100644 --- a/flatten/src/record_tuple.rs +++ b/flatten/src/record_tuple.rs @@ -824,6 +824,105 @@ mod tests { ); } + #[test] + fn flatten_exotic_enum_empty() { + struct EmptyEnum; + + impl sval::Value for EmptyEnum { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&Label::new("Enum")), None)?; + stream.enum_end(None, Some(&Label::new("Enum")), None) + } + } + + sval_test::assert_tokens( + &Outer { + a: 1, + i: EmptyEnum, + d: 4, + }, + { + use sval_test::Token::*; + + &[ + RecordTupleBegin(None, Some(Label::new("Outer")), None, None), + RecordTupleValueBegin(None, Label::new("a"), Index::new(0)), + I32(1), + RecordTupleValueEnd(None, Label::new("a"), Index::new(0)), + RecordTupleValueBegin(None, Label::new("d"), Index::new(1)), + I32(4), + RecordTupleValueEnd(None, Label::new("d"), Index::new(1)), + RecordTupleEnd(None, Some(Label::new("Outer")), None), + ] + }, + ); + } + + #[test] + fn flatten_exotic_enum_nested_empty() { + struct NestedEnum; + + impl sval::Value for NestedEnum { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&Label::new("Enum")), None)?; + + stream.enum_begin( + None, + Some(&Label::new("EnumInner")), + Some(&Index::new(7).with_tag(&sval::tags::VALUE_OFFSET)), + )?; + + stream.enum_begin( + None, + Some(&Label::new("EnumInnerInner")), + Some(&Index::new(3).with_tag(&sval::tags::VALUE_OFFSET)), + )?; + + stream.enum_end( + None, + Some(&Label::new("EnumInnerInner")), + Some(&Index::new(3).with_tag(&sval::tags::VALUE_OFFSET)), + )?; + + stream.enum_end( + None, + Some(&Label::new("EnumInner")), + Some(&Index::new(7).with_tag(&sval::tags::VALUE_OFFSET)), + )?; + + stream.enum_end(None, Some(&Label::new("Enum")), None) + } + } + + sval_test::assert_tokens( + &Outer { + a: 1, + i: NestedEnum, + d: 4, + }, + { + use sval_test::Token::*; + + &[ + RecordTupleBegin(None, Some(Label::new("Outer")), None, None), + RecordTupleValueBegin(None, Label::new("a"), Index::new(0)), + I32(1), + RecordTupleValueEnd(None, Label::new("a"), Index::new(0)), + RecordTupleValueBegin(None, Label::new("d"), Index::new(1)), + I32(4), + RecordTupleValueEnd(None, Label::new("d"), Index::new(1)), + RecordTupleEnd(None, Some(Label::new("Outer")), None), + ] + }, + ); + } + #[test] fn flatten_primitive() { sval_test::assert_tokens( diff --git a/fmt/src/writer.rs b/fmt/src/writer.rs index 45e1f4ce..e8ec851f 100644 --- a/fmt/src/writer.rs +++ b/fmt/src/writer.rs @@ -344,15 +344,21 @@ impl<'sval, W: TokenWrite> sval::Stream<'sval> for Writer { _: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { + self.is_current_depth_empty = true; + Ok(()) } fn enum_end( &mut self, - _: Option<&sval::Tag>, - _: Option<&sval::Label>, - _: Option<&sval::Index>, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, ) -> sval::Result { + if self.is_current_depth_empty { + self.tag(tag, label, index)?; + } + Ok(()) } @@ -362,6 +368,8 @@ impl<'sval, W: TokenWrite> sval::Stream<'sval> for Writer { label: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { + self.is_current_depth_empty = false; + if tag == Some(&tags::NUMBER) { self.is_number = true; } @@ -403,6 +411,8 @@ impl<'sval, W: TokenWrite> sval::Stream<'sval> for Writer { label: Option<&sval::Label>, _: Option<&sval::Index>, ) -> sval::Result { + self.is_current_depth_empty = false; + if let Some(label) = label { self.out .write_type(label.as_str()) diff --git a/fmt/test/lib.rs b/fmt/test/lib.rs index ea0aae73..7ecfb46b 100644 --- a/fmt/test/lib.rs +++ b/fmt/test/lib.rs @@ -215,6 +215,54 @@ fn debug_exotic_nested_enum() { assert_eq!("Variant", format!("{:?}", sval_fmt::ToFmt::new(NestedEnum))); } +#[test] +fn debug_exotic_empty_enum() { + struct Enum; + + impl sval::Value for Enum { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Enum")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Enum")), None) + } + } + + assert_eq!("Enum", format!("{:?}", sval_fmt::ToFmt::new(Enum))); +} + +#[test] +fn debug_exotic_nested_enum_empty() { + // Outer::Inner::Variant + struct NestedEnum; + + impl sval::Value for NestedEnum { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Outer")), None)?; + + stream.enum_begin( + None, + Some(&sval::Label::new("Inner")), + Some(&sval::Index::new(1)), + )?; + + stream.enum_end( + None, + Some(&sval::Label::new("Inner")), + Some(&sval::Index::new(1)), + )?; + + stream.enum_end(None, Some(&sval::Label::new("Outer")), None) + } + } + + assert_eq!("Inner", format!("{:?}", sval_fmt::ToFmt::new(NestedEnum))); +} + #[test] fn debug_exotic_unnamed_enum() { // i32 | bool diff --git a/json/src/to_fmt.rs b/json/src/to_fmt.rs index 140a76ef..d557cb52 100644 --- a/json/src/to_fmt.rs +++ b/json/src/to_fmt.rs @@ -271,16 +271,21 @@ where _try_no_conv!(self.internally_tagged_begin(label)); self.is_internally_tagged = true; + self.is_current_depth_empty = true; Ok(()) } fn enum_end( &mut self, - _: Option<&sval::Tag>, + tag: Option<&sval::Tag>, label: Option<&sval::Label>, - _: Option<&sval::Index>, + index: Option<&sval::Index>, ) -> sval::Result { + if self.is_current_depth_empty { + _try_no_conv!(self.tag(tag, label, index)); + } + if self.is_internally_tagged { self.internally_tagged_map_end() } else { @@ -357,6 +362,7 @@ where _: Option<&sval::Index>, ) -> sval::Result { self.is_internally_tagged = false; + self.is_current_depth_empty = false; match tag { Some(&sval::tags::RUST_OPTION_NONE) => self.null(), @@ -442,6 +448,7 @@ where fn internally_tagged_begin(&mut self, label: Option<&sval::Label>) -> sval::Result { // If there's a label then begin a map, using the label as the key if self.is_internally_tagged { + self.is_current_depth_empty = false; self.is_internally_tagged = false; if let Some(label) = label { diff --git a/json/test/lib.rs b/json/test/lib.rs index 80804311..e62395f7 100644 --- a/json/test/lib.rs +++ b/json/test/lib.rs @@ -246,13 +246,10 @@ fn stream_enum() { #[test] fn stream_untagged_enum() { - #[derive(Value)] - enum Null {} - #[derive(Value)] #[sval(dynamic)] enum Dynamic<'a> { - Null(Option), + Null(sval::Null), Text(&'a str), Number(f64), Boolean(bool), @@ -273,7 +270,7 @@ fn stream_untagged_enum() { ); assert_eq!( "null", - sval_json::stream_to_string(Dynamic::Null(None)).unwrap() + sval_json::stream_to_string(Dynamic::Null(sval::Null)).unwrap() ); assert_eq!( "[true,false]", @@ -304,6 +301,23 @@ fn stream_externally_tagged_enum() { ); } +#[test] +fn stream_empty_enum() { + struct Enum; + + impl sval::Value for Enum { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Enum")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Enum")), None) + } + } + + assert_eq!("\"Enum\"", sval_json::stream_to_string(Enum).unwrap()); +} + #[test] fn stream_exotic_record() { // { field_0: 42, field_1: true, field_2: "Hello" } @@ -436,6 +450,47 @@ fn stream_exotic_nested_enum_tag() { assert_valid(SeqStruct(NestedEnum, NestedEnum)); } +#[test] +fn stream_exotic_nested_enum_empty() { + // Outer::Inner + struct NestedEnum; + + impl sval::Value for NestedEnum { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Outer")), None)?; + + stream.enum_begin( + None, + Some(&sval::Label::new("Inner")), + Some(&sval::Index::new(1)), + )?; + + stream.enum_end( + None, + Some(&sval::Label::new("Inner")), + Some(&sval::Index::new(1)), + )?; + + stream.enum_end(None, Some(&sval::Label::new("Outer")), None) + } + } + + assert_eq!( + "{\"Inner\":\"Inner\"}", + sval_json::stream_to_string(NestedEnum).unwrap(), + ); + + assert_valid(MapStruct { + field_0: NestedEnum, + field_1: NestedEnum, + }); + + assert_valid(SeqStruct(NestedEnum, NestedEnum)); +} + #[test] fn stream_exotic_nested_enum_record() { // Outer::Inner::Variant { a: 42 } diff --git a/nested/Cargo.toml b/nested/Cargo.toml new file mode 100644 index 00000000..68f3a7f2 --- /dev/null +++ b/nested/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "sval_nested" +version = "2.10.2" +authors = ["Ashley Mannix "] +edition = "2021" +license = "Apache-2.0 OR MIT" +documentation = "https://docs.rs/sval_nested" +description = "A recursive variant of sval" +repository = "https://github.com/sval-rs/sval" +readme = "README.md" +keywords = ["serialization", "no_std"] +categories = ["encoding", "no-std"] + +[package.metadata.docs.rs] +features = ["std"] + +[features] +default = ["alloc"] +std = ["alloc", "sval/std", "sval_buffer/std"] +alloc = ["sval/alloc", "sval_buffer/alloc"] +no_debug_assertions = [] + +[dependencies.sval] +version = "2.10.2" +path = "../" + +[dependencies.sval_buffer] +version = "2.10.2" +path = "../buffer" +default-features = false + +[dependencies.sval_ref] +version = "2.10.2" +path = "../ref" + +[dev-dependencies.sval_derive_macros] +version = "2.10.2" +path = "../derive_macros" diff --git a/nested/LICENSE-APACHE b/nested/LICENSE-APACHE new file mode 100644 index 00000000..965b606f --- /dev/null +++ b/nested/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/nested/LICENSE-MIT b/nested/LICENSE-MIT new file mode 100644 index 00000000..76219eb7 --- /dev/null +++ b/nested/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/nested/README.md b/nested/README.md new file mode 100644 index 00000000..581873fa --- /dev/null +++ b/nested/README.md @@ -0,0 +1,7 @@ +# `sval_nested` + +[![Rust](https://github.com/sval-rs/sval/workflows/ref/badge.svg)](https://github.com/sval-rs/sval/actions) +[![Latest version](https://img.shields.io/crates/v/sval.svg)](https://crates.io/crates/sval_nested) +[![Documentation Latest](https://docs.rs/sval_nested/badge.svg)](https://docs.rs/sval_nested) + +A variant of `sval::Stream` for cases where a recursive API is needed. diff --git a/nested/src/error.rs b/nested/src/error.rs new file mode 100644 index 00000000..38de81e0 --- /dev/null +++ b/nested/src/error.rs @@ -0,0 +1,83 @@ +use core::fmt; + +/** +An error encountered buffering data. +*/ +#[derive(Debug)] +pub struct Error(ErrorKind); + +#[derive(Debug)] +enum ErrorKind { + Buffer(sval_buffer::Error), + InvalidValue { + reason: &'static str, + }, + #[cfg(not(feature = "alloc"))] + #[allow(dead_code)] + NoAlloc { + method: &'static str, + }, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + ErrorKind::Buffer(_) => { + write!(f, "failed to buffer a value") + } + ErrorKind::InvalidValue { reason } => { + write!(f, "the value is invalid: {}", reason) + } + #[cfg(not(feature = "alloc"))] + ErrorKind::NoAlloc { method } => write!(f, "cannot allocate for {}", method), + } + } +} + +impl Error { + pub(crate) fn buffer(err: sval_buffer::Error) -> Self { + Error(ErrorKind::Buffer(err)) + } + + /** + The given value is invalid. + */ + pub fn invalid_value(reason: &'static str) -> Self { + Error(ErrorKind::InvalidValue { reason }) + } + + #[cfg(not(feature = "alloc"))] + #[track_caller] + pub(crate) fn no_alloc(method: &'static str) -> Self { + /* + The pattern here is the same as what's used in `sval_buffer`. + */ + + #[cfg(all(debug_assertions, not(no_debug_assertions), not(test)))] + { + panic!("attempt to allocate for {} would fail; add the `alloc` feature of `sval_nested` or the depdendent `sval_*` library to support allocation. This call will error instead of panicking in release builds. Add the `no_debug_assertions` feature of `sval_nested` if this error is expected.", method); + } + #[cfg(not(all(debug_assertions, not(no_debug_assertions), not(test))))] + { + Error(ErrorKind::NoAlloc { method }) + } + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + use std::error; + + impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.0 { + ErrorKind::Buffer(ref err) => Some(err), + ErrorKind::InvalidValue { .. } => None, + #[cfg(not(feature = "alloc"))] + ErrorKind::NoAlloc { .. } => None, + } + } + } +} diff --git a/nested/src/flat.rs b/nested/src/flat.rs new file mode 100644 index 00000000..337e42f2 --- /dev/null +++ b/nested/src/flat.rs @@ -0,0 +1,1413 @@ +use core::{fmt, marker::PhantomData, mem}; + +use sval_buffer::{BinaryBuf, TextBuf, ValueBuf}; + +use crate::{Error, Result, Stream, StreamEnum, StreamMap, StreamRecord, StreamSeq, StreamTuple}; + +use super::{flat_enum::FlatStreamEnum, owned_label_ref}; + +pub(super) struct FlatStream<'sval, S: Stream<'sval>> { + buffered: Option>, + state: State<'sval, S>, +} + +impl<'sval, S: Stream<'sval>> fmt::Debug for FlatStream<'sval, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FlatStream") + .field("buffered", &self.buffered) + .field("state", &self.state) + .finish() + } +} + +enum State<'sval, S: Stream<'sval>> { + Any(Option>), + Seq(Option>), + Map(Option>), + Tagged(Option>), + Tuple(Option>), + Record(Option>), + Enum(Option>>), + EnumVariant(Option>), + Done(Option>), +} + +impl<'sval, S: Stream<'sval>> fmt::Debug for State<'sval, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + State::Any(state) => fmt::Debug::fmt(state, f), + State::Seq(state) => fmt::Debug::fmt(state, f), + State::Map(state) => fmt::Debug::fmt(state, f), + State::Tuple(state) => fmt::Debug::fmt(state, f), + State::Record(state) => fmt::Debug::fmt(state, f), + State::Tagged(state) => fmt::Debug::fmt(state, f), + State::Enum(state) => fmt::Debug::fmt(state, f), + State::EnumVariant(state) => fmt::Debug::fmt(state, f), + State::Done(_) => f.debug_struct("Done").finish_non_exhaustive(), + } + } +} + +#[derive(Debug)] +enum Buffered<'sval> { + Text(TextBuf<'sval>), + Binary(BinaryBuf<'sval>), + Value(ValueBuf<'sval>), +} + +struct Any<'sval, S: Stream<'sval>> { + stream: S, + _marker: PhantomData<&'sval ()>, +} + +impl<'sval, S: Stream<'sval>> fmt::Debug for Any<'sval, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Any").finish_non_exhaustive() + } +} + +struct Seq { + stream: S, +} + +impl fmt::Debug for Seq { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Seq").finish_non_exhaustive() + } +} + +struct Map { + stream: S, + is_key: bool, +} + +impl fmt::Debug for Map { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Map") + .field("is_key", &self.is_key) + .finish_non_exhaustive() + } +} + +struct Record { + stream: S, + field: Option<(Option, sval::Label<'static>)>, +} + +impl fmt::Debug for Record { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Record").finish_non_exhaustive() + } +} + +struct Tuple { + stream: S, + field: Option<(Option, sval::Index)>, +} + +impl fmt::Debug for Tuple { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Tuple").finish_non_exhaustive() + } +} + +struct Tagged { + stream: S, + tag: Option, + label: Option>, + index: Option, +} + +impl fmt::Debug for Tagged { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Tagged") + .field("tag", &self.tag) + .field("label", &self.label) + .field("index", &self.index) + .finish_non_exhaustive() + } +} + +struct Enum { + stream: S, +} + +impl fmt::Debug for Enum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Enum").finish_non_exhaustive() + } +} + +enum EnumVariant<'sval, S: Stream<'sval>> { + Tagged(Tagged>), + Tuple(Tuple<>::Tuple>), + Record(Record<>::Record>), +} + +impl<'sval, S: Stream<'sval>> fmt::Debug for EnumVariant<'sval, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EnumVariant::Tagged(stream) => fmt::Debug::fmt(stream, f), + EnumVariant::Tuple(stream) => fmt::Debug::fmt(stream, f), + EnumVariant::Record(stream) => fmt::Debug::fmt(stream, f), + } + } +} + +impl<'sval, S: Stream<'sval>> FlatStream<'sval, S> { + pub fn new(stream: S) -> Self { + FlatStream { + buffered: None, + state: State::Any(Some(Any { + stream, + _marker: PhantomData, + })), + } + } + + pub fn finish(&mut self) -> Result { + if let State::Done(ref mut r) = self.state { + r.take() + .unwrap_or_else(|| Err(Error::invalid_value("incomplete stream"))) + } else { + Err(Error::invalid_value("incomplete stream")) + } + } +} + +impl<'sval, S: Stream<'sval>> sval::Stream<'sval> for FlatStream<'sval, S> { + fn value(&mut self, v: &'sval V) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.value(v), + |stream| match stream.state { + State::Enum(_) => { + sval::default_stream::value(stream, v) + .map_err(|_| Error::invalid_value("failed to stream value"))?; + Ok(None) + } + ref mut state => state.value(&sval_ref::to_ref(v), |stream, v| stream.value(v)), + }, + ) + } + + fn value_computed(&mut self, v: &V) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.value_computed(v), + |stream| match stream.state { + State::Enum(_) => { + sval::default_stream::value_computed(stream, v) + .map_err(|_| Error::invalid_value("failed to stream value"))?; + Ok(None) + } + ref mut state => state.value_computed(v, |stream, v| stream.value_computed(v)), + }, + ) + } + + fn tag( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.tag(tag, label, index), + |stream| match stream.state { + State::Enum(ref mut stream) => { + let stream = stream.take().ok_or_else(|| { + Error::invalid_value( + "failed to stream an enum; the stream is already completed", + ) + })?; + + Ok(Some(stream.stream.tag( + tag.cloned(), + label.cloned(), + index.cloned(), + )?)) + } + ref mut state => state.value_computed(&Tag(tag, label, index), |stream, _| { + stream.tag(tag.cloned(), label.cloned(), index.cloned()) + }), + }, + ) + } + + fn seq_begin(&mut self, num_entries: Option) -> sval::Result { + self.buffer_or_begin_with( + |buf| buf.seq_begin(num_entries), + |stream| { + Ok(State::Seq(Some(Seq { + stream: stream.stream.seq_begin(num_entries)?, + }))) + }, + |_| { + Err(Error::invalid_value( + "sequences cannot be used as enum variants", + )) + }, + ) + } + + fn seq_value_begin(&mut self) -> sval::Result { + Ok(()) + } + + fn seq_value_end(&mut self) -> sval::Result { + Ok(()) + } + + fn seq_end(&mut self) -> sval::Result { + self.buffer_or_end_with( + |buf| buf.seq_end(), + |stream| stream.take_seq()?.stream.end(), + ) + } + + fn map_begin(&mut self, num_entries: Option) -> sval::Result { + self.buffer_or_begin_with( + |buf| buf.map_begin(num_entries), + |stream| { + Ok(State::Map(Some(Map { + stream: stream.stream.map_begin(num_entries)?, + is_key: true, + }))) + }, + |_| Err(Error::invalid_value("maps cannot be used as enum variants")), + ) + } + + fn map_key_begin(&mut self) -> sval::Result { + self.buffer_or_with( + |buf| buf.map_key_begin(), + |stream| { + stream.with_map(|stream| { + stream.is_key = true; + + Ok(()) + }) + }, + ) + } + + fn map_key_end(&mut self) -> sval::Result { + self.buffer_or_with(|buf| buf.map_key_end(), |_| Ok(())) + } + + fn map_value_begin(&mut self) -> sval::Result { + self.buffer_or_with( + |buf| buf.map_value_begin(), + |stream| { + stream.with_map(|stream| { + stream.is_key = false; + + Ok(()) + }) + }, + ) + } + + fn map_value_end(&mut self) -> sval::Result { + self.buffer_or_with(|buf| buf.map_value_end(), |_| Ok(())) + } + + fn map_end(&mut self) -> sval::Result { + self.buffer_or_end_with( + |buf| buf.map_end(), + |stream| stream.take_map()?.stream.end(), + ) + } + + fn enum_begin( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_begin_with( + |buf| buf.enum_begin(tag, label, index), + |stream| { + Ok(State::Enum(Some(Enum { + stream: FlatStreamEnum::new(stream.stream.enum_begin( + tag.cloned(), + label.cloned(), + index.cloned(), + )?), + }))) + }, + |mut stream| { + stream + .stream + .push(tag.cloned(), label.cloned(), index.cloned())?; + + Ok(State::Enum(Some(stream))) + }, + ) + } + + fn enum_end( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_end_with( + |buf| buf.enum_end(tag, label, index), + |stream| { + if let Some(stream) = stream.take_enum()? { + stream.stream.end() + } else { + stream.finish() + } + }, + ) + } + + fn tagged_begin( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_begin_with( + |buf| buf.tagged_begin(tag, label, index), + |stream| { + Ok(State::Tagged(Some(Tagged { + stream: stream.stream, + tag: tag.cloned(), + label: if let Some(label) = label { + Some(owned_label_ref(label)?) + } else { + None + }, + index: index.cloned(), + }))) + }, + |stream| { + Ok(State::EnumVariant(Some(EnumVariant::Tagged(Tagged { + stream: stream.stream, + tag: tag.cloned(), + label: if let Some(label) = label { + Some(owned_label_ref(label)?) + } else { + None + }, + index: index.cloned(), + })))) + }, + ) + } + + fn tagged_end( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_end_with( + |buf| buf.tagged_end(tag, label, index), + |stream| stream.finish(), + ) + } + + fn record_begin( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + num_entries: Option, + ) -> sval::Result { + self.buffer_or_begin_with( + |buf| buf.record_begin(tag, label, index, num_entries), + |stream| { + Ok(State::Record(Some(Record { + stream: stream.stream.record_begin( + tag.cloned(), + label.cloned(), + index.cloned(), + num_entries, + )?, + field: None, + }))) + }, + |stream| { + Ok(State::EnumVariant(Some(EnumVariant::Record(Record { + stream: stream.stream.record_begin( + tag.cloned(), + label.cloned(), + index.cloned(), + num_entries, + )?, + field: None, + })))) + }, + ) + } + + fn record_value_begin(&mut self, tag: Option<&sval::Tag>, label: &sval::Label) -> sval::Result { + self.buffer_or_with( + |buf| buf.record_value_begin(tag, label), + |stream| { + stream.with_record( + |record| { + record.field = Some((tag.cloned(), owned_label_ref(label)?)); + + Ok(()) + }, + |record_variant| { + record_variant.field = Some((tag.cloned(), owned_label_ref(label)?)); + + Ok(()) + }, + ) + }, + ) + } + + fn record_value_end(&mut self, tag: Option<&sval::Tag>, label: &sval::Label) -> sval::Result { + self.buffer_or_with(|buf| buf.record_value_end(tag, label), |_| Ok(())) + } + + fn record_end( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_end_with( + |buf| buf.record_end(tag, label, index), + |stream| { + stream.take_with_record( + |record| record.stream.end(), + |record_variant| record_variant.stream.end(), + ) + }, + ) + } + + fn tuple_begin( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + num_entries: Option, + ) -> sval::Result { + self.buffer_or_begin_with( + |buf| buf.tuple_begin(tag, label, index, num_entries), + |stream| { + Ok(State::Tuple(Some(Tuple { + stream: stream.stream.tuple_begin( + tag.cloned(), + label.cloned(), + index.cloned(), + num_entries, + )?, + field: None, + }))) + }, + |stream| { + Ok(State::EnumVariant(Some(EnumVariant::Tuple(Tuple { + stream: stream.stream.tuple_begin( + tag.cloned(), + label.cloned(), + index.cloned(), + num_entries, + )?, + field: None, + })))) + }, + ) + } + + fn tuple_value_begin(&mut self, tag: Option<&sval::Tag>, index: &sval::Index) -> sval::Result { + self.buffer_or_with( + |buf| buf.tuple_value_begin(tag, index), + |stream| { + stream.with_tuple( + |tuple| { + tuple.field = Some((tag.cloned(), index.clone())); + + Ok(()) + }, + |tuple_variant| { + tuple_variant.field = Some((tag.cloned(), index.clone())); + + Ok(()) + }, + ) + }, + ) + } + + fn tuple_value_end(&mut self, tag: Option<&sval::Tag>, index: &sval::Index) -> sval::Result { + self.buffer_or_with(|buf| buf.tuple_value_end(tag, index), |_| Ok(())) + } + + fn tuple_end( + &mut self, + tag: Option<&sval::Tag>, + label: Option<&sval::Label>, + index: Option<&sval::Index>, + ) -> sval::Result { + self.buffer_or_end_with( + |buf| buf.tuple_end(tag, label, index), + |stream| { + stream.take_with_tuple( + |tuple| tuple.stream.end(), + |tuple_variant| tuple_variant.stream.end(), + ) + }, + ) + } + + fn null(&mut self) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.null(), + |stream| { + stream + .state + .value(&sval_ref::to_ref(&sval::Null), |stream, _| stream.null()) + }, + ) + } + + fn bool(&mut self, value: bool) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.bool(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.bool(*value)) + }, + ) + } + + fn u8(&mut self, value: u8) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.u8(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.u8(*value)) + }, + ) + } + + fn u16(&mut self, value: u16) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.u16(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.u16(*value)) + }, + ) + } + + fn u32(&mut self, value: u32) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.u32(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.u32(*value)) + }, + ) + } + + fn u64(&mut self, value: u64) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.u64(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.u64(*value)) + }, + ) + } + + fn u128(&mut self, value: u128) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.u128(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.u128(*value)) + }, + ) + } + + fn i8(&mut self, value: i8) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.i8(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.i8(*value)) + }, + ) + } + + fn i16(&mut self, value: i16) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.i16(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.i16(*value)) + }, + ) + } + + fn i32(&mut self, value: i32) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.i32(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.i32(*value)) + }, + ) + } + + fn i64(&mut self, value: i64) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.i64(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.i64(*value)) + }, + ) + } + + fn i128(&mut self, value: i128) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.i128(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.i128(*value)) + }, + ) + } + + fn f32(&mut self, value: f32) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.f32(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.f32(*value)) + }, + ) + } + + fn f64(&mut self, value: f64) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.f64(value), + |stream| { + stream + .state + .value_computed(&value, |stream, value| stream.f64(*value)) + }, + ) + } + + fn text_begin(&mut self, size_hint: Option) -> sval::Result { + self.buffer_or_with( + |buf| buf.text_begin(size_hint), + |stream| stream.put_buffer(Buffered::Text(TextBuf::new())), + ) + } + + fn text_fragment(&mut self, fragment: &'sval str) -> sval::Result { + self.buffer_or_with( + |buf| buf.text_fragment(fragment), + |stream| stream.with_text(|text| text.push_fragment(fragment).map_err(Error::buffer)), + ) + } + + fn text_fragment_computed(&mut self, fragment: &str) -> sval::Result { + self.buffer_or_with( + |buf| buf.text_fragment_computed(fragment), + |stream| { + stream + .with_text(|text| text.push_fragment_computed(fragment).map_err(Error::buffer)) + }, + ) + } + + fn text_end(&mut self) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.text_end(), + |stream| { + let buf = stream.take_text()?; + + if let Some(text) = buf.as_borrowed_str() { + stream.state.value(&sval_ref::to_ref(text), |stream, text| { + stream.text(text.into_inner()) + }) + } else { + stream + .state + .value_computed(buf.as_str(), |stream, text| stream.text_computed(text)) + } + }, + ) + } + + fn binary_begin(&mut self, size_hint: Option) -> sval::Result { + self.buffer_or_with( + |buf| buf.binary_begin(size_hint), + |stream| stream.put_buffer(Buffered::Binary(BinaryBuf::new())), + ) + } + + fn binary_fragment(&mut self, fragment: &'sval [u8]) -> sval::Result { + self.buffer_or_with( + |buf| buf.binary_fragment(fragment), + |stream| { + stream.with_binary(|binary| binary.push_fragment(fragment).map_err(Error::buffer)) + }, + ) + } + + fn binary_fragment_computed(&mut self, fragment: &[u8]) -> sval::Result { + self.buffer_or_with( + |buf| buf.binary_fragment_computed(fragment), + |stream| { + stream.with_binary(|binary| { + binary + .push_fragment_computed(fragment) + .map_err(Error::buffer) + }) + }, + ) + } + + fn binary_end(&mut self) -> sval::Result { + self.buffer_or_stream_with( + |buf| buf.binary_end(), + |stream| { + let buf = stream.take_binary()?; + + if let Some(binary) = buf.as_borrowed_slice() { + stream.state.value( + &sval_ref::to_ref(sval::BinarySlice::new(binary)), + |stream, binary| stream.binary(binary.into_inner().as_slice()), + ) + } else { + stream + .state + .value_computed(sval::BinarySlice::new(buf.as_slice()), |stream, binary| { + stream.binary_computed(binary.as_slice()) + }) + } + }, + ) + } +} + +fn try_catch<'sval, T, S: Stream<'sval>>( + stream: &mut FlatStream<'sval, S>, + f: impl FnOnce(&mut FlatStream<'sval, S>) -> Result, +) -> sval::Result { + match f(stream) { + Ok(v) => Ok(v), + Err(e) => { + stream.state = State::Done(Some(Err(e))); + + sval::error() + } + } +} + +impl<'sval, S: Stream<'sval>> State<'sval, S> { + fn value + ?Sized>( + &mut self, + value: &V, + any: impl FnOnce(S, &V) -> Result, + ) -> Result> { + self.value_with( + |stream| any(stream, value), + |stream, tag, label, index| stream.tagged(tag, label, index, value), + |stream| StreamSeq::value(stream, value), + |stream| StreamMap::key(stream, value), + |stream| StreamMap::value(stream, value), + |stream, tag, index| stream.value(tag, index, value), + |stream, tag, label| stream.value(tag, label, value), + |stream, tag, label, index| stream.tagged(tag, label, index, value), + |stream, tag, index| stream.value(tag, index, value), + |stream, tag, label| stream.value(tag, label, value), + ) + } + + fn value_computed( + &mut self, + value: &V, + any: impl FnOnce(S, &V) -> Result, + ) -> Result> { + self.value_with( + |stream| any(stream, value), + |stream, tag, label, index| stream.tagged_computed(tag, label, index, value), + |stream| StreamSeq::value_computed(stream, value), + |stream| StreamMap::key_computed(stream, value), + |stream| StreamMap::value_computed(stream, value), + |stream, tag, index| stream.value_computed(tag, index, value), + |stream, tag, label| stream.value_computed(tag, label, value), + |stream, tag, label, index| stream.tagged_computed(tag, label, index, value), + |stream, tag, index| stream.value_computed(tag, index, value), + |stream, tag, label| stream.value_computed(tag, label, value), + ) + } + + fn value_with( + &mut self, + any: impl FnOnce(S) -> Result, + tagged: impl FnOnce( + S, + Option, + Option, + Option, + ) -> Result, + seq: impl FnOnce(&mut S::Seq) -> Result, + map_key: impl FnOnce(&mut S::Map) -> Result, + map_value: impl FnOnce(&mut S::Map) -> Result, + tuple: impl FnOnce(&mut S::Tuple, Option, sval::Index) -> Result, + record: impl FnOnce(&mut S::Record, Option, sval::Label) -> Result, + tagged_variant: impl FnOnce( + FlatStreamEnum, + Option, + Option, + Option, + ) -> Result, + tuple_variant: impl FnOnce( + &mut >::Tuple, + Option, + sval::Index, + ) -> Result, + record_variant: impl FnOnce( + &mut >::Record, + Option, + sval::Label, + ) -> Result, + ) -> Result> { + match self { + State::Any(ref mut stream) => { + let stream = stream.take().ok_or_else(|| { + Error::invalid_value("cannot stream value; the stream is already completed") + })?; + + Ok(Some(any(stream.stream)?)) + } + State::Tagged(ref mut stream) => { + let stream = stream.take().ok_or_else(|| { + Error::invalid_value( + "cannot stream tagged value; the stream is already completed", + ) + })?; + + Ok(Some(tagged( + stream.stream, + stream.tag, + stream.label, + stream.index, + )?)) + } + State::Seq(stream) => { + let stream = stream.as_mut().ok_or_else(|| { + Error::invalid_value( + "cannot stream a sequence; the stream is already completed", + ) + })?; + + seq(&mut stream.stream)?; + + Ok(None) + } + State::Map(stream) => { + let stream = stream.as_mut().ok_or_else(|| { + Error::invalid_value("cannot stream a map; the stream is already completed") + })?; + + if stream.is_key { + map_key(&mut stream.stream)?; + } else { + map_value(&mut stream.stream)?; + } + + Ok(None) + } + State::Tuple(stream) => { + let stream = stream.as_mut().ok_or_else(|| { + Error::invalid_value("cannot stream a tuple; the stream is already completed") + })?; + + let (tag, index) = stream.field.take().ok_or_else(|| { + Error::invalid_value("cannot stream a tuple; the field index is missing") + })?; + + tuple(&mut stream.stream, tag, index)?; + + Ok(None) + } + State::Record(stream) => { + let stream = stream.as_mut().ok_or_else(|| { + Error::invalid_value("cannot stream a record; the stream is already completed") + })?; + + let (tag, label) = stream.field.take().ok_or_else(|| { + Error::invalid_value("cannot stream a record; the field label is missing") + })?; + + record(&mut stream.stream, tag, label)?; + + Ok(None) + } + State::Enum(_) => Err(Error::invalid_value( + "cannot stream an enum; the stream is in an invalid state", + )), + State::EnumVariant(stream) => match stream { + Some(EnumVariant::Tuple(Tuple { + ref mut stream, + ref mut field, + })) => { + let (tag, index) = field.take().ok_or_else(|| { + Error::invalid_value( + "cannot stream a tuple variant; the field index is missing", + ) + })?; + + tuple_variant(stream, tag, index)?; + + Ok(None) + } + Some(EnumVariant::Record(Record { + ref mut stream, + ref mut field, + })) => { + let (tag, label) = field.take().ok_or_else(|| { + Error::invalid_value( + "cannot stream a record variant; the field label is missing", + ) + })?; + + record_variant(stream, tag, label)?; + + Ok(None) + } + stream => { + match stream.take().ok_or_else(|| { + Error::invalid_value( + "cannot stream an enum variant; the stream is already completed", + ) + })? { + EnumVariant::Tagged(Tagged { + stream, + tag, + label, + index, + }) => Ok(Some(tagged_variant(stream, tag, label, index)?)), + _ => unreachable!(), + } + } + }, + State::Done(_) => Err(Error::invalid_value( + "cannot stream a value; the stream is already completed", + )), + } + } +} + +impl<'sval, S: Stream<'sval>> FlatStream<'sval, S> { + fn buffer_or_stream_with( + &mut self, + buffer: impl FnOnce(&mut ValueBuf<'sval>) -> sval::Result, + stream: impl FnOnce(&mut Self) -> Result>, + ) -> sval::Result { + let mut r = None; + self.buffer_or_with(buffer, |s| match stream(s) { + Ok(ok) => { + r = ok; + Ok(()) + } + Err(e) => Err(e), + })?; + + if let Some(ok) = r { + self.state = State::Done(Some(Ok(ok))); + } + + Ok(()) + } + + fn buffer_or_with( + &mut self, + buffer: impl FnOnce(&mut ValueBuf<'sval>) -> sval::Result, + stream: impl FnOnce(&mut Self) -> Result, + ) -> sval::Result { + let r = try_catch(self, |s: &mut FlatStream<'_, S>| match s { + FlatStream { + buffered: Some(Buffered::Value(ref mut buf)), + .. + } => { + if buffer(buf).is_err() { + let buf = mem::take(buf); + + Err(buf.into_err().map(Error::buffer).unwrap_or_else(|| { + Error::invalid_value("the value itself failed to stream") + })) + } else { + Ok(()) + } + } + s => stream(s), + }); + + r + } + + fn buffer_or_begin_with( + &mut self, + mut buffer: impl FnMut(&mut ValueBuf<'sval>) -> sval::Result, + transition_any: impl FnOnce(Any<'sval, S>) -> Result>, + transition_enum: impl FnOnce(Enum>) -> Result>, + ) -> sval::Result { + let new_buf = try_catch(self, |stream| match stream { + FlatStream { + buffered: Some(Buffered::Value(ref mut buf)), + state: _, + } => { + if buffer(buf).is_err() { + let buf = mem::take(buf); + + return Err(buf.into_err().map(Error::buffer).unwrap_or_else(|| { + Error::invalid_value("the value itself failed to stream") + })); + } + + Ok(None) + } + FlatStream { + buffered: None, + state: State::Any(state), + } => { + stream.state = transition_any(state.take().ok_or_else(|| { + Error::invalid_value("cannot stream value; the stream is already completed") + })?)?; + + Ok(None) + } + FlatStream { + buffered: None, + state: State::Enum(state), + } => { + stream.state = transition_enum(state.take().ok_or_else(|| { + Error::invalid_value( + "cannot stream enum value; the stream is already completed", + ) + })?)?; + + Ok(None) + } + FlatStream { + buffered: None, + state: _, + } => { + let mut buf = ValueBuf::new(); + if buffer(&mut buf).is_err() { + return Err(buf.into_err().map(Error::buffer).unwrap_or_else(|| { + Error::invalid_value("the value itself failed to stream") + })); + } + + Ok(Some(Buffered::Value(buf))) + } + _ => Err(Error::invalid_value( + "cannot begin buffering; the stream is in an invalid state", + )), + })?; + + if let Some(new_buf) = new_buf { + self.buffered = Some(new_buf); + } + + Ok(()) + } + + fn buffer_or_end_with( + &mut self, + buffer: impl FnOnce(&mut ValueBuf<'sval>) -> sval::Result, + transition: impl FnOnce(&mut Self) -> Result, + ) -> sval::Result { + let r = try_catch(self, |stream| match stream { + FlatStream { buffered: None, .. } => Ok(Some(transition(stream)?)), + FlatStream { buffered, .. } => { + let Some(Buffered::Value(ref mut buf)) = buffered else { + return Err(Error::invalid_value( + "cannot end buffering value; the stream is in an invalid state", + )); + }; + + if buffer(buf).is_err() { + let buf = mem::take(buf); + + return Err(buf.into_err().map(Error::buffer).unwrap_or_else(|| { + Error::invalid_value("the value itself failed to stream") + })); + } + + if buf.is_complete() { + let buf = mem::take(buf); + *buffered = None; + + return stream + .state + .value_computed(&buf, |stream, value| stream.value_computed(value)); + } + + return Ok(None); + } + })?; + + if let Some(r) = r { + self.state = State::Done(Some(Ok(r))); + } + + Ok(()) + } + + fn put_buffer(&mut self, buf: Buffered<'sval>) -> Result { + match self.buffered { + None => { + self.buffered = Some(buf); + + Ok(()) + } + Some(_) => Err(Error::invalid_value( + "cannot begin buffering; a buffer is already active", + )), + } + } + + fn with_text(&mut self, buffer: impl FnOnce(&mut TextBuf<'sval>) -> Result) -> Result { + match self.buffered { + Some(Buffered::Text(ref mut buf)) => buffer(buf), + _ => Err(Error::invalid_value( + "cannot buffer text; no active text buffer", + )), + } + } + + fn take_text(&mut self) -> Result> { + match self.buffered { + Some(Buffered::Text(ref mut buf)) => { + let buf = mem::take(buf); + self.buffered = None; + + Ok(buf) + } + _ => Err(Error::invalid_value( + "cannot end buffering text; no active text buffer", + )), + } + } + + fn with_binary(&mut self, buffer: impl FnOnce(&mut BinaryBuf<'sval>) -> Result) -> Result { + match self.buffered { + Some(Buffered::Binary(ref mut buf)) => buffer(buf), + _ => Err(Error::invalid_value( + "cannot buffer binary; no active binary buffer", + )), + } + } + + fn take_binary(&mut self) -> Result> { + match self.buffered { + Some(Buffered::Binary(ref mut buf)) => { + let buf = mem::take(buf); + self.buffered = None; + + Ok(buf) + } + _ => Err(Error::invalid_value( + "cannot end buffering binary; no active binary buffer", + )), + } + } + + fn take_seq(&mut self) -> Result> { + match self { + FlatStream { + buffered: None, + state: State::Seq(seq), + } => seq.take().ok_or_else(|| { + Error::invalid_value("cannot end a sequence; the stream is already completed") + }), + _ => Err(Error::invalid_value( + "cannot end a sequence; invalid stream state", + )), + } + } + + fn with_map(&mut self, f: impl FnOnce(&mut Map) -> Result) -> Result { + match self { + FlatStream { + buffered: None, + state: State::Map(Some(map)), + } => f(map), + _ => Err(Error::invalid_value( + "cannot stream a map; invalid stream state", + )), + } + } + + fn take_map(&mut self) -> Result> { + match self { + FlatStream { + buffered: None, + state: State::Map(map), + } => map.take().ok_or_else(|| { + Error::invalid_value("cannot end a map; the stream is already completed") + }), + _ => Err(Error::invalid_value( + "cannot end a map; invalid stream state", + )), + } + } + + fn with_tuple( + &mut self, + tuple: impl FnOnce(&mut Tuple) -> Result, + tuple_variant: impl FnOnce(&mut Tuple<>::Tuple>) -> Result, + ) -> Result { + match self { + FlatStream { + buffered: None, + state: State::Tuple(Some(stream)), + } => tuple(stream), + FlatStream { + buffered: None, + state: State::EnumVariant(Some(EnumVariant::Tuple(stream))), + } => tuple_variant(stream), + _ => Err(Error::invalid_value( + "cannot stream a tuple; invalid stream state", + )), + } + } + + fn take_with_tuple( + &mut self, + tuple: impl FnOnce(Tuple) -> Result, + tuple_variant: impl FnOnce(Tuple<>::Tuple>) -> Result, + ) -> Result { + match self { + FlatStream { + buffered: None, + state: State::Tuple(stream), + } => tuple(stream.take().ok_or_else(|| { + Error::invalid_value("cannot end a tuple; the stream is already completed") + })?), + FlatStream { + buffered: None, + state: State::EnumVariant(stream), + } => { + let stream = stream.take().ok_or_else(|| { + Error::invalid_value("cannot end a tuple; the stream is already completed") + })?; + + match stream { + EnumVariant::Tuple(stream) => tuple_variant(stream), + _ => Err(Error::invalid_value( + "cannot end a tuple; invalid stream state", + )), + } + } + _ => Err(Error::invalid_value( + "cannot end a tuple; invalid stream state", + )), + } + } + + fn with_record( + &mut self, + record: impl FnOnce(&mut Record) -> Result, + record_variant: impl FnOnce(&mut Record<>::Record>) -> Result, + ) -> Result { + match self { + FlatStream { + buffered: None, + state: State::Record(Some(stream)), + } => record(stream), + FlatStream { + buffered: None, + state: State::EnumVariant(Some(EnumVariant::Record(stream))), + } => record_variant(stream), + _ => Err(Error::invalid_value( + "cannot stream a record; invalid stream state", + )), + } + } + + fn take_with_record( + &mut self, + record: impl FnOnce(Record) -> Result, + record_variant: impl FnOnce(Record<>::Record>) -> Result, + ) -> Result { + match self { + FlatStream { + buffered: None, + state: State::Record(stream), + } => record(stream.take().ok_or_else(|| { + Error::invalid_value("cannot end a record; the stream is already completed") + })?), + FlatStream { + buffered: None, + state: State::EnumVariant(stream), + } => { + let stream = stream.take().ok_or_else(|| { + Error::invalid_value("cannot end a record; the stream is already completed") + })?; + + match stream { + EnumVariant::Record(stream) => record_variant(stream), + _ => Err(Error::invalid_value( + "cannot end a record; invalid stream state", + )), + } + } + _ => Err(Error::invalid_value( + "cannot end a record; invalid stream state", + )), + } + } + + fn take_enum(&mut self) -> Result>>> { + match self { + FlatStream { + buffered: None, + state: State::Enum(variant), + } => Ok(variant.take()), + FlatStream { + buffered: None, + state: State::Done(_), + } => Ok(None), + _ => Err(Error::invalid_value( + "cannot end an enum; invalid stream state", + )), + } + } +} + +struct Tag<'a>( + Option<&'a sval::Tag>, + Option<&'a sval::Label<'a>>, + Option<&'a sval::Index>, +); + +impl<'a> sval::Value for Tag<'a> { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { + stream.tag(self.0, self.1, self.2) + } +} diff --git a/nested/src/flat_enum.rs b/nested/src/flat_enum.rs new file mode 100644 index 00000000..385e1fbb --- /dev/null +++ b/nested/src/flat_enum.rs @@ -0,0 +1,257 @@ +use crate::{default_stream, Error, Result, Stream, StreamEnum, Unsupported}; + +use super::owned_label; + +pub(super) struct FlatStreamEnum { + stream: S, + queue: Queue, +} + +#[derive(Debug)] +struct NestedVariant { + tag: Option, + label: Option>, + index: Option, +} + +impl<'sval, S: StreamEnum<'sval>> FlatStreamEnum { + pub fn new(stream: S) -> Self { + FlatStreamEnum { + stream, + queue: Default::default(), + } + } + + pub fn push( + &mut self, + tag: Option, + label: Option, + index: Option, + ) -> Result { + self.queue.push_back(NestedVariant { + tag, + label: if let Some(label) = label { + Some(owned_label(label)?) + } else { + None + }, + index, + }) + } + + pub fn end(self) -> Result { + self.value_or_recurse(|stream, _| stream.end(), |stream, _| stream.end(), ()) + } + + fn value_or_recurse( + mut self, + value: impl FnOnce(Self, I) -> Result, + nested: impl FnOnce( + FlatStreamEnum, + I, + ) -> Result<>::Ok>, + input: I, + ) -> Result { + if let Some(variant) = self.queue.pop_front() { + self.stream + .nested(variant.tag, variant.label, variant.index, |variant| { + nested( + FlatStreamEnum { + stream: variant, + queue: self.queue, + }, + input, + ) + }) + } else { + value(self, input) + } + } +} + +impl<'sval, S: StreamEnum<'sval>> Stream<'sval> for FlatStreamEnum { + type Ok = S::Ok; + + type Seq = Unsupported; + type Map = Unsupported; + + type Tuple = S::Tuple; + type Record = S::Record; + + type Enum = Unsupported; + + fn value>(self, value: V) -> Result { + self.value_or_recurse( + |stream, value| default_stream::value(stream, value), + |stream, value| stream.value(value), + value, + ) + } + + fn value_computed(self, value: V) -> Result { + self.value_or_recurse( + |stream, value| default_stream::value_computed(stream, value), + |stream, value| stream.value_computed(value), + value, + ) + } + + fn null(self) -> Result { + Err(Error::invalid_value( + "enum variants must be wrapped in a tag-carrying value", + )) + } + + fn bool(self, _: bool) -> Result { + Err(Error::invalid_value( + "enum variants must be wrapped in a tag-carrying value", + )) + } + + fn i64(self, _: i64) -> Result { + Err(Error::invalid_value( + "enum variants must be wrapped in a tag-carrying value", + )) + } + + fn f64(self, _: f64) -> Result { + Err(Error::invalid_value( + "enum variants must be wrapped in a tag-carrying value", + )) + } + + fn text_computed(self, _: &str) -> Result { + Err(Error::invalid_value( + "enum variants must be wrapped in a tag-carrying value", + )) + } + + fn tag( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result { + self.value_or_recurse( + |stream, (tag, label, index)| stream.stream.tag(tag, label, index), + |stream, (tag, label, index)| Stream::tag(stream, tag, label, index), + (tag, label, index), + ) + } + + fn tagged>( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result { + self.value_or_recurse( + |stream, (value, tag, label, index)| stream.stream.tagged(tag, label, index, value), + |stream, (value, tag, label, index)| Stream::tagged(stream, tag, label, index, value), + (value, tag, label, index), + ) + } + + fn tagged_computed( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result { + self.value_or_recurse( + |stream, (value, tag, label, index)| { + stream.stream.tagged_computed(tag, label, index, value) + }, + |stream, (value, tag, label, index)| { + Stream::tagged_computed(stream, tag, label, index, value) + }, + (value, tag, label, index), + ) + } + + fn seq_begin(self, _: Option) -> Result { + Ok(Unsupported::default()) + } + + fn map_begin(self, _: Option) -> Result { + Ok(Unsupported::default()) + } + + fn tuple_begin( + self, + tag: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> Result { + assert!(self.queue.is_empty()); + + self.stream.tuple_begin(tag, label, index, num_entries) + } + + fn record_begin( + self, + tag: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> Result { + assert!(self.queue.is_empty()); + + self.stream.record_begin(tag, label, index, num_entries) + } + + fn enum_begin( + self, + _: Option, + _: Option, + _: Option, + ) -> Result { + unreachable!() + } +} + +#[derive(Default)] +struct Queue { + #[cfg(feature = "alloc")] + inner: alloc::collections::VecDeque, +} + +impl Queue { + fn push_back(&mut self, variant: NestedVariant) -> Result { + #[cfg(feature = "alloc")] + { + self.inner.push_back(variant); + Ok(()) + } + #[cfg(not(feature = "alloc"))] + { + let _ = variant; + Err(Error::no_alloc("nested enum variant")) + } + } + + fn pop_front(&mut self) -> Option { + #[cfg(feature = "alloc")] + { + self.inner.pop_front() + } + #[cfg(not(feature = "alloc"))] + { + None + } + } + + fn is_empty(&self) -> bool { + #[cfg(feature = "alloc")] + { + self.inner.is_empty() + } + #[cfg(not(feature = "alloc"))] + { + true + } + } +} diff --git a/nested/src/lib.rs b/nested/src/lib.rs new file mode 100644 index 00000000..2fa3e2e4 --- /dev/null +++ b/nested/src/lib.rs @@ -0,0 +1,2279 @@ +/*! +A variant of [`sval::Stream`] for cases where a recursive API is needed. +*/ + +#![cfg_attr(not(test), no_std)] +#![deny(missing_docs)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +mod error; +mod flat; +mod flat_enum; + +pub use sval_ref::{Ref, ValueRef}; + +/** +A generic streaming result. +*/ +pub type Result = sval::Result; + +pub use self::error::*; + +use core::marker::PhantomData; + +use self::flat::FlatStream; + +/** +A recursive variant of [`sval::Stream`]. +*/ +pub trait Stream<'sval> { + /** + The type of value produced by this stream on completion. + */ + type Ok; + + /** + Stream a sequence. + */ + type Seq: StreamSeq<'sval, Ok = Self::Ok>; + + /** + Stream a map. + */ + type Map: StreamMap<'sval, Ok = Self::Ok>; + + /** + Stream a tuple. + */ + type Tuple: StreamTuple<'sval, Ok = Self::Ok>; + + /** + Stream a record. + */ + type Record: StreamRecord<'sval, Ok = Self::Ok>; + + /** + Stream an enum. + */ + type Enum: StreamEnum<'sval, Ok = Self::Ok>; + + /** + Recurse into a value. + */ + fn value>(self, value: V) -> Result + where + Self: Sized, + { + default_stream::value(self, value) + } + + /** + Recurse into a value by reference. + */ + fn value_ref(self, value: &'sval V) -> Result + where + Self: Sized, + { + default_stream::value_ref(self, value) + } + + /** + Recurse into a value for an arbitrarily short lifetime. + */ + fn value_computed(self, value: V) -> Result + where + Self: Sized, + { + default_stream::value_computed(self, value) + } + + /** + Stream null, the absence of any other meaningful value. + */ + fn null(self) -> Result; + + /** + Stream a boolean. + */ + fn bool(self, value: bool) -> Result; + + /** + Stream a signed 8bit integer. + */ + fn i8(self, value: i8) -> Result + where + Self: Sized, + { + default_stream::i8(self, value) + } + + /** + Stream a signed 16bit integer. + */ + fn i16(self, value: i16) -> Result + where + Self: Sized, + { + default_stream::i16(self, value) + } + + /** + Stream a signed 32bit integer. + */ + fn i32(self, value: i32) -> Result + where + Self: Sized, + { + default_stream::i32(self, value) + } + + /** + Stream a signed 64bit integer. + */ + fn i64(self, value: i64) -> Result; + + /** + Stream a signed 128bit integer. + */ + fn i128(self, value: i128) -> Result + where + Self: Sized, + { + default_stream::i128(self, value) + } + + /** + Stream an unsigned 8bit integer. + */ + fn u8(self, value: u8) -> Result + where + Self: Sized, + { + default_stream::u8(self, value) + } + + /** + Stream an unsigned 16bit integer. + */ + fn u16(self, value: u16) -> Result + where + Self: Sized, + { + default_stream::u16(self, value) + } + + /** + Stream an unsigned 32bit integer. + */ + fn u32(self, value: u32) -> Result + where + Self: Sized, + { + default_stream::u32(self, value) + } + + /** + Stream an unsigned 64bit integer. + */ + fn u64(self, value: u64) -> Result + where + Self: Sized, + { + default_stream::u64(self, value) + } + + /** + Stream an unsigned 128bit integer. + */ + fn u128(self, value: u128) -> Result + where + Self: Sized, + { + default_stream::u128(self, value) + } + + /** + Stream a 32bit floating point number. + */ + fn f32(self, value: f32) -> Result + where + Self: Sized, + { + default_stream::f32(self, value) + } + + /** + Stream a 64bit floating point number. + */ + fn f64(self, value: f64) -> Result; + + /** + Stream UTF8 text. + */ + fn text(self, text: &'sval str) -> Result + where + Self: Sized, + { + default_stream::text(self, text) + } + + /** + Stream UTF8 text, borrowed for an arbitrarily short lifetime. + */ + fn text_computed(self, text: &str) -> Result; + + /** + Streeam a bitstring. + */ + fn binary(self, binary: &'sval [u8]) -> Result + where + Self: Sized, + { + default_stream::binary(self, binary) + } + + /** + Stream a bitstring, borrowed for an arbitrarily short lifetime. + */ + fn binary_computed(self, binary: &[u8]) -> Result + where + Self: Sized, + { + default_stream::binary_computed(self, binary) + } + + /** + Stream a tag. + */ + fn tag( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result; + + /** + Stream a tagged value. + */ + fn tagged>( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result + where + Self: Sized, + { + default_stream::tagged(self, tag, label, index, value) + } + + /** + Stream a reference to a tagged value. + */ + fn tagged_ref( + self, + tag: Option, + label: Option, + index: Option, + value: &'sval V, + ) -> Result + where + Self: Sized, + { + default_stream::tagged_ref(self, tag, label, index, value) + } + + /** + Stream a tagged value, borrowed for an arbitrarily short lifetime. + */ + fn tagged_computed( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result; + + /** + Stream a sequence. + */ + fn seq_begin(self, num_entries: Option) -> Result; + + /** + Stream a map. + */ + fn map_begin(self, num_entries: Option) -> Result; + + /** + Stream a tuple. + */ + fn tuple_begin( + self, + tag: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> Result; + + /** + Stream a record. + */ + fn record_begin( + self, + tag: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> Result; + + /** + Stream an enum. + */ + fn enum_begin( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result; +} + +/** +A stream for a sequence. +*/ +pub trait StreamSeq<'sval> { + /** + The type of value produced by this stream on completion. + */ + type Ok; + + /** + Stream a sequence element. + */ + fn value>(&mut self, value: V) -> Result { + default_stream::seq_value(self, value) + } + + /** + Stream a reference to a sequence element. + */ + fn value_ref(&mut self, value: &'sval V) -> Result { + default_stream::seq_value_ref(self, value) + } + + /** + Stream a sequence element, borrowed for an arbitrarily short lifetime. + */ + fn value_computed(&mut self, value: V) -> Result; + + /** + Complete the sequence. + */ + fn end(self) -> Result; +} + +/** +A stream for a map. +*/ +pub trait StreamMap<'sval> { + /** + The type of value produced by this stream on completion. + */ + type Ok; + + /** + Stream a map key. + */ + fn key>(&mut self, key: V) -> Result { + default_stream::map_key(self, key) + } + + /** + Stream a reference to a map key. + */ + fn key_ref(&mut self, key: &'sval V) -> Result { + default_stream::map_key_ref(self, key) + } + + /** + Stream a map key, borrowed for an arbitrarily short lifetime. + */ + fn key_computed(&mut self, key: V) -> Result; + + /** + Stream a map value. + */ + fn value>(&mut self, value: V) -> Result { + default_stream::map_value(self, value) + } + + /** + Stream a reference to a map value. + */ + fn value_ref(&mut self, value: &'sval V) -> Result { + default_stream::map_value_ref(self, value) + } + + /** + Stream a map value, borrowed for an arbitrarily short lifetime. + */ + fn value_computed(&mut self, value: V) -> Result; + + /** + Complete the map. + */ + fn end(self) -> Result; +} + +/** +A stream for a tuple. +*/ +pub trait StreamTuple<'sval> { + /** + The type of value produced by this stream on completion. + */ + type Ok; + + /** + Stream a tuple field. + */ + fn value>( + &mut self, + tag: Option, + index: sval::Index, + value: V, + ) -> Result { + default_stream::tuple_value(self, tag, index, value) + } + + /** + Stream a reference to a tuple field. + */ + fn value_ref( + &mut self, + tag: Option, + index: sval::Index, + value: &'sval V, + ) -> Result { + default_stream::tuple_value_ref(self, tag, index, value) + } + + /** + Stream a tuple field, borrowed for an arbitrarily short lifetime. + */ + fn value_computed( + &mut self, + tag: Option, + index: sval::Index, + value: V, + ) -> Result; + + /** + Complete the tuple. + */ + fn end(self) -> Result; +} + +/** +A stream for a record. +*/ +pub trait StreamRecord<'sval> { + /** + The type of value produced by this stream on completion. + */ + type Ok; + + /** + Stream a record field. + */ + fn value>( + &mut self, + tag: Option, + label: sval::Label, + value: V, + ) -> Result { + default_stream::record_value(self, tag, label, value) + } + + /** + Stream a reference to a record field. + */ + fn value_ref( + &mut self, + tag: Option, + label: sval::Label, + value: &'sval V, + ) -> Result { + default_stream::record_value_ref(self, tag, label, value) + } + + /** + Stream a record field, borrowed for an arbitrarily short lifetime. + */ + fn value_computed( + &mut self, + tag: Option, + label: sval::Label, + value: V, + ) -> Result; + + /** + Complete the record. + */ + fn end(self) -> Result; +} + +/** +A stream for an enum. +*/ +pub trait StreamEnum<'sval> { + /** + The type of result produced by this stream on completion. + */ + type Ok; + + /** + Stream a tuple variant. + */ + type Tuple: StreamTuple<'sval, Ok = Self::Ok>; + + /** + Stream a record variant. + */ + type Record: StreamRecord<'sval, Ok = Self::Ok>; + + /** + Stream a nested enum variant. + */ + type Nested: StreamEnum<'sval, Ok = Self::Ok, Nested = Self::Nested>; + + /** + Stream a tag variant. + */ + fn tag( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result; + + /** + Stream a tagged value variant. + */ + fn tagged>( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result + where + Self: Sized, + { + default_stream::enum_tagged(self, tag, label, index, value) + } + + /** + Stream a reference to a tagged value variant. + */ + fn tagged_ref( + self, + tag: Option, + label: Option, + index: Option, + value: &'sval V, + ) -> Result + where + Self: Sized, + { + default_stream::enum_tagged_ref(self, tag, label, index, value) + } + + /** + Stream a tagged value variant, borrowed for an arbitrarily short lifetime. + */ + fn tagged_computed( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result; + + /** + Stream a tuple variant. + */ + fn tuple_begin( + self, + tag: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> Result; + + /** + Stream a record variant. + */ + fn record_begin( + self, + tag: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> Result; + + /** + Recurse into a nested variant. + */ + fn nested Result<>::Ok>>( + self, + tag: Option, + label: Option, + index: Option, + variant: F, + ) -> Result; + + /** + Stream an empty variant. + */ + fn empty(self) -> Result; +} + +/** +A placeholder for a kind of value that isn't supported by a particular stream. +*/ +pub struct Unsupported(PhantomData>); + +impl Default for Unsupported { + fn default() -> Self { + Unsupported(PhantomData) + } +} + +impl<'sval, Ok> Stream<'sval> for Unsupported { + type Ok = Ok; + + type Seq = Self; + type Map = Self; + type Tuple = Self; + type Record = Self; + type Enum = Self; + + fn null(self) -> Result { + Err(Error::invalid_value("null is unsupported")) + } + + fn bool(self, _: bool) -> Result { + Err(Error::invalid_value("booleans are unsupported")) + } + + fn i64(self, _: i64) -> Result { + Err(Error::invalid_value("numbers are unsupported")) + } + + fn f64(self, _: f64) -> Result { + Err(Error::invalid_value("numbers are unsupported")) + } + + fn text_computed(self, _: &str) -> Result { + Err(Error::invalid_value("text is unsupported")) + } + + fn tag( + self, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("tags are unsupported")) + } + + fn tagged_computed( + self, + _: Option, + _: Option, + _: Option, + _: V, + ) -> Result { + Err(Error::invalid_value("tagged values are unsupported")) + } + + fn seq_begin(self, _: Option) -> Result { + Err(Error::invalid_value("sequences are unsupported")) + } + + fn map_begin(self, _: Option) -> Result { + Err(Error::invalid_value("maps are unsupported")) + } + + fn tuple_begin( + self, + _: Option, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("records are unsupported")) + } + + fn record_begin( + self, + _: Option, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("records are unsupported")) + } + + fn enum_begin( + self, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } +} + +impl<'sval, Ok> StreamSeq<'sval> for Unsupported { + type Ok = Ok; + + fn value_computed(&mut self, _: V) -> Result { + Err(Error::invalid_value("sequences are unsupported")) + } + + fn end(self) -> Result { + Err(Error::invalid_value("sequences are unsupported")) + } +} + +impl<'sval, Ok> StreamMap<'sval> for Unsupported { + type Ok = Ok; + + fn key_computed(&mut self, _: V) -> Result { + Err(Error::invalid_value("maps are unsupported")) + } + + fn value_computed(&mut self, _: V) -> Result { + Err(Error::invalid_value("maps are unsupported")) + } + + fn end(self) -> Result { + Err(Error::invalid_value("maps are unsupported")) + } +} + +impl<'sval, Ok> StreamTuple<'sval> for Unsupported { + type Ok = Ok; + + fn value_computed( + &mut self, + _: Option, + _: sval::Index, + _: V, + ) -> Result { + Err(Error::invalid_value("tuples are unsupported")) + } + + fn end(self) -> Result { + Err(Error::invalid_value("tuples are unsupported")) + } +} + +impl<'sval, Ok> StreamRecord<'sval> for Unsupported { + type Ok = Ok; + + fn value_computed( + &mut self, + _: Option, + _: sval::Label, + _: V, + ) -> Result { + Err(Error::invalid_value("records are unsupported")) + } + + fn end(self) -> Result { + Err(Error::invalid_value("records are unsupported")) + } +} + +impl<'sval, Ok> StreamEnum<'sval> for Unsupported { + type Ok = Ok; + + type Tuple = Self; + type Record = Self; + type Nested = Self; + + fn tag( + self, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } + + fn tagged_computed( + self, + _: Option, + _: Option, + _: Option, + _: V, + ) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } + + fn tuple_begin( + self, + _: Option, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } + + fn record_begin( + self, + _: Option, + _: Option, + _: Option, + _: Option, + ) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } + + fn nested Result<>::Ok>>( + self, + _: Option, + _: Option, + _: Option, + _: F, + ) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } + + fn empty(self) -> Result { + Err(Error::invalid_value("enums are unsupported")) + } +} + +fn owned_label(label: sval::Label) -> Result> { + owned_label_ref(&label) +} + +fn owned_label_ref(label: &sval::Label) -> Result> { + #[cfg(feature = "alloc")] + { + Ok(label.to_owned()) + } + #[cfg(not(feature = "alloc"))] + { + if let Some(label) = label.as_static_str() { + Ok(sval::Label::new(label)) + } else { + Err(Error::no_alloc("streaming value")) + } + } +} + +pub mod default_stream { + /*! + Default method implementations for the [`Stream`] trait. + */ + + use super::*; + + /** + Recurse into a value. + */ + pub fn value<'sval, S: Stream<'sval>, V: sval_ref::ValueRef<'sval>>( + stream: S, + value: V, + ) -> Result { + let mut stream = FlatStream::new(stream); + let _ = sval_ref::stream_ref(&mut stream, value); + stream.finish() + } + + /** + Recurse into a value by reference. + */ + pub fn value_ref<'sval, S: Stream<'sval>, V: sval::Value + ?Sized>( + stream: S, + value: &'sval V, + ) -> Result { + stream.value(sval_ref::to_ref(value)) + } + + /** + Recurse into a value for an arbitrarily short lifetime. + */ + pub fn value_computed<'sval, S: Stream<'sval>, V: sval::Value>( + stream: S, + value: V, + ) -> Result { + let mut stream = FlatStream::new(stream); + let _ = sval::default_stream::value_computed(&mut stream, &value); + stream.finish() + } + + /** + Stream a signed 8bit integer. + */ + pub fn i8<'sval, S: Stream<'sval>>(stream: S, value: i8) -> Result { + stream.i16(value as i16) + } + + /** + Stream a signed 16bit integer. + */ + pub fn i16<'sval, S: Stream<'sval>>(stream: S, value: i16) -> Result { + stream.i32(value as i32) + } + + /** + Stream a signed 32bit integer. + */ + pub fn i32<'sval, S: Stream<'sval>>(stream: S, value: i32) -> Result { + stream.i64(value as i64) + } + + /** + Stream a signed 128bit integer. + */ + pub fn i128<'sval, S: Stream<'sval>>(stream: S, value: i128) -> Result { + if let Ok(value) = value.try_into() { + stream.i64(value) + } else { + let mut stream = FlatStream::new(stream); + let _ = sval::stream_number(&mut stream, value); + stream.finish() + } + } + + /** + Stream an unsigned 8bit integer. + */ + pub fn u8<'sval, S: Stream<'sval>>(stream: S, value: u8) -> Result { + stream.u16(value as u16) + } + + /** + Stream an unsigned 16bit integer. + */ + pub fn u16<'sval, S: Stream<'sval>>(stream: S, value: u16) -> Result { + stream.u32(value as u32) + } + + /** + Stream an unsigned 32bit integer. + */ + pub fn u32<'sval, S: Stream<'sval>>(stream: S, value: u32) -> Result { + stream.u64(value as u64) + } + + /** + Stream an unsigned 64bit integer. + */ + pub fn u64<'sval, S: Stream<'sval>>(stream: S, value: u64) -> Result { + stream.u128(value as u128) + } + + /** + Stream an unsigned 128bit integer. + */ + pub fn u128<'sval, S: Stream<'sval>>(stream: S, value: u128) -> Result { + if let Ok(value) = value.try_into() { + stream.i64(value) + } else { + let mut stream = FlatStream::new(stream); + let _ = sval::stream_number(&mut stream, value); + stream.finish() + } + } + + /** + Stream a 32bit floating point number. + */ + pub fn f32<'sval, S: Stream<'sval>>(stream: S, value: f32) -> Result { + stream.f64(value as f64) + } + + /** + Stream UTF8 text. + */ + pub fn text<'sval, S: Stream<'sval>>(stream: S, text: &'sval str) -> Result { + stream.text_computed(text) + } + + /** + Streeam a bitstring. + */ + pub fn binary<'sval, S: Stream<'sval>>(stream: S, binary: &'sval [u8]) -> Result { + stream.binary_computed(binary) + } + + /** + Stream a bitstring, borrowed for an arbitrarily short lifetime. + */ + pub fn binary_computed<'sval, S: Stream<'sval>>(stream: S, binary: &[u8]) -> Result { + let mut seq = stream.seq_begin(Some(binary.len()))?; + + for b in binary { + StreamSeq::value_computed(&mut seq, b)?; + } + + seq.end() + } + + /** + Stream a tagged value. + */ + pub fn tagged<'sval, S: Stream<'sval>, V: sval_ref::ValueRef<'sval>>( + stream: S, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result { + stream.tagged_computed(tag, label, index, value) + } + + /** + Stream a reference to a tagged value. + */ + pub fn tagged_ref<'sval, S: Stream<'sval>, V: sval::Value + ?Sized>( + stream: S, + tag: Option, + label: Option, + index: Option, + value: &'sval V, + ) -> Result { + stream.tagged(tag, label, index, sval_ref::to_ref(value)) + } + + /** + Stream a sequence element. + */ + pub fn seq_value<'sval, S: StreamSeq<'sval> + ?Sized, V: sval_ref::ValueRef<'sval>>( + seq: &mut S, + value: V, + ) -> Result { + seq.value_computed(value) + } + + /** + Stream a reference to a sequence element. + */ + pub fn seq_value_ref<'sval, S: StreamSeq<'sval> + ?Sized, V: sval::Value + ?Sized>( + seq: &mut S, + value: &'sval V, + ) -> Result { + seq.value(sval_ref::to_ref(value)) + } + + /** + Stream a map key. + */ + pub fn map_key<'sval, S: StreamMap<'sval> + ?Sized, V: sval_ref::ValueRef<'sval>>( + map: &mut S, + key: V, + ) -> Result { + map.key_computed(key) + } + + /** + Stream a reference to a map key. + */ + pub fn map_key_ref<'sval, S: StreamMap<'sval> + ?Sized, V: sval::Value + ?Sized>( + map: &mut S, + key: &'sval V, + ) -> Result { + map.key(sval_ref::to_ref(key)) + } + + /** + Stream a map value. + */ + pub fn map_value<'sval, S: StreamMap<'sval> + ?Sized, V: sval_ref::ValueRef<'sval>>( + map: &mut S, + value: V, + ) -> Result { + map.value_computed(value) + } + + /** + Stream a reference to a map value. + */ + pub fn map_value_ref<'sval, S: StreamMap<'sval> + ?Sized, V: sval::Value + ?Sized>( + map: &mut S, + value: &'sval V, + ) -> Result { + map.value(sval_ref::to_ref(value)) + } + + /** + Stream a tuple field. + */ + pub fn tuple_value<'sval, S: StreamTuple<'sval> + ?Sized, V: sval_ref::ValueRef<'sval>>( + tuple: &mut S, + tag: Option, + index: sval::Index, + value: V, + ) -> Result { + tuple.value_computed(tag, index, value) + } + + /** + Stream a reference to a tuple field. + */ + pub fn tuple_value_ref<'sval, S: StreamTuple<'sval> + ?Sized, V: sval::Value + ?Sized>( + tuple: &mut S, + tag: Option, + index: sval::Index, + value: &'sval V, + ) -> Result { + tuple.value(tag, index, sval_ref::to_ref(value)) + } + + /** + Stream a record field. + */ + pub fn record_value<'sval, S: StreamRecord<'sval> + ?Sized, V: sval_ref::ValueRef<'sval>>( + record: &mut S, + tag: Option, + label: sval::Label, + value: V, + ) -> Result { + record.value_computed(tag, label, value) + } + + /** + Stream a reference to a record field. + */ + pub fn record_value_ref<'sval, S: StreamRecord<'sval> + ?Sized, V: sval::Value + ?Sized>( + record: &mut S, + tag: Option, + label: sval::Label, + value: &'sval V, + ) -> Result { + record.value(tag, label, sval_ref::to_ref(value)) + } + + /** + Stream a tagged value variant. + */ + pub fn enum_tagged<'sval, S: StreamEnum<'sval>, V: sval_ref::ValueRef<'sval>>( + stream: S, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result { + stream.tagged_computed(tag, label, index, value) + } + + /** + Stream a reference to a tagged value variant. + */ + pub fn enum_tagged_ref<'sval, S: StreamEnum<'sval>, V: sval::Value + ?Sized>( + stream: S, + tag: Option, + label: Option, + index: Option, + value: &'sval V, + ) -> Result { + stream.tagged(tag, label, index, sval_ref::to_ref(value)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::borrow::Cow; + + use sval_derive_macros::*; + + #[test] + fn stream_derive() { + #[derive(Value)] + struct DeriveRecord { + a: i32, + b: DeriveTuple, + } + + #[derive(Value)] + struct DeriveTuple(i32, DeriveEnum); + + #[derive(Value)] + enum DeriveEnum { + Record { a: i32, b: DeriveTagged }, + } + + #[derive(Value)] + struct DeriveTagged(bool); + + assert_eq!( + Value::Record(Record { + tag: Tag::new(None, Some(sval::Label::new("DeriveRecord")), None).unwrap(), + entries: vec![ + (sval::Label::new("a"), Value::I64(1)), + ( + sval::Label::new("b"), + Value::Tuple(Tuple { + tag: Tag::new(None, Some(sval::Label::new("DeriveTuple")), None) + .unwrap(), + entries: vec![ + (sval::Index::new(0), Value::I64(2)), + ( + sval::Index::new(1), + Value::Enum(Enum { + tag: Tag::new( + None, + Some(sval::Label::new("DeriveEnum")), + None + ) + .unwrap(), + variant: Some(Variant::Record(Record { + tag: Tag::new( + None, + Some(sval::Label::new("Record")), + Some(sval::Index::new(0)) + ) + .unwrap(), + entries: vec![ + (sval::Label::new("a"), Value::I64(3)), + ( + sval::Label::new("b"), + Value::Tagged(Tagged { + tag: Tag::new( + None, + Some(sval::Label::new("DeriveTagged")), + None + ) + .unwrap(), + value: Box::new(Value::Bool(true)), + }) + ) + ] + })) + }) + ) + ] + }) + ) + ] + }), + ToValue::default() + .value_ref(&DeriveRecord { + a: 1, + b: DeriveTuple( + 2, + DeriveEnum::Record { + a: 3, + b: DeriveTagged(true) + } + ) + }) + .unwrap() + ); + } + + #[test] + fn stream_primitive() { + assert_eq!( + Value::Null, + ToValue::default().value_ref(&sval::Null).unwrap() + ); + assert_eq!( + Value::I64(42), + ToValue::default().value_ref(&42i64).unwrap() + ); + assert_eq!( + Value::F64(42.1), + ToValue::default().value_ref(&42.1).unwrap() + ); + assert_eq!( + Value::Bool(true), + ToValue::default().value_ref(&true).unwrap() + ); + } + + #[test] + fn stream_text_borrowed() { + assert_eq!( + Value::Text(Cow::Borrowed("borrowed")), + ToValue::default().value_ref("borrowed").unwrap() + ); + } + + #[test] + fn stream_binary_borrowed() { + assert_eq!( + Value::Binary(Cow::Borrowed(b"borrowed")), + ToValue::default() + .value_ref(sval::BinarySlice::new(b"borrowed")) + .unwrap() + ); + } + + #[test] + fn stream_seq() { + assert_eq!( + Value::Seq(Seq { + entries: vec![Value::I64(1), Value::I64(2), Value::I64(3),] + }), + ToValue::default().value_ref(&[1, 2, 3] as &[_]).unwrap() + ); + } + + #[test] + fn stream_map() { + assert_eq!( + Value::Map(Map { + entries: vec![ + (Value::Text(Cow::Borrowed("a")), Value::I64(1)), + (Value::Text(Cow::Borrowed("b")), Value::I64(2)), + (Value::Text(Cow::Borrowed("c")), Value::I64(3)), + ] + }), + ToValue::default() + .value_ref(sval::MapSlice::new(&[("a", 1), ("b", 2), ("c", 3),])) + .unwrap() + ); + } + + #[test] + fn stream_tuple() { + assert_eq!( + Value::Tuple(Tuple { + tag: Tag::new(None, Some(sval::Label::new("Tuple")), None).unwrap(), + entries: vec![ + (sval::Index::new(0), Value::I64(1)), + (sval::Index::new(1), Value::Bool(true)), + ] + }), + ToValue::default() + .value_ref(&{ + struct Tuple; + + impl sval::Value for Tuple { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.tuple_begin( + None, + Some(&sval::Label::new("Tuple")), + None, + None, + )?; + + stream.tuple_value_begin(None, &sval::Index::new(0))?; + stream.i64(1)?; + stream.tuple_value_end(None, &sval::Index::new(0))?; + + stream.tuple_value_begin(None, &sval::Index::new(1))?; + stream.bool(true)?; + stream.tuple_value_end(None, &sval::Index::new(1))?; + + stream.tuple_end(None, Some(&sval::Label::new("Tuple")), None) + } + } + + Tuple + }) + .unwrap(), + ) + } + + #[test] + fn stream_enum_tuple_variant() { + assert_eq!( + Value::Enum(Enum { + tag: Tag::new(None, Some(sval::Label::new("Enum")), None).unwrap(), + variant: Some(Variant::Tuple(Tuple { + tag: Tag::new( + None, + Some(sval::Label::new("Tuple")), + Some(sval::Index::new(0)) + ) + .unwrap(), + entries: vec![ + (sval::Index::new(0), Value::I64(1)), + (sval::Index::new(1), Value::Bool(true)), + ] + })), + }), + ToValue::default() + .value_ref(&{ + struct TupleVariant; + + impl sval::Value for TupleVariant { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Enum")), None)?; + + stream.tuple_begin( + None, + Some(&sval::Label::new("Tuple")), + Some(&sval::Index::new(0)), + None, + )?; + + stream.tuple_value_begin(None, &sval::Index::new(0))?; + stream.i64(1)?; + stream.tuple_value_end(None, &sval::Index::new(0))?; + + stream.tuple_value_begin(None, &sval::Index::new(1))?; + stream.bool(true)?; + stream.tuple_value_end(None, &sval::Index::new(1))?; + + stream.tuple_end( + None, + Some(&sval::Label::new("Tuple")), + Some(&sval::Index::new(0)), + )?; + + stream.enum_end(None, Some(&sval::Label::new("Enum")), None) + } + } + + TupleVariant + }) + .unwrap(), + ) + } + + #[test] + fn stream_record() { + assert_eq!( + Value::Record(Record { + tag: Tag::new(None, Some(sval::Label::new("Record")), None).unwrap(), + entries: vec![ + (sval::Label::new("a"), Value::I64(1)), + (sval::Label::new("b"), Value::Bool(true)), + ] + }), + ToValue::default() + .value_ref(&{ + struct Record; + + impl sval::Value for Record { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.record_begin( + None, + Some(&sval::Label::new("Record")), + None, + None, + )?; + + stream.record_value_begin(None, &sval::Label::new("a"))?; + stream.i64(1)?; + stream.record_value_end(None, &sval::Label::new("a"))?; + + stream.record_value_begin(None, &sval::Label::new("b"))?; + stream.bool(true)?; + stream.record_value_end(None, &sval::Label::new("b"))?; + + stream.record_end(None, Some(&sval::Label::new("Record")), None) + } + } + + Record + }) + .unwrap(), + ) + } + + #[test] + fn stream_enum_record_variant() { + assert_eq!( + Value::Enum(Enum { + tag: Tag::new(None, Some(sval::Label::new("Enum")), None).unwrap(), + variant: Some(Variant::Record(Record { + tag: Tag::new( + None, + Some(sval::Label::new("Record")), + Some(sval::Index::new(0)) + ) + .unwrap(), + entries: vec![ + (sval::Label::new("a"), Value::I64(1)), + (sval::Label::new("b"), Value::Bool(true)), + ] + })), + }), + ToValue::default() + .value_ref(&{ + struct RecordVariant; + + impl sval::Value for RecordVariant { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Enum")), None)?; + + stream.record_begin( + None, + Some(&sval::Label::new("Record")), + Some(&sval::Index::new(0)), + None, + )?; + + stream.record_value_begin(None, &sval::Label::new("a"))?; + stream.i64(1)?; + stream.record_value_end(None, &sval::Label::new("a"))?; + + stream.record_value_begin(None, &sval::Label::new("b"))?; + stream.bool(true)?; + stream.record_value_end(None, &sval::Label::new("b"))?; + + stream.record_end( + None, + Some(&sval::Label::new("Record")), + Some(&sval::Index::new(0)), + )?; + + stream.enum_end(None, Some(&sval::Label::new("Enum")), None) + } + } + + RecordVariant + }) + .unwrap(), + ) + } + + #[test] + #[cfg(feature = "alloc")] + fn stream_text_owned() { + assert_eq!( + Value::Text(Cow::Owned("owned".into())), + ToValue::default() + .value_ref(&{ + struct Text; + + impl sval::Value for Text { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.text_begin(None)?; + + stream.text_fragment("ow")?; + stream.text_fragment("ned")?; + + stream.text_end() + } + } + + Text + }) + .unwrap() + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn stream_binary_owned() { + assert_eq!( + Value::Binary(Cow::Owned(b"owned".into())), + ToValue::default() + .value_ref(&{ + struct Binary; + + impl sval::Value for Binary { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.binary_begin(None)?; + + stream.binary_fragment(b"ow")?; + stream.binary_fragment(b"ned")?; + + stream.binary_end() + } + } + + Binary + }) + .unwrap() + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn stream_enum_nested_value() { + struct Layer; + + impl sval::Value for Layer { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + struct Layer; + + impl sval::Value for Layer { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Layer2")), None)?; + stream.tagged_begin(None, Some(&sval::Label::new("Value")), None)?; + stream.i64(42)?; + stream.tagged_end(None, Some(&sval::Label::new("Value")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer2")), None) + } + } + + stream.enum_begin(None, Some(&sval::Label::new("Layer1")), None)?; + stream.value(&Layer)?; + stream.enum_end(None, Some(&sval::Label::new("Layer1")), None) + } + } + + assert_eq!( + Value::Enum(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer1")), None).unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer2")), None).unwrap(), + variant: Some(Variant::Tagged(Tagged { + tag: Tag::new(None, Some(sval::Label::new("Value")), None).unwrap(), + value: Box::new(Value::I64(42)), + })) + }))) + }), + ToValue::default().value_ref(&Layer).unwrap() + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn stream_deeply_nested_enum() { + struct Layer; + + impl sval::Value for Layer { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + stream.enum_begin(None, Some(&sval::Label::new("Layer1")), None)?; + stream.enum_begin(None, Some(&sval::Label::new("Layer2")), None)?; + stream.enum_begin(None, Some(&sval::Label::new("Layer3")), None)?; + stream.enum_begin(None, Some(&sval::Label::new("Layer4")), None)?; + stream.enum_begin(None, Some(&sval::Label::new("Layer5")), None)?; + stream.enum_begin(None, Some(&sval::Label::new("Layer6")), None)?; + stream.enum_begin(None, Some(&sval::Label::new("Layer7")), None)?; + stream.tagged_begin(None, Some(&sval::Label::new("Value")), None)?; + stream.i64(42)?; + stream.tagged_end(None, Some(&sval::Label::new("Value")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer7")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer6")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer5")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer4")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer3")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer2")), None)?; + stream.enum_end(None, Some(&sval::Label::new("Layer1")), None) + } + } + + assert_eq!( + Value::Enum(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer1")), None).unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer2")), None).unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer3")), None).unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer4")), None).unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer5")), None) + .unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer6")), None) + .unwrap(), + variant: Some(Variant::Enum(Box::new(Enum { + tag: Tag::new(None, Some(sval::Label::new("Layer7")), None) + .unwrap(), + variant: Some(Variant::Tagged(Tagged { + tag: Tag::new( + None, + Some(sval::Label::new("Value")), + None + ) + .unwrap(), + value: Box::new(Value::I64(42)), + })) + }))) + }))) + }))) + }))) + }))) + }))) + }), + ToValue::default().value_ref(&Layer).unwrap() + ); + } + + #[derive(Debug, PartialEq)] + enum Value<'sval> { + Null, + Bool(bool), + I64(i64), + F64(f64), + Binary(Cow<'sval, [u8]>), + Text(Cow<'sval, str>), + Tag(Tag), + Tagged(Tagged<'sval>), + Seq(Seq<'sval>), + Map(Map<'sval>), + Tuple(Tuple<'sval>), + Record(Record<'sval>), + Enum(Enum<'sval>), + } + + impl<'sval> Value<'sval> { + fn try_into_variant(self) -> Result, Error> { + match self { + Value::Tag(variant) => Ok(Variant::Tag(variant)), + Value::Tagged(variant) => Ok(Variant::Tagged(variant)), + Value::Tuple(variant) => Ok(Variant::Tuple(variant)), + Value::Record(variant) => Ok(Variant::Record(variant)), + Value::Enum(variant) => Ok(Variant::Enum(Box::new(variant))), + _ => Err(Error::invalid_value("expected an enum variant")), + } + } + } + + #[derive(Debug, PartialEq)] + struct Tag { + tag: Option, + label: Option>, + index: Option, + } + + impl Tag { + fn new( + tag: Option, + label: Option, + index: Option, + ) -> Result { + Ok(Tag { + tag, + label: label.map(owned_label).transpose()?, + index: index, + }) + } + } + + #[derive(Debug, PartialEq)] + struct Tagged<'sval> { + tag: Tag, + value: Box>, + } + + #[derive(Debug, PartialEq)] + struct Seq<'sval> { + entries: Vec>, + } + + #[derive(Debug, PartialEq)] + struct Map<'sval> { + entries: Vec<(Value<'sval>, Value<'sval>)>, + } + + #[derive(Debug, PartialEq)] + struct Tuple<'sval> { + tag: Tag, + entries: Vec<(sval::Index, Value<'sval>)>, + } + + #[derive(Debug, PartialEq)] + struct Record<'sval> { + tag: Tag, + entries: Vec<(sval::Label<'static>, Value<'sval>)>, + } + + #[derive(Debug, PartialEq)] + struct Enum<'sval> { + tag: Tag, + variant: Option>, + } + + #[derive(Debug, PartialEq)] + enum Variant<'sval> { + Tag(Tag), + Tagged(Tagged<'sval>), + Tuple(Tuple<'sval>), + Record(Record<'sval>), + Enum(Box>), + } + + #[derive(Default)] + struct ToValue<'sval>(PhantomData>); + + struct ToMap<'sval> { + key: Option>, + map: Map<'sval>, + } + + struct ToSeq<'sval> { + seq: Seq<'sval>, + } + + struct ToTuple<'sval> { + tuple: Tuple<'sval>, + } + + struct ToRecord<'sval> { + record: Record<'sval>, + } + + struct ToEnum<'sval> { + tag: Tag, + _marker: PhantomData>, + } + + struct ToVariant { + tag: Tag, + stream: S, + } + + impl<'sval> Stream<'sval> for ToValue<'sval> { + type Ok = Value<'sval>; + + type Seq = ToSeq<'sval>; + type Map = ToMap<'sval>; + + type Tuple = ToTuple<'sval>; + type Record = ToRecord<'sval>; + type Enum = ToEnum<'sval>; + + fn null(self) -> Result { + Ok(Value::Null) + } + + fn bool(self, value: bool) -> Result { + Ok(Value::Bool(value)) + } + + fn i64(self, value: i64) -> Result { + Ok(Value::I64(value)) + } + + fn f64(self, value: f64) -> Result { + Ok(Value::F64(value)) + } + + fn text(self, text: &'sval str) -> Result { + Ok(Value::Text(Cow::Borrowed(text))) + } + + fn text_computed(self, text: &str) -> Result { + Ok(Value::Text(Cow::Owned(text.into()))) + } + + fn binary(self, binary: &'sval [u8]) -> Result { + Ok(Value::Binary(Cow::Borrowed(binary))) + } + + fn binary_computed(self, binary: &[u8]) -> Result { + Ok(Value::Binary(Cow::Owned(binary.into()))) + } + + fn tag( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result { + let tag = Tag::new(tag, label, index)?; + + Ok(Value::Tag(tag)) + } + + fn tagged_computed( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result { + let tag = Tag::new(tag, label, index)?; + let value = ToValue::default().value_computed(value)?; + + Ok(Value::Tagged(Tagged { + tag, + value: Box::new(value), + })) + } + + fn seq_begin(self, _: Option) -> Result { + Ok(ToSeq { + seq: Seq { + entries: Vec::new(), + }, + }) + } + + fn map_begin(self, _: Option) -> Result { + Ok(ToMap { + key: None, + map: Map { + entries: Vec::new(), + }, + }) + } + + fn tuple_begin( + self, + tag: Option, + label: Option, + index: Option, + _: Option, + ) -> Result { + Ok(ToTuple { + tuple: Tuple { + tag: Tag::new(tag, label, index)?, + entries: Default::default(), + }, + }) + } + + fn record_begin( + self, + tag: Option, + label: Option, + index: Option, + _: Option, + ) -> Result { + Ok(ToRecord { + record: Record { + tag: Tag::new(tag, label, index)?, + entries: Default::default(), + }, + }) + } + + fn enum_begin( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result { + Ok(ToEnum { + tag: Tag::new(tag, label, index)?, + _marker: Default::default(), + }) + } + } + + impl<'sval> StreamSeq<'sval> for ToSeq<'sval> { + type Ok = Value<'sval>; + + fn value>(&mut self, value: V) -> Result { + let value = ToValue::default().value(value)?; + + self.seq.entries.push(value); + + Ok(()) + } + + fn value_computed(&mut self, value: V) -> Result { + let value = ToValue::default().value_computed(value)?; + + self.seq.entries.push(value); + + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Seq(self.seq)) + } + } + + impl<'sval> StreamMap<'sval> for ToMap<'sval> { + type Ok = Value<'sval>; + + fn key>(&mut self, key: V) -> Result { + self.key = Some(ToValue::default().value(key)?); + + Ok(()) + } + + fn key_computed(&mut self, key: V) -> Result { + self.key = Some(ToValue::default().value_computed(key)?); + + Ok(()) + } + + fn value>(&mut self, value: V) -> Result { + let key = self.key.take().unwrap(); + let value = ToValue::default().value(value)?; + + self.map.entries.push((key, value)); + + Ok(()) + } + + fn value_computed(&mut self, value: V) -> Result { + let key = self.key.take().unwrap(); + let value = ToValue::default().value_computed(value)?; + + self.map.entries.push((key, value)); + + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Map(self.map)) + } + } + + impl<'sval> StreamTuple<'sval> for ToTuple<'sval> { + type Ok = Value<'sval>; + + fn value>( + &mut self, + _: Option, + index: sval::Index, + value: V, + ) -> Result { + let value = ToValue::default().value(value)?; + + self.tuple.entries.push((index.clone(), value)); + + Ok(()) + } + + fn value_computed( + &mut self, + _: Option, + index: sval::Index, + value: V, + ) -> Result { + let value = ToValue::default().value_computed(value)?; + + self.tuple.entries.push((index.clone(), value)); + + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Tuple(self.tuple)) + } + } + + impl<'sval> StreamRecord<'sval> for ToRecord<'sval> { + type Ok = Value<'sval>; + + fn value>( + &mut self, + _: Option, + label: sval::Label, + value: V, + ) -> Result { + let label = owned_label(label)?; + let value = ToValue::default().value(value)?; + + self.record.entries.push((label, value)); + + Ok(()) + } + + fn value_computed( + &mut self, + _: Option, + label: sval::Label, + value: V, + ) -> Result { + let label = owned_label(label)?; + let value = ToValue::default().value_computed(value)?; + + self.record.entries.push((label, value)); + + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Record(self.record)) + } + } + + impl<'sval> StreamEnum<'sval> for ToEnum<'sval> { + type Ok = Value<'sval>; + + type Tuple = ToVariant>; + type Record = ToVariant>; + type Nested = Self; + + fn tag( + self, + tag: Option, + label: Option, + index: Option, + ) -> Result { + let tag = Tag::new(tag, label, index)?; + + Ok(Value::Enum(Enum { + tag: self.tag, + variant: Some(Variant::Tag(tag)), + })) + } + + fn tagged_computed( + self, + tag: Option, + label: Option, + index: Option, + value: V, + ) -> Result { + let tag = Tag::new(tag, label, index)?; + let value = ToValue::default().value_computed(value)?; + + Ok(Value::Enum(Enum { + tag: self.tag, + variant: Some(Variant::Tagged(Tagged { + tag, + value: Box::new(value), + })), + })) + } + + fn tuple_begin( + self, + tag: Option, + label: Option, + index: Option, + _: Option, + ) -> Result { + Ok(ToVariant { + tag: self.tag, + stream: ToTuple { + tuple: Tuple { + tag: Tag::new(tag, label, index)?, + entries: Vec::new(), + }, + }, + }) + } + + fn record_begin( + self, + tag: Option, + label: Option, + index: Option, + _: Option, + ) -> Result { + Ok(ToVariant { + tag: self.tag, + stream: ToRecord { + record: Record { + tag: Tag::new(tag, label, index)?, + entries: Vec::new(), + }, + }, + }) + } + + fn nested Result<>::Ok>>( + self, + tag: Option, + label: Option, + index: Option, + variant: F, + ) -> Result { + let variant = variant(ToEnum { + tag: Tag::new(tag, label, index)?, + _marker: PhantomData, + })? + .try_into_variant()?; + + Ok(Value::Enum(Enum { + tag: self.tag, + variant: Some(variant), + })) + } + + fn empty(self) -> Result { + Ok(Value::Enum(Enum { + tag: self.tag, + variant: None, + })) + } + } + + impl<'sval> StreamTuple<'sval> for ToVariant> { + type Ok = Value<'sval>; + + fn value>( + &mut self, + tag: Option, + index: sval::Index, + value: V, + ) -> Result { + self.stream.value(tag, index, value) + } + + fn value_computed( + &mut self, + tag: Option, + index: sval::Index, + value: V, + ) -> Result { + self.stream.value_computed(tag, index, value) + } + + fn end(self) -> Result { + Ok(Value::Enum(Enum { + tag: self.tag, + variant: Some(Variant::Tuple(self.stream.tuple)), + })) + } + } + + impl<'sval> StreamRecord<'sval> for ToVariant> { + type Ok = Value<'sval>; + + fn value>( + &mut self, + tag: Option, + label: sval::Label, + value: V, + ) -> Result { + self.stream.value(tag, label, value) + } + + fn value_computed( + &mut self, + tag: Option, + label: sval::Label, + value: V, + ) -> Result { + self.stream.value_computed(tag, label, value) + } + + fn end(self) -> Result { + Ok(Value::Enum(Enum { + tag: self.tag, + variant: Some(Variant::Record(self.stream.record)), + })) + } + } +} diff --git a/ref/src/lib.rs b/ref/src/lib.rs index 3f618c02..23a12959 100644 --- a/ref/src/lib.rs +++ b/ref/src/lib.rs @@ -36,8 +36,131 @@ pub fn stream_ref<'sval>( value.stream_ref(stream) } +/** +Wrap an [`sval::Value`] in a [`ValueRef`] +*/ +pub fn to_ref<'sval, V: sval::Value + ?Sized>(value: &'sval V) -> Ref<&'sval V> { + Ref::new(value) +} + use sval::{Result, Stream, Value}; +/** +Adapt an [`sval::Value`] into a [`ValueRef`]. +*/ +#[repr(transparent)] +#[derive(Debug, Clone, Copy)] +pub struct Ref(V); + +impl Ref { + /** + Wrap a value. + */ + pub fn new(value: V) -> Self { + Ref(value) + } + + /** + Get a reference to the underlying value. + */ + pub fn inner(&self) -> &V { + &self.0 + } + + /** + Take ownership of the underlying value. + */ + pub fn into_inner(self) -> V { + self.0 + } +} + +impl Ref { + /** + Get a borrowed wrapper over a borrowed value. + */ + pub fn new_borrowed<'a>(value: &'a V) -> &'a Ref { + // SAFETY: `&'a V` and `&'a Ref` have the same ABI + unsafe { &*(value as *const _ as *const Ref) } + } +} + +impl sval::Value for Ref { + fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result { + self.0.stream(stream) + } + + fn tag(&self) -> Option { + self.0.tag() + } + + fn to_bool(&self) -> Option { + self.0.to_bool() + } + + fn to_f32(&self) -> Option { + self.0.to_f32() + } + + fn to_f64(&self) -> Option { + self.0.to_f64() + } + + fn to_i8(&self) -> Option { + self.0.to_i8() + } + + fn to_i16(&self) -> Option { + self.0.to_i16() + } + + fn to_i32(&self) -> Option { + self.0.to_i32() + } + + fn to_i64(&self) -> Option { + self.0.to_i64() + } + + fn to_i128(&self) -> Option { + self.0.to_i128() + } + + fn to_u8(&self) -> Option { + self.0.to_u8() + } + + fn to_u16(&self) -> Option { + self.0.to_u16() + } + + fn to_u32(&self) -> Option { + self.0.to_u32() + } + + fn to_u64(&self) -> Option { + self.0.to_u64() + } + + fn to_u128(&self) -> Option { + self.0.to_u128() + } + + fn to_text(&self) -> Option<&str> { + self.0.to_text() + } + + fn to_binary(&self) -> Option<&[u8]> { + self.0.to_binary() + } +} + +impl<'sval, V: sval::Value + ?Sized> ValueRef<'sval> for Ref<&'sval V> { + fn stream_ref + ?Sized>(&self, stream: &mut S) -> Result { + self.0.stream(stream) + } +} + /** A producer of structured data that stores a reference internally. diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 10dd419a..93a4cb55 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -15,22 +15,18 @@ categories = ["encoding", "no-std"] features = ["std"] [features] -std = ["alloc", "serde/std", "sval/std", "sval_buffer/std"] -alloc = ["serde/alloc", "sval/alloc", "sval_buffer/alloc"] +std = ["alloc", "serde/std", "sval/std", "sval_nested/std"] +alloc = ["serde/alloc", "sval/alloc", "sval_nested/alloc"] [dependencies.sval] version = "2.10.2" path = "../" -[dependencies.sval_buffer] +[dependencies.sval_nested] version = "2.10.2" -path = "../buffer" +path = "../nested" default-features = false -[dependencies.sval_fmt] -version = "2.10.2" -path = "../fmt" - [dependencies.serde] version = "1" default-features = false diff --git a/serde/src/to_serialize.rs b/serde/src/to_serialize.rs index dc442581..c12d9e12 100644 --- a/serde/src/to_serialize.rs +++ b/serde/src/to_serialize.rs @@ -1,13 +1,9 @@ -use core::mem; +use serde::ser::{Error as _, Serialize as _}; -use serde::ser::{ - Error as _, Serialize as _, SerializeMap as _, SerializeSeq as _, SerializeStruct as _, - SerializeStructVariant as _, SerializeTuple as _, SerializeTupleStruct as _, - SerializeTupleVariant as _, +use sval_nested::{ + Stream, StreamEnum, StreamMap, StreamRecord, StreamSeq, StreamTuple, Unsupported, }; -use sval_buffer::{BinaryBuf, TextBuf, ValueBuf}; - /** Serialize an [`sval::Value`] into a [`serde::Serializer`]. */ @@ -45,955 +41,633 @@ impl ToSerialize { impl serde::Serialize for ToSerialize { fn serialize(&self, serializer: S) -> Result { - let mut stream = Serializer { - buffered: None, - state: State::Any(Some(Any { - serializer, - is_option: false, - struct_label: None, - variant_label: None, - variant_index: None, - })), - }; - - let _ = self.0.stream(&mut stream); - - stream.finish() + Serializer::new(serializer) + .value_computed(&self.0) + .unwrap_or_else(|e| Err(S::Error::custom(e))) } } -struct Serializer<'sval, S: serde::Serializer> { - buffered: Option>, - state: State, +struct Serializer { + serializer: S, } -impl<'sval, S: serde::Serializer> sval::Stream<'sval> for Serializer<'sval, S> { - fn value(&mut self, value: &'sval V) -> sval::Result { - self.buffer_or_value(|buf| buf.value(value), || ToSerialize(value)) - } - - fn value_computed(&mut self, value: &V) -> sval::Result { - self.buffer_or_value(|buf| buf.value_computed(value), || ToSerialize(value)) - } - - fn null(&mut self) -> sval::Result { - self.buffer_or_value(|buf| buf.null(), || None::<()>) - } +struct SerializeSeq { + serializer: Result, +} - fn bool(&mut self, value: bool) -> sval::Result { - self.buffer_or_value(|buf| buf.bool(value), || value) - } +struct SerializeMap { + serializer: Result, +} - fn u8(&mut self, value: u8) -> sval::Result { - self.buffer_or_value(|buf| buf.u8(value), || value) - } +struct SerializeTuple { + serializer: Result, E>, +} - fn u16(&mut self, value: u16) -> sval::Result { - self.buffer_or_value(|buf| buf.u16(value), || value) - } +enum MaybeNamed { + Named { serializer: TNamed }, + Unnamed { serializer: TUnnamed }, +} - fn u32(&mut self, value: u32) -> sval::Result { - self.buffer_or_value(|buf| buf.u32(value), || value) - } +struct SerializeRecord { + serializer: Result, E>, +} - fn u64(&mut self, value: u64) -> sval::Result { - self.buffer_or_value(|buf| buf.u64(value), || value) - } +struct SerializeEnum { + name: &'static str, + serializer: S, +} - fn u128(&mut self, value: u128) -> sval::Result { - self.buffer_or_value(|buf| buf.u128(value), || value) - } +struct SerializeRecordVariant { + serializer: Result, +} - fn i8(&mut self, value: i8) -> sval::Result { - self.buffer_or_value(|buf| buf.i8(value), || value) - } +struct SerializeTupleVariant { + serializer: Result, +} - fn i16(&mut self, value: i16) -> sval::Result { - self.buffer_or_value(|buf| buf.i16(value), || value) +impl Serializer { + fn new(serializer: S) -> Self { + Serializer { serializer } } +} - fn i32(&mut self, value: i32) -> sval::Result { - self.buffer_or_value(|buf| buf.i32(value), || value) - } +impl<'sval, S: serde::Serializer> Stream<'sval> for Serializer { + type Ok = Result; - fn i64(&mut self, value: i64) -> sval::Result { - self.buffer_or_value(|buf| buf.i64(value), || value) - } + type Seq = SerializeSeq; - fn i128(&mut self, value: i128) -> sval::Result { - self.buffer_or_value(|buf| buf.i128(value), || value) - } + type Map = SerializeMap; - fn f32(&mut self, value: f32) -> sval::Result { - self.buffer_or_value(|buf| buf.f32(value), || value) - } + type Tuple = SerializeTuple; - fn f64(&mut self, value: f64) -> sval::Result { - self.buffer_or_value(|buf| buf.f64(value), || value) - } + type Record = SerializeRecord; - fn text_begin(&mut self, size_hint: Option) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.text_begin(size_hint), - |serializer| serializer.put_buffer(Buffered::Text(TextBuf::new())), - ) - } + type Enum = SerializeEnum; - fn text_fragment(&mut self, fragment: &'sval str) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.text_fragment(fragment), - |serializer| serializer.with_text(|text| text.push_fragment(fragment)), - ) + fn null(self) -> sval_nested::Result { + Ok(self.serializer.serialize_none()) } - fn text_fragment_computed(&mut self, fragment: &str) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.text_fragment_computed(fragment), - |serializer| serializer.with_text(|text| text.push_fragment_computed(fragment)), - ) + fn bool(self, value: bool) -> sval_nested::Result { + Ok(self.serializer.serialize_bool(value)) } - fn text_end(&mut self) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.text_end(), - |serializer| { - let buf = serializer.take_text()?; - - serializer.state.serialize_value(buf.as_str()) - }, - ) + fn i8(self, value: i8) -> sval_nested::Result { + Ok(self.serializer.serialize_i8(value)) } - fn binary_begin(&mut self, size_hint: Option) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.binary_begin(size_hint), - |serializer| serializer.put_buffer(Buffered::Binary(BinaryBuf::new())), - ) + fn i16(self, value: i16) -> sval_nested::Result { + Ok(self.serializer.serialize_i16(value)) } - fn binary_fragment(&mut self, fragment: &'sval [u8]) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.binary_fragment(fragment), - |serializer| serializer.with_binary(|binary| binary.push_fragment(fragment)), - ) + fn i32(self, value: i32) -> sval_nested::Result { + Ok(self.serializer.serialize_i32(value)) } - fn binary_fragment_computed(&mut self, fragment: &[u8]) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.binary_fragment_computed(fragment), - |serializer| serializer.with_binary(|binary| binary.push_fragment_computed(fragment)), - ) + fn i64(self, value: i64) -> sval_nested::Result { + Ok(self.serializer.serialize_i64(value)) } - fn binary_end(&mut self) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.binary_end(), - |serializer| { - let buf = serializer.take_binary()?; - - serializer.state.serialize_value(Bytes(buf.as_slice())) - }, - ) + fn i128(self, value: i128) -> sval_nested::Result { + Ok(self.serializer.serialize_i128(value)) } - fn map_begin(&mut self, num_entries_hint: Option) -> sval::Result { - self.buffer_or_transition_any_with( - |buf| buf.map_begin(num_entries_hint), - |serializer| { - Ok(State::Map(Some(Map { - serializer: serializer.serializer.serialize_map(num_entries_hint)?, - is_key: true, - }))) - }, - ) + fn u8(self, value: u8) -> sval_nested::Result { + Ok(self.serializer.serialize_u8(value)) } - fn map_key_begin(&mut self) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.map_key_begin(), - |serializer| { - serializer.with_map(|serializer| { - serializer.is_key = true; - - Ok(()) - }) - }, - ) + fn u16(self, value: u16) -> sval_nested::Result { + Ok(self.serializer.serialize_u16(value)) } - fn map_key_end(&mut self) -> sval::Result { - self.buffer_or_serialize_with(|buf| buf.map_key_end(), |_| Ok(())) + fn u32(self, value: u32) -> sval_nested::Result { + Ok(self.serializer.serialize_u32(value)) } - fn map_value_begin(&mut self) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.map_value_begin(), - |serializer| { - serializer.with_map(|serializer| { - serializer.is_key = false; - - Ok(()) - }) - }, - ) + fn u64(self, value: u64) -> sval_nested::Result { + Ok(self.serializer.serialize_u64(value)) } - fn map_value_end(&mut self) -> sval::Result { - self.buffer_or_serialize_with(|buf| buf.map_value_end(), |_| Ok(())) + fn u128(self, value: u128) -> sval_nested::Result { + Ok(self.serializer.serialize_u128(value)) } - fn map_end(&mut self) -> sval::Result { - self.buffer_or_transition_done_with( - |buf| buf.map_end(), - |serializer| serializer.take_map()?.serializer.end(), - ) + fn f32(self, value: f32) -> sval_nested::Result { + Ok(self.serializer.serialize_f32(value)) } - fn seq_begin(&mut self, num_entries_hint: Option) -> sval::Result { - self.buffer_or_transition_any_with( - |buf| buf.seq_begin(num_entries_hint), - |serializer| { - Ok(State::Seq(Some(Seq { - serializer: serializer.serializer.serialize_seq(num_entries_hint)?, - }))) - }, - ) + fn f64(self, value: f64) -> sval_nested::Result { + Ok(self.serializer.serialize_f64(value)) } - fn seq_value_begin(&mut self) -> sval::Result { - self.buffer_or_serialize_with(|buf| buf.seq_value_begin(), |_| Ok(())) + fn text_computed(self, text: &str) -> sval_nested::Result { + Ok(self.serializer.serialize_str(text)) } - fn seq_value_end(&mut self) -> sval::Result { - self.buffer_or_serialize_with(|buf| buf.seq_value_begin(), |_| Ok(())) + fn binary_computed(self, binary: &[u8]) -> sval_nested::Result { + Ok(self.serializer.serialize_bytes(binary)) } - fn seq_end(&mut self) -> sval::Result { - self.buffer_or_transition_done_with( - |buf| buf.seq_end(), - |serializer| serializer.take_seq()?.serializer.end(), - ) + fn tag( + self, + tag: Option, + label: Option, + _: Option, + ) -> sval_nested::Result { + match tag { + Some(sval::tags::RUST_OPTION_NONE) => Ok(self.serializer.serialize_none()), + Some(sval::tags::RUST_UNIT) => Ok(self.serializer.serialize_unit()), + _ => { + let name = label + .and_then(|label| label.as_static_str()) + .ok_or_else(|| sval_nested::Error::invalid_value("unit label must be static"))?; + + Ok(self.serializer.serialize_unit_struct(name)) + } + } } - fn enum_begin( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - self.buffer_or_transition_any_with( - |buf| buf.enum_begin(tag, label, index), - |mut serializer| { - serializer.struct_label = label.and_then(|label| label.as_static_str()); - - Ok(State::Any(Some(serializer))) - }, - ) - } + fn tagged_computed( + self, + tag: Option, + label: Option, + _: Option, + value: V, + ) -> sval_nested::Result { + match tag { + Some(sval::tags::RUST_OPTION_SOME) => { + Ok(self.serializer.serialize_some(&ToSerialize::new(value))) + } + _ => { + let name = label + .and_then(|label| label.as_static_str()) + .ok_or_else(|| sval_nested::Error::invalid_value("newtype label must be static"))?; - fn enum_end( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - self.buffer_or_transition_done_with( - |buf| buf.enum_end(tag, label, index), - |serializer| serializer.finish(), - ) + Ok(self + .serializer + .serialize_newtype_struct(name, &ToSerialize::new(value))) + } + } } - fn tagged_begin( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - self.buffer_or_transition_any_with( - |buf| buf.tagged_begin(tag, label, index), - |mut serializer| { - match tag { - Some(&sval::tags::RUST_OPTION_SOME) => { - serializer.is_option = true; - } - _ => { - if serializer.struct_label.is_none() { - serializer.struct_label = label.and_then(|label| label.as_static_str()); - } else { - serializer.variant_label = - label.and_then(|label| label.as_static_str()); - serializer.variant_index = index.and_then(|index| index.to_u32()); - } - } - } - - Ok(State::Any(Some(serializer))) - }, - ) + fn seq_begin(self, num_entries: Option) -> sval_nested::Result { + Ok(SerializeSeq { + serializer: self.serializer.serialize_seq(num_entries), + }) } - fn tagged_end( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - self.buffer_or_transition_done_with( - |buf| buf.tagged_end(tag, label, index), - |serializer| serializer.finish(), - ) + fn map_begin(self, num_entries: Option) -> sval_nested::Result { + Ok(SerializeMap { + serializer: self.serializer.serialize_map(num_entries), + }) } - fn tag( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - match tag { - Some(&sval::tags::RUST_OPTION_NONE) => { - self.buffer_or_value(|buf| buf.tag(tag, label, index), || None::<()>) - } - Some(&sval::tags::RUST_UNIT) => { - self.buffer_or_value(|buf| buf.tag(tag, label, index), || ()) + fn tuple_begin( + self, + _: Option, + label: Option, + _: Option, + num_entries: Option, + ) -> sval_nested::Result { + let len = + num_entries.ok_or_else(|| sval_nested::Error::invalid_value("missing tuple len"))?; + + match label { + Some(label) => { + let name = label + .as_static_str() + .ok_or_else(|| sval_nested::Error::invalid_value("tuple label must be static"))?; + + Ok(SerializeTuple { + serializer: self + .serializer + .serialize_tuple_struct(name, len) + .map(|serializer| MaybeNamed::Named { serializer }), + }) } - _ => self.buffer_or_transition_any_with( - |buf| buf.tag(tag, label, index), - |serializer| { - let unit_label = label - .and_then(|label| label.as_static_str()) - .ok_or_else(|| S::Error::custom("missing unit label"))?; - - let r = if let Some(struct_label) = serializer.struct_label { - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| S::Error::custom("missing variant index"))?; - - serializer.serializer.serialize_unit_variant( - struct_label, - variant_index, - unit_label, - ) - } else { - serializer.serializer.serialize_unit_struct(unit_label) - }; - - Ok(State::Done(Some(r))) - }, - ), + None => Ok(SerializeTuple { + serializer: self + .serializer + .serialize_tuple(len) + .map(|serializer| MaybeNamed::Unnamed { serializer }), + }), } } fn record_begin( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, + self, + _: Option, + label: Option, + _: Option, num_entries: Option, - ) -> sval::Result { - self.buffer_or_transition_any_with( - |buf| buf.record_begin(tag, label, index, num_entries), - |serializer| { - let record_label = label.and_then(|label| label.as_static_str()); - - let num_entries = - num_entries.ok_or_else(|| S::Error::custom("missing struct field count"))?; - - match (serializer.struct_label, record_label) { - (Some(struct_label), Some(variant_label)) => { - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| S::Error::custom("missing variant index"))?; - - Ok(State::Record(Some(Record::Variant(VariantRecord { - serializer: serializer.serializer.serialize_struct_variant( - struct_label, - variant_index, - variant_label, - num_entries, - )?, - label: None, - })))) - } - (None, Some(struct_label)) | (Some(struct_label), None) => { - Ok(State::Record(Some(Record::Struct(StructRecord { - serializer: serializer - .serializer - .serialize_struct(struct_label, num_entries)?, - label: None, - })))) - } - (None, None) => Ok(State::Record(Some(Record::Anonymous(AnonymousRecord { - serializer: serializer.serializer.serialize_map(Some(num_entries))?, - })))), - } - }, - ) - } - - fn record_value_begin(&mut self, tag: Option<&sval::Tag>, label: &sval::Label) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.record_value_begin(tag, label), - |serializer| { - serializer.with_record(|serializer| match serializer { - Record::Anonymous(serializer) => { - serializer.serializer.serialize_key(label.as_str())?; - - Ok(()) - } - Record::Struct(serializer) => { - serializer.label = label.as_static_str(); - - Ok(()) - } - Record::Variant(serializer) => { - serializer.label = label.as_static_str(); - - Ok(()) - } + ) -> sval_nested::Result { + let len = + num_entries.ok_or_else(|| sval_nested::Error::invalid_value("missing struct len"))?; + + match label { + Some(label) => { + let name = label + .as_static_str() + .ok_or_else(|| sval_nested::Error::invalid_value("struct label must be static"))?; + + Ok(SerializeRecord { + serializer: self + .serializer + .serialize_struct(name, len) + .map(|serializer| MaybeNamed::Named { serializer }), }) - }, - ) + } + None => Ok(SerializeRecord { + serializer: self + .serializer + .serialize_tuple(len) + .map(|serializer| MaybeNamed::Unnamed { serializer }), + }), + } } - fn record_value_end(&mut self, tag: Option<&sval::Tag>, label: &sval::Label) -> sval::Result { - self.buffer_or_serialize_with( - |buf| buf.record_value_end(tag, label), - |serializer| { - serializer.with_record(|serializer| match serializer { - Record::Anonymous(_) => Ok(()), - Record::Struct(serializer) => { - serializer.label = None; - - Ok(()) - } - Record::Variant(serializer) => { - serializer.label = None; - - Ok(()) - } - }) - }, - ) + fn enum_begin( + self, + _: Option, + label: Option, + _: Option, + ) -> sval_nested::Result { + let name = label + .and_then(|label| label.as_static_str()) + .ok_or_else(|| sval_nested::Error::invalid_value("enum label must be static"))?; + + Ok(SerializeEnum { + name, + serializer: self.serializer, + }) } +} - fn record_end( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - self.buffer_or_transition_done_with( - |buf| buf.record_end(tag, label, index), - |serializer| match serializer.take_record()? { - Record::Anonymous(serializer) => serializer.serializer.end(), - Record::Struct(serializer) => serializer.serializer.end(), - Record::Variant(serializer) => serializer.serializer.end(), - }, - ) - } +impl<'sval, S: serde::ser::SerializeSeq> StreamSeq<'sval> for SerializeSeq { + type Ok = Result; - fn tuple_begin( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - num_entries: Option, - ) -> sval::Result { - self.buffer_or_transition_any_with( - |buf| buf.tuple_begin(tag, label, index, num_entries), - |serializer| { - let tuple_label = label.and_then(|label| label.as_static_str()); - - let num_entries = - num_entries.ok_or_else(|| S::Error::custom("missing tuple field count"))?; - - match (serializer.struct_label, tuple_label) { - (Some(struct_label), Some(variant_label)) => { - let variant_index = index - .and_then(|index| index.to_u32()) - .ok_or_else(|| S::Error::custom("missing variant index"))?; - - Ok(State::Tuple(Some(Tuple::Variant(VariantTuple { - serializer: serializer.serializer.serialize_tuple_variant( - struct_label, - variant_index, - variant_label, - num_entries, - )?, - })))) - } - (None, Some(struct_label)) | (Some(struct_label), None) => { - Ok(State::Tuple(Some(Tuple::Struct(StructTuple { - serializer: serializer - .serializer - .serialize_tuple_struct(struct_label, num_entries)?, - })))) - } - (None, None) => Ok(State::Tuple(Some(Tuple::Anonymous(AnonymousTuple { - serializer: serializer.serializer.serialize_tuple(num_entries)?, - })))), + fn value_computed(&mut self, value: V) -> sval_nested::Result { + if let Ok(ref mut serializer) = self.serializer { + match serializer.serialize_element(&ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); } - }, - ) - } - - fn tuple_value_begin(&mut self, tag: Option<&sval::Tag>, index: &sval::Index) -> sval::Result { - self.buffer_or_serialize_with(|buf| buf.tuple_value_begin(tag, index), |_| Ok(())) - } + } + } - fn tuple_value_end(&mut self, tag: Option<&sval::Tag>, index: &sval::Index) -> sval::Result { - self.buffer_or_serialize_with(|buf| buf.tuple_value_end(tag, index), |_| Ok(())) + Err(sval_nested::Error::invalid_value( + "failed to serialize sequence element", + )) } - fn tuple_end( - &mut self, - tag: Option<&sval::Tag>, - label: Option<&sval::Label>, - index: Option<&sval::Index>, - ) -> sval::Result { - self.buffer_or_transition_done_with( - |buf| buf.tuple_end(tag, label, index), - |serializer| match serializer.take_tuple()? { - Tuple::Anonymous(serializer) => serializer.serializer.end(), - Tuple::Struct(serializer) => serializer.serializer.end(), - Tuple::Variant(serializer) => serializer.serializer.end(), - }, - ) + fn end(self) -> sval_nested::Result { + match self.serializer { + Ok(serializer) => Ok(serializer.end()), + Err(err) => Ok(Err(err)), + } } } -impl State { - fn serialize_value(&mut self, v: T) -> sval::Result { - let mut r = || match self { - State::Any(serializer) => { - let serializer = serializer - .take() - .ok_or_else(|| S::Error::custom("missing serializer"))?; - - let r = match serializer { - Any { - is_option: true, - serializer, - .. - } => serializer.serialize_some(&v), - Any { - struct_label: Some(struct_label), - variant_label: None, - variant_index: None, - is_option: false, - serializer, - } => serializer.serialize_newtype_struct(struct_label, &v), - Any { - struct_label: Some(struct_label), - variant_label: Some(variant_label), - variant_index: Some(variant_index), - is_option: false, - serializer, - } => serializer.serialize_newtype_variant( - struct_label, - variant_index, - variant_label, - &v, - ), - Any { serializer, .. } => v.serialize(serializer), - }; - - match r { - Ok(r) => Ok(Some(r)), - Err(e) => Err(e), - } - } - State::Map(serializer) => { - let serializer = serializer - .as_mut() - .ok_or_else(|| S::Error::custom("missing serializer"))?; - - if serializer.is_key { - serializer.serializer.serialize_key(&v)?; - - Ok(None) - } else { - serializer.serializer.serialize_value(&v)?; +impl<'sval, S: serde::ser::SerializeMap> StreamMap<'sval> for SerializeMap { + type Ok = Result; - Ok(None) + fn key_computed(&mut self, key: V) -> sval_nested::Result { + if let Ok(ref mut serializer) = self.serializer { + match serializer.serialize_key(&ToSerialize::new(key)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); } } - State::Seq(serializer) => { - serializer - .as_mut() - .ok_or_else(|| S::Error::custom("missing serializer"))? - .serializer - .serialize_element(&v)?; + } - Ok(None) - } - State::Record(serializer) => { - let serializer = serializer - .as_mut() - .ok_or_else(|| S::Error::custom("missing serializer"))?; - - match serializer { - Record::Anonymous(serializer) => { - serializer.serializer.serialize_value(&v)?; - } - Record::Struct(serializer) => serializer.serializer.serialize_field( - serializer - .label - .ok_or_else(|| S::Error::custom("missing field label"))?, - &v, - )?, - Record::Variant(serializer) => serializer.serializer.serialize_field( - serializer - .label - .ok_or_else(|| S::Error::custom("missing field label"))?, - &v, - )?, - } + Err(sval_nested::Error::invalid_value( + "failed to serialize map key", + )) + } - Ok(None) - } - State::Tuple(serializer) => { - let serializer = serializer - .as_mut() - .ok_or_else(|| S::Error::custom("missing serializer"))?; - - match serializer { - Tuple::Anonymous(serializer) => serializer.serializer.serialize_element(&v)?, - Tuple::Struct(serializer) => serializer.serializer.serialize_field(&v)?, - Tuple::Variant(serializer) => serializer.serializer.serialize_field(&v)?, + fn value_computed(&mut self, value: V) -> sval_nested::Result { + if let Ok(ref mut serializer) = self.serializer { + match serializer.serialize_value(&ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); } - - Ok(None) - } - State::Done(_) => Err(S::Error::custom("already completed")), - }; - - match r() { - Ok(Some(r)) => { - *self = State::Done(Some(Ok(r))); - Ok(()) - } - Ok(None) => Ok(()), - Err(e) => { - *self = State::Done(Some(Err(e))); - Err(sval::Error::new()) } } - } -} -fn try_catch<'sval, T, S: serde::Serializer>( - serializer: &mut Serializer<'sval, S>, - f: impl FnOnce(&mut Serializer<'sval, S>) -> Result, -) -> sval::Result { - match f(serializer) { - Ok(v) => Ok(v), - Err(e) => { - serializer.state = State::Done(Some(Err(e))); + Err(sval_nested::Error::invalid_value( + "failed to serialize map value", + )) + } - sval::error() + fn end(self) -> sval_nested::Result { + match self.serializer { + Ok(serializer) => Ok(serializer.end()), + Err(err) => Ok(Err(err)), } } } -impl<'sval, S: serde::Serializer> Serializer<'sval, S> { - fn buffer_or_serialize_with( +impl< + 'sval, + TOk, + TError, + TNamed: serde::ser::SerializeStruct, + TUnnamed: serde::ser::SerializeTuple, + > StreamRecord<'sval> for SerializeRecord +{ + type Ok = Result; + + fn value_computed( &mut self, - buffer: impl FnOnce(&mut sval_buffer::ValueBuf<'sval>) -> sval::Result, - stream: impl FnOnce(&mut Self) -> sval::Result, - ) -> sval::Result { - match self { - Serializer { - buffered: Some(Buffered::Value(ref mut buf)), - .. - } => buffer(buf), - serializer => stream(serializer), + _: Option, + label: sval::Label, + value: V, + ) -> sval_nested::Result { + match self.serializer { + Ok(MaybeNamed::Named { ref mut serializer }) => { + let field = label.as_static_str().ok_or_else(|| { + sval_nested::Error::invalid_value("struct field label must be static") + })?; + + match serializer.serialize_field(field, &ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); + } + } + } + Ok(MaybeNamed::Unnamed { ref mut serializer }) => { + match serializer.serialize_element(&ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); + } + } + } + Err(_) => (), } - } - fn buffer_or_value( - &mut self, - buffer: impl FnOnce(&mut sval_buffer::ValueBuf<'sval>) -> sval::Result, - value: impl FnOnce() -> T, - ) -> sval::Result { - self.buffer_or_serialize_with(buffer, |stream| stream.state.serialize_value(value())) + Err(sval_nested::Error::invalid_value( + "failed to serialize tuple field", + )) } - fn put_buffer(&mut self, buf: Buffered<'sval>) -> sval::Result { - try_catch(self, |serializer| match serializer.buffered { - None => { - serializer.buffered = Some(buf); - - Ok(()) - } - Some(_) => Err(S::Error::custom("a buffer is already active")), - }) + fn end(self) -> sval_nested::Result { + match self.serializer { + Ok(MaybeNamed::Named { serializer }) => Ok(serializer.end()), + Ok(MaybeNamed::Unnamed { serializer }) => Ok(serializer.end()), + Err(e) => Ok(Err(e)), + } } +} - fn buffer_or_transition_any_with( +impl< + 'sval, + TOk, + TError, + TNamed: serde::ser::SerializeTupleStruct, + TUnnamed: serde::ser::SerializeTuple, + > StreamTuple<'sval> for SerializeTuple +{ + type Ok = Result; + + fn value_computed( &mut self, - mut buffer: impl FnMut(&mut sval_buffer::ValueBuf<'sval>) -> sval::Result, - transition: impl FnOnce(Any) -> Result, S::Error>, - ) -> sval::Result { - let buf = try_catch(self, |serializer| { - match serializer { - Serializer { - buffered: Some(Buffered::Value(ref mut buf)), - .. - } => { - buffer(buf).map_err(|_| S::Error::custom("failed to buffer a value"))?; - - return Ok(None); - } - Serializer { - buffered: None, - state: State::Any(any), - } => { - if let Ok(state) = transition( - any.take() - .ok_or_else(|| S::Error::custom("missing serializer"))?, - ) { - serializer.state = state; - - return Ok(None); + _: Option, + _: sval::Index, + value: V, + ) -> sval_nested::Result { + match self.serializer { + Ok(MaybeNamed::Named { ref mut serializer }) => { + match serializer.serialize_field(&ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); } } - _ => return Err(S::Error::custom("invalid serializer state")), } - - let mut value = ValueBuf::new(); - buffer(&mut value).map_err(|_| S::Error::custom("failed to buffer a value"))?; - - Ok(Some(Buffered::Value(value))) - })?; - - self.buffered = buf; - - Ok(()) - } - - fn buffer_or_transition_done_with( - &mut self, - buffer: impl FnOnce(&mut sval_buffer::ValueBuf<'sval>) -> sval::Result, - transition: impl FnOnce(&mut Serializer) -> Result, - ) -> sval::Result { - let r = try_catch(self, |serializer| match serializer { - Serializer { - buffered: Some(Buffered::Value(ref mut buf)), - .. - } => { - buffer(buf).map_err(|_| S::Error::custom("failed to buffer a value"))?; - - if buf.is_complete() { - // Errors handled internally by `serialize_value` - let _ = serializer.state.serialize_value(ToSerialize(&*buf)); - serializer.buffered = None; + Ok(MaybeNamed::Unnamed { ref mut serializer }) => { + match serializer.serialize_element(&ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); + } } - - return Ok(None); } - Serializer { buffered: None, .. } => Ok(Some(transition(serializer)?)), - _ => return Err(S::Error::custom("invalid serializer state")), - })?; - - if let Some(r) = r { - self.state = State::Done(Some(Ok(r))); + Err(_) => (), } - Ok(()) + Err(sval_nested::Error::invalid_value( + "failed to serialize tuple field", + )) } - fn with_map(&mut self, f: impl FnOnce(&mut Map) -> Result<(), S::Error>) -> sval::Result { - try_catch(self, |serializer| match serializer { - Serializer { - buffered: None, - state: State::Map(Some(map)), - } => f(map), - _ => Err(S::Error::custom("invalid serializer state")), - }) - } - - fn take_map(&mut self) -> Result, S::Error> { - match self { - Serializer { - buffered: None, - state: State::Map(map), - } => map - .take() - .ok_or_else(|| S::Error::custom("invalid serializer state")), - _ => Err(S::Error::custom("invalid serializer state")), + fn end(self) -> sval_nested::Result { + match self.serializer { + Ok(MaybeNamed::Named { serializer }) => Ok(serializer.end()), + Ok(MaybeNamed::Unnamed { serializer }) => Ok(serializer.end()), + Err(e) => Ok(Err(e)), } } +} - fn take_seq(&mut self) -> Result, S::Error> { - match self { - Serializer { - buffered: None, - state: State::Seq(seq), - } => seq - .take() - .ok_or_else(|| S::Error::custom("invalid serializer state")), - _ => Err(S::Error::custom("invalid serializer state")), - } - } +impl<'sval, S: serde::Serializer> StreamEnum<'sval> for SerializeEnum { + type Ok = Result; - fn with_record( - &mut self, - f: impl FnOnce(&mut Record) -> Result<(), S::Error>, - ) -> sval::Result { - try_catch(self, |serializer| match serializer { - Serializer { - buffered: None, - state: State::Record(Some(s)), - } => f(s), - _ => Err(S::Error::custom("invalid serializer state")), - }) - } + type Tuple = SerializeTupleVariant; - fn take_record(&mut self) -> Result, S::Error> { - match self { - Serializer { - buffered: None, - state: State::Record(s), - } => s - .take() - .ok_or_else(|| S::Error::custom("invalid serializer state")), - _ => Err(S::Error::custom("invalid serializer state")), - } - } + type Record = SerializeRecordVariant; - fn take_tuple(&mut self) -> Result, S::Error> { - match self { - Serializer { - buffered: None, - state: State::Tuple(s), - } => s - .take() - .ok_or_else(|| S::Error::custom("invalid serializer state")), - _ => Err(S::Error::custom("invalid serializer state")), - } - } + type Nested = Unsupported; - fn with_text( - &mut self, - f: impl FnOnce(&mut TextBuf<'sval>) -> Result<(), sval_buffer::Error>, - ) -> sval::Result { - try_catch(self, |serializer| match serializer.buffered { - Some(Buffered::Text(ref mut buf)) => f(buf).map_err(|e| S::Error::custom(e)), - _ => Err(S::Error::custom("no active text buffer")), - }) + fn tag( + self, + _: Option, + label: Option, + index: Option, + ) -> 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"))?; + + 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 + .serialize_unit_variant(self.name, variant_index, variant)) + } + + fn tagged_computed( + self, + _: Option, + label: Option, + index: Option, + value: V, + ) -> 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"))?; + + 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, + variant_index, + variant, + &ToSerialize::new(value), + )) } - fn take_text(&mut self) -> sval::Result> { - try_catch(self, |serializer| match serializer.buffered { - Some(Buffered::Text(ref mut buf)) => { - let buf = mem::take(buf); - serializer.buffered = None; - - Ok(buf) - } - _ => Err(S::Error::custom("no active text buffer")), + fn tuple_begin( + self, + _: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> 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"))?; + + 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"))?; + + Ok(SerializeTupleVariant { + serializer: self.serializer.serialize_tuple_variant( + self.name, + variant_index, + variant, + len, + ), }) } - fn with_binary( - &mut self, - f: impl FnOnce(&mut BinaryBuf<'sval>) -> Result<(), sval_buffer::Error>, - ) -> sval::Result { - try_catch(self, |serializer| match serializer.buffered { - Some(Buffered::Binary(ref mut buf)) => f(buf).map_err(|e| S::Error::custom(e)), - _ => Err(S::Error::custom("no active binary buffer")), + fn record_begin( + self, + _: Option, + label: Option, + index: Option, + num_entries: Option, + ) -> 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"))?; + + 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"))?; + + Ok(SerializeRecordVariant { + serializer: self.serializer.serialize_struct_variant( + self.name, + variant_index, + variant, + len, + ), }) } - fn take_binary(&mut self) -> sval::Result> { - try_catch(self, |serializer| match serializer.buffered { - Some(Buffered::Binary(ref mut buf)) => { - let buf = mem::take(buf); - serializer.buffered = None; - - Ok(buf) - } - _ => Err(S::Error::custom("no active binary buffer")), - }) + fn nested< + F: FnOnce(Self::Nested) -> sval_nested::Result<>::Ok>, + >( + self, + _: Option, + _: Option, + _: Option, + _: F, + ) -> sval_nested::Result { + Err(sval_nested::Error::invalid_value( + "nested enums aren't supported", + )) } - fn finish(&mut self) -> Result { - if let State::Done(ref mut r) = self.state { - r.take() - .unwrap_or_else(|| Err(S::Error::custom("incomplete serializer"))) - } else { - Err(S::Error::custom("incomplete serializer")) - } + fn empty(self) -> sval_nested::Result { + Ok(self.serializer.serialize_unit_struct(self.name)) } } -enum Buffered<'sval> { - Text(TextBuf<'sval>), - Binary(BinaryBuf<'sval>), - Value(ValueBuf<'sval>), -} - -enum State { - Any(Option>), - Map(Option>), - Seq(Option>), - Record(Option>), - Tuple(Option>), - Done(Option>), -} +impl<'sval, S: serde::ser::SerializeStructVariant> StreamRecord<'sval> + for SerializeRecordVariant +{ + type Ok = Result; -struct Any { - serializer: S, - is_option: bool, - struct_label: Option<&'static str>, - variant_label: Option<&'static str>, - variant_index: Option, -} + fn value_computed( + &mut self, + _: Option, + 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"))?; + + if let Ok(ref mut serializer) = self.serializer { + match serializer.serialize_field(field, &ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); + } + } + } -struct Map { - serializer: S::SerializeMap, - is_key: bool, -} + Err(sval_nested::Error::invalid_value( + "failed to serialize struct value", + )) + } -struct Seq { - serializer: S::SerializeSeq, + fn end(self) -> sval_nested::Result { + match self.serializer { + Ok(serializer) => Ok(serializer.end()), + Err(err) => Ok(Err(err)), + } + } } -struct AnonymousRecord { - serializer: S::SerializeMap, -} +impl<'sval, S: serde::ser::SerializeTupleVariant> StreamTuple<'sval> + for SerializeTupleVariant +{ + type Ok = Result; -struct StructRecord { - serializer: S::SerializeStruct, - label: Option<&'static str>, -} -struct VariantRecord { - serializer: S::SerializeStructVariant, - label: Option<&'static str>, -} - -enum Record { - Anonymous(AnonymousRecord), - Struct(StructRecord), - Variant(VariantRecord), -} + fn value_computed( + &mut self, + _: Option, + _: sval::Index, + value: V, + ) -> sval_nested::Result { + if let Ok(ref mut serializer) = self.serializer { + match serializer.serialize_field(&ToSerialize::new(value)) { + Ok(()) => return Ok(()), + Err(err) => { + self.serializer = Err(err); + } + } + } -struct AnonymousTuple { - serializer: S::SerializeTuple, -} -struct StructTuple { - serializer: S::SerializeTupleStruct, -} -struct VariantTuple { - serializer: S::SerializeTupleVariant, -} + Err(sval_nested::Error::invalid_value( + "failed to serialize tuple value", + )) + } -enum Tuple { - Anonymous(AnonymousTuple), - Struct(StructTuple), - Variant(VariantTuple), + fn end(self) -> sval_nested::Result { + match self.serializer { + Ok(serializer) => Ok(serializer.end()), + Err(err) => Ok(Err(err)), + } + } } struct Bytes<'sval>(&'sval [u8]); diff --git a/serde/src/to_value.rs b/serde/src/to_value.rs index 50bedb1b..be259438 100644 --- a/serde/src/to_value.rs +++ b/serde/src/to_value.rs @@ -183,7 +183,7 @@ impl<'sval, S: sval::Stream<'sval>> serde::Serializer for Stream { where T: fmt::Display, { - sval_fmt::stream_display(&mut self.stream, value) + sval::stream_display(&mut self.stream, value) .map_err(|_| Error::custom("failed to stream a string")) } diff --git a/src/data.rs b/src/data.rs index c07f0019..d4d370fe 100644 --- a/src/data.rs +++ b/src/data.rs @@ -21,9 +21,7 @@ use crate::{ #[cfg(feature = "alloc")] use crate::std::boxed::Box; -pub(crate) use self::number::*; - -pub use self::{binary::*, map::*, text::*}; +pub use self::{binary::*, map::*, number::*, option::*, text::*}; /** A textual label for some value. diff --git a/src/data/number.rs b/src/data/number.rs index 46ca4683..85fa87e9 100644 --- a/src/data/number.rs +++ b/src/data/number.rs @@ -58,9 +58,13 @@ impl_value!( to_f64 => f64, ); -fn stream_number<'sval, T: fmt::Display>( +/** +Stream an arbitrary precision number conforming to [`tags::NUMBER`] +using its [`fmt::Display`] implementation. +*/ +pub fn stream_number<'sval>( mut stream: &mut (impl Stream<'sval> + ?Sized), - text: T, + number: impl fmt::Display, ) -> Result { struct Writer(S); @@ -75,7 +79,7 @@ fn stream_number<'sval, T: fmt::Display>( stream.tagged_begin(Some(&tags::NUMBER), None, None)?; stream.text_begin(None)?; - write!(Writer(&mut stream), "{}", text).map_err(|_| crate::Error::new())?; + write!(Writer(&mut stream), "{}", number).map_err(|_| crate::Error::new())?; stream.text_end()?; stream.tagged_end(Some(&tags::NUMBER), None, None) diff --git a/src/data/option.rs b/src/data/option.rs index b2f76687..402e839b 100644 --- a/src/data/option.rs +++ b/src/data/option.rs @@ -1,5 +1,17 @@ use crate::{tags, Index, Label, Result, Stream, Value}; +/** +The absence of any meaningful value. +*/ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Null; + +impl Value for Null { + fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result { + stream.null() + } +} + impl Value for Option { fn stream<'a, S: Stream<'a> + ?Sized>(&'a self, stream: &mut S) -> Result { if let Some(some) = self { diff --git a/src/stream.rs b/src/stream.rs index 21b0ee53..a12823c3 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -8,14 +8,14 @@ pub trait Stream<'sval> { Recurse into a nested value. */ fn value(&mut self, v: &'sval V) -> Result { - v.stream(self) + default_stream::value(self, v) } /** Recurse into a nested value, borrowed for some arbitrarily short lifetime. */ fn value_computed(&mut self, v: &V) -> Result { - v.stream(Computed::new_borrowed(self)) + default_stream::value_computed(self, v) } /** @@ -38,7 +38,7 @@ pub trait Stream<'sval> { */ #[inline] fn text_fragment(&mut self, fragment: &'sval str) -> Result { - self.text_fragment_computed(fragment) + default_stream::text_fragment(self, fragment) } /** @@ -55,7 +55,7 @@ pub trait Stream<'sval> { Start a bitstring. */ fn binary_begin(&mut self, num_bytes: Option) -> Result { - self.seq_begin(num_bytes) + default_stream::binary_begin(self, num_bytes) } /** @@ -63,20 +63,14 @@ pub trait Stream<'sval> { */ #[inline] fn binary_fragment(&mut self, fragment: &'sval [u8]) -> Result { - self.binary_fragment_computed(fragment) + default_stream::binary_fragment(self, fragment) } /** Stream a fragment of a bitstring, borrowed for some arbitrarily short lifetime. */ fn binary_fragment_computed(&mut self, fragment: &[u8]) -> Result { - for byte in fragment { - self.seq_value_begin()?; - self.u8(*byte)?; - self.seq_value_end()?; - } - - Ok(()) + default_stream::binary_fragment_computed(self, fragment) } /** @@ -84,7 +78,7 @@ pub trait Stream<'sval> { */ #[inline] fn binary_end(&mut self) -> Result { - self.seq_end() + default_stream::binary_end(self) } /** @@ -92,7 +86,7 @@ pub trait Stream<'sval> { */ #[inline] fn u8(&mut self, value: u8) -> Result { - self.u16(value as u16) + default_stream::u8(self, value) } /** @@ -100,7 +94,7 @@ pub trait Stream<'sval> { */ #[inline] fn u16(&mut self, value: u16) -> Result { - self.u32(value as u32) + default_stream::u16(self, value) } /** @@ -108,7 +102,7 @@ pub trait Stream<'sval> { */ #[inline] fn u32(&mut self, value: u32) -> Result { - self.u64(value as u64) + default_stream::u32(self, value) } /** @@ -116,18 +110,14 @@ pub trait Stream<'sval> { */ #[inline] fn u64(&mut self, value: u64) -> Result { - self.u128(value as u128) + default_stream::u64(self, value) } /** Stream an unsigned 128bit integer. */ fn u128(&mut self, value: u128) -> Result { - if let Ok(value) = value.try_into() { - self.i64(value) - } else { - data::stream_u128(value, self) - } + default_stream::u128(self, value) } /** @@ -135,7 +125,7 @@ pub trait Stream<'sval> { */ #[inline] fn i8(&mut self, value: i8) -> Result { - self.i16(value as i16) + default_stream::i8(self, value) } /** @@ -143,7 +133,7 @@ pub trait Stream<'sval> { */ #[inline] fn i16(&mut self, value: i16) -> Result { - self.i32(value as i32) + default_stream::i16(self, value) } /** @@ -151,7 +141,7 @@ pub trait Stream<'sval> { */ #[inline] fn i32(&mut self, value: i32) -> Result { - self.i64(value as i64) + default_stream::i32(self, value) } /** @@ -163,11 +153,7 @@ pub trait Stream<'sval> { Stream a signed 128bit integer. */ fn i128(&mut self, value: i128) -> Result { - if let Ok(value) = value.try_into() { - self.i64(value) - } else { - data::stream_i128(value, self) - } + default_stream::i128(self, value) } /** @@ -175,7 +161,7 @@ pub trait Stream<'sval> { */ #[inline] fn f32(&mut self, value: f32) -> Result { - self.f64(value as f64) + default_stream::f32(self, value) } /** @@ -188,7 +174,7 @@ pub trait Stream<'sval> { */ #[inline] fn map_begin(&mut self, num_entries: Option) -> Result { - self.seq_begin(num_entries) + default_stream::map_begin(self, num_entries) } /** @@ -196,9 +182,7 @@ pub trait Stream<'sval> { */ #[inline] fn map_key_begin(&mut self) -> Result { - self.seq_value_begin()?; - self.tuple_begin(None, None, None, Some(2))?; - self.tuple_value_begin(None, &Index::new(0)) + default_stream::map_key_begin(self) } /** @@ -206,7 +190,7 @@ pub trait Stream<'sval> { */ #[inline] fn map_key_end(&mut self) -> Result { - self.tuple_value_end(None, &Index::new(0)) + default_stream::map_key_end(self) } /** @@ -214,7 +198,7 @@ pub trait Stream<'sval> { */ #[inline] fn map_value_begin(&mut self) -> Result { - self.tuple_value_begin(None, &Index::new(1)) + default_stream::map_value_begin(self) } /** @@ -222,9 +206,7 @@ pub trait Stream<'sval> { */ #[inline] fn map_value_end(&mut self) -> Result { - self.tuple_value_end(None, &Index::new(1))?; - self.tuple_end(None, None, None)?; - self.seq_value_end() + default_stream::map_value_end(self) } /** @@ -232,7 +214,7 @@ pub trait Stream<'sval> { */ #[inline] fn map_end(&mut self) -> Result { - self.seq_end() + default_stream::map_end(self) } /** @@ -265,7 +247,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - self.tagged_begin(tag, label, index) + default_stream::enum_begin(self, tag, label, index) } /** @@ -278,7 +260,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - self.tagged_end(tag, label, index) + default_stream::enum_end(self, tag, label, index) } /** @@ -293,11 +275,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - let _ = tag; - let _ = label; - let _ = index; - - Ok(()) + default_stream::tagged_begin(self, tag, label, index) } /** @@ -310,11 +288,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - let _ = tag; - let _ = label; - let _ = index; - - Ok(()) + default_stream::tagged_end(self, tag, label, index) } /** @@ -323,26 +297,7 @@ pub trait Stream<'sval> { Standalone tags may be used as enum variants. */ fn tag(&mut self, tag: Option<&Tag>, label: Option<&Label>, index: Option<&Index>) -> Result { - self.tagged_begin(tag, label, index)?; - - // Rust's `Option` is fundamental enough that we handle it specially here - if let Some(&tags::RUST_OPTION_NONE) = tag { - self.null()?; - } - // If the tag has a label then stream it as its value - else if let Some(ref label) = label { - if let Some(label) = label.as_static_str() { - self.value(label)?; - } else { - self.value_computed(label.as_str())?; - } - } - // If the tag doesn't have a label then stream null - else { - self.null()?; - } - - self.tagged_end(tag, label, index) + default_stream::tag(self, tag, label, index) } /** @@ -358,8 +313,7 @@ pub trait Stream<'sval> { index: Option<&Index>, num_entries: Option, ) -> Result { - self.tagged_begin(tag, label, index)?; - self.map_begin(num_entries) + default_stream::record_begin(self, tag, label, index, num_entries) } /** @@ -367,19 +321,7 @@ pub trait Stream<'sval> { */ #[inline] fn record_value_begin(&mut self, tag: Option<&Tag>, label: &Label) -> Result { - let _ = tag; - - self.map_key_begin()?; - - if let Some(label) = label.as_static_str() { - self.value(label)?; - } else { - self.value_computed(label.as_str())?; - } - - self.map_key_end()?; - - self.map_value_begin() + default_stream::record_value_begin(self, tag, label) } /** @@ -387,10 +329,7 @@ pub trait Stream<'sval> { */ #[inline] fn record_value_end(&mut self, tag: Option<&Tag>, label: &Label) -> Result { - let _ = tag; - let _ = label; - - self.map_value_end() + default_stream::record_value_end(self, tag, label) } /** @@ -403,8 +342,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - self.map_end()?; - self.tagged_end(tag, label, index) + default_stream::record_end(self, tag, label, index) } /** @@ -420,8 +358,7 @@ pub trait Stream<'sval> { index: Option<&Index>, num_entries: Option, ) -> Result { - self.tagged_begin(tag, label, index)?; - self.seq_begin(num_entries) + default_stream::tuple_begin(self, tag, label, index, num_entries) } /** @@ -429,10 +366,7 @@ pub trait Stream<'sval> { */ #[inline] fn tuple_value_begin(&mut self, tag: Option<&Tag>, index: &Index) -> Result { - let _ = tag; - let _ = index; - - self.seq_value_begin() + default_stream::tuple_value_begin(self, tag, index) } /** @@ -440,10 +374,7 @@ pub trait Stream<'sval> { */ #[inline] fn tuple_value_end(&mut self, tag: Option<&Tag>, index: &Index) -> Result { - let _ = tag; - let _ = index; - - self.seq_value_end() + default_stream::tuple_value_end(self, tag, index) } /** @@ -456,8 +387,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - self.seq_end()?; - self.tagged_end(tag, label, index) + default_stream::tuple_end(self, tag, label, index) } /** @@ -471,7 +401,7 @@ pub trait Stream<'sval> { index: Option<&Index>, num_entries: Option, ) -> Result { - self.record_begin(tag, label, index, num_entries) + default_stream::record_tuple_begin(self, tag, label, index, num_entries) } /** @@ -484,9 +414,7 @@ pub trait Stream<'sval> { label: &Label, index: &Index, ) -> Result { - let _ = index; - - self.record_value_begin(tag, label) + default_stream::record_tuple_value_begin(self, tag, label, index) } /** @@ -499,9 +427,7 @@ pub trait Stream<'sval> { label: &Label, index: &Index, ) -> Result { - let _ = index; - - self.record_value_end(tag, label) + default_stream::record_tuple_value_end(self, tag, label, index) } /** @@ -514,7 +440,7 @@ pub trait Stream<'sval> { label: Option<&Label>, index: Option<&Index>, ) -> Result { - self.record_end(tag, label, index) + default_stream::record_tuple_end(self, tag, label, index) } } @@ -841,8 +767,6 @@ mod alloc_support { /** A `Stream` that accepts values for any lifetime. - -This is the result of calling [`Stream::computed`]. */ #[repr(transparent)] struct Computed(S); @@ -1170,6 +1094,483 @@ impl<'a, 'b, S: Stream<'a> + ?Sized> Stream<'b> for Computed { } } +pub mod default_stream { + /*! + Default method implementations for [`Stream`]s. + */ + + use super::*; + + /** + Recurse into a nested value. + */ + pub fn value<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + v: &'sval (impl Value + ?Sized), + ) -> Result { + v.stream(stream) + } + + /** + Recurse into a nested value, borrowed for some arbitrarily short lifetime. + */ + pub fn value_computed<'a, 'b>( + stream: &mut (impl Stream<'a> + ?Sized), + v: &'b (impl Value + ?Sized), + ) -> Result { + v.stream(Computed::new_borrowed(stream)) + } + + /** + Stream a fragment of UTF8 text. + */ + pub fn text_fragment<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + fragment: &'sval str, + ) -> Result { + stream.text_fragment_computed(fragment) + } + + /** + Start a bitstring. + */ + pub fn binary_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + num_bytes: Option, + ) -> Result { + stream.seq_begin(num_bytes) + } + + /** + Stream a fragment of a bitstring. + */ + pub fn binary_fragment<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + fragment: &'sval [u8], + ) -> Result { + stream.binary_fragment_computed(fragment) + } + + /** + Stream a fragment of a bitstring, borrowed for some arbitrarily short lifetime. + */ + pub fn binary_fragment_computed<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + fragment: &[u8], + ) -> Result { + for byte in fragment { + stream.seq_value_begin()?; + stream.u8(*byte)?; + stream.seq_value_end()?; + } + + Ok(()) + } + + /** + Complete a bitstring. + */ + pub fn binary_end<'sval>(stream: &mut (impl Stream<'sval> + ?Sized)) -> Result { + stream.seq_end() + } + + /** + Stream an unsigned 8bit integer. + */ + pub fn u8<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: u8) -> Result { + stream.u16(value as u16) + } + + /** + Stream an unsigned 16bit integer. + */ + pub fn u16<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: u16) -> Result { + stream.u32(value as u32) + } + + /** + Stream an unsigned 32bit integer. + */ + pub fn u32<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: u32) -> Result { + stream.u64(value as u64) + } + + /** + Stream an unsigned 64bit integer. + */ + pub fn u64<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: u64) -> Result { + stream.u128(value as u128) + } + + /** + Stream an unsigned 128bit integer. + */ + pub fn u128<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: u128) -> Result { + if let Ok(value) = value.try_into() { + stream.i64(value) + } else { + data::stream_u128(value, stream) + } + } + + /** + Stream a signed 8bit integer. + */ + pub fn i8<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: i8) -> Result { + stream.i16(value as i16) + } + + /** + Stream a signed 16bit integer. + */ + pub fn i16<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: i16) -> Result { + stream.i32(value as i32) + } + + /** + Stream a signed 32bit integer. + */ + pub fn i32<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: i32) -> Result { + stream.i64(value as i64) + } + + /** + Stream a signed 128bit integer. + */ + pub fn i128<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: i128) -> Result { + if let Ok(value) = value.try_into() { + stream.i64(value) + } else { + data::stream_i128(value, stream) + } + } + + /** + Stream a 32bit binary floating point number. + */ + pub fn f32<'sval>(stream: &mut (impl Stream<'sval> + ?Sized), value: f32) -> Result { + stream.f64(value as f64) + } + + /** + Start a homogenous mapping of arbitrary keys to values. + */ + pub fn map_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + num_entries: Option, + ) -> Result { + stream.seq_begin(num_entries) + } + + /** + Start a key in a key-value mapping. + */ + pub fn map_key_begin<'sval>(stream: &mut (impl Stream<'sval> + ?Sized)) -> Result { + stream.seq_value_begin()?; + stream.tuple_begin(None, None, None, Some(2))?; + stream.tuple_value_begin(None, &Index::new(0)) + } + + /** + Complete a key in a key-value mapping. + */ + pub fn map_key_end<'sval>(stream: &mut (impl Stream<'sval> + ?Sized)) -> Result { + stream.tuple_value_end(None, &Index::new(0)) + } + + /** + Start a value in a key-value mapping. + */ + pub fn map_value_begin<'sval>(stream: &mut (impl Stream<'sval> + ?Sized)) -> Result { + stream.tuple_value_begin(None, &Index::new(1)) + } + + /** + Complete a value in a key-value mapping. + */ + pub fn map_value_end<'sval>(stream: &mut (impl Stream<'sval> + ?Sized)) -> Result { + stream.tuple_value_end(None, &Index::new(1))?; + stream.tuple_end(None, None, None)?; + stream.seq_value_end() + } + + /** + Complete a homogenous mapping of arbitrary keys to values. + */ + pub fn map_end<'sval>(stream: &mut (impl Stream<'sval> + ?Sized)) -> Result { + stream.seq_end() + } + + /** + Start a variant in an enumerated type. + */ + pub fn enum_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + stream.tagged_begin(tag, label, index) + } + + /** + Complete a variant in an enumerated type. + */ + pub fn enum_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + stream.tagged_end(tag, label, index) + } + + /** + Start a tagged value. + + Tagged values may be used as enum variants. + */ + pub fn tagged_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + let _ = stream; + let _ = tag; + let _ = label; + let _ = index; + + Ok(()) + } + + /** + Complete a tagged value. + */ + pub fn tagged_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + let _ = stream; + let _ = tag; + let _ = label; + let _ = index; + + Ok(()) + } + + /** + Stream a standalone tag. + + Standalone tags may be used as enum variants. + */ + pub fn tag<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + stream.tagged_begin(tag, label, index)?; + + // Rust's `Option` is fundamental enough that we handle it specially here + if let Some(&tags::RUST_OPTION_NONE) = tag { + stream.null()?; + } + // If the tag has a label then stream it as its value + else if let Some(ref label) = label { + if let Some(label) = label.as_static_str() { + stream.value(label)?; + } else { + stream.value_computed(label.as_str())?; + } + } + // If the tag doesn't have a label then stream null + else { + stream.null()?; + } + + stream.tagged_end(tag, label, index) + } + + /** + Start a record type. + + Records may be used as enum variants. + */ + pub fn record_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + num_entries: Option, + ) -> Result { + stream.tagged_begin(tag, label, index)?; + stream.map_begin(num_entries) + } + + /** + Start a field in a record. + */ + pub fn record_value_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: &Label, + ) -> Result { + let _ = tag; + + stream.map_key_begin()?; + + if let Some(label) = label.as_static_str() { + stream.value(label)?; + } else { + stream.value_computed(label.as_str())?; + } + + stream.map_key_end()?; + + stream.map_value_begin() + } + + /** + Complete a field in a record. + */ + pub fn record_value_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: &Label, + ) -> Result { + let _ = tag; + let _ = label; + + stream.map_value_end() + } + + /** + Complete a record type. + */ + pub fn record_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + stream.map_end()?; + stream.tagged_end(tag, label, index) + } + + /** + Start a tuple type. + + Tuples may be used as enum variants. + */ + pub fn tuple_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + num_entries: Option, + ) -> Result { + stream.tagged_begin(tag, label, index)?; + stream.seq_begin(num_entries) + } + + /** + Start a field in a tuple. + */ + pub fn tuple_value_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + index: &Index, + ) -> Result { + let _ = tag; + let _ = index; + + stream.seq_value_begin() + } + + /** + Complete a field in a tuple. + */ + pub fn tuple_value_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + index: &Index, + ) -> Result { + let _ = tag; + let _ = index; + + stream.seq_value_end() + } + + /** + Complete a tuple type. + */ + pub fn tuple_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + stream.seq_end()?; + stream.tagged_end(tag, label, index) + } + + /** + Begin a type that may be treated as either a record or a tuple. + */ + pub fn record_tuple_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + num_entries: Option, + ) -> Result { + stream.record_begin(tag, label, index, num_entries) + } + + /** + Begin a field in a type that may be treated as either a record or a tuple. + */ + pub fn record_tuple_value_begin<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: &Label, + index: &Index, + ) -> Result { + let _ = index; + + stream.record_value_begin(tag, label) + } + + /** + Complete a field in a type that may be treated as either a record or a tuple. + */ + pub fn record_tuple_value_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: &Label, + index: &Index, + ) -> Result { + let _ = index; + + stream.record_value_end(tag, label) + } + + /** + Complete a type that may be treated as either a record or a tuple. + */ + pub fn record_tuple_end<'sval>( + stream: &mut (impl Stream<'sval> + ?Sized), + tag: Option<&Tag>, + label: Option<&Label>, + index: Option<&Index>, + ) -> Result { + stream.record_end(tag, label, index) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/value.rs b/src/value.rs index ba8305dc..8b25b143 100644 --- a/src/value.rs +++ b/src/value.rs @@ -14,6 +14,259 @@ pub trait Value { */ #[inline] fn tag(&self) -> Option { + default_value::tag(self) + } + + /** + Try convert this value into a boolean. + */ + #[inline] + fn to_bool(&self) -> Option { + default_value::to_bool(self) + } + + /** + Try convert this value into a 32bit binary floating point number. + */ + #[inline] + fn to_f32(&self) -> Option { + default_value::to_f32(self) + } + + /** + Try convert this value into a 64bit binary floating point number. + */ + #[inline] + fn to_f64(&self) -> Option { + default_value::to_f64(self) + } + + /** + Try convert this value into a signed 8bit integer. + */ + #[inline] + fn to_i8(&self) -> Option { + default_value::to_i8(self) + } + + /** + Try convert this value into a signed 16bit integer. + */ + #[inline] + fn to_i16(&self) -> Option { + default_value::to_i16(self) + } + + /** + Try convert this value into a signed 32bit integer. + */ + #[inline] + fn to_i32(&self) -> Option { + default_value::to_i32(self) + } + + /** + Try convert this value into a signed 64bit integer. + */ + #[inline] + fn to_i64(&self) -> Option { + default_value::to_i64(self) + } + + /** + Try convert this value into a signed 128bit integer. + */ + #[inline] + fn to_i128(&self) -> Option { + default_value::to_i128(self) + } + + /** + Try convert this value into an unsigned 8bit integer. + */ + #[inline] + fn to_u8(&self) -> Option { + default_value::to_u8(self) + } + + /** + Try convert this value into an unsigned 16bit integer. + */ + #[inline] + fn to_u16(&self) -> Option { + default_value::to_u16(self) + } + + /** + Try convert this value into an unsigned 32bit integer. + */ + #[inline] + fn to_u32(&self) -> Option { + default_value::to_u32(self) + } + + /** + Try convert this value into an unsigned 64bit integer. + */ + #[inline] + fn to_u64(&self) -> Option { + default_value::to_u64(self) + } + + /** + Try convert this value into an unsigned 128bit integer. + */ + #[inline] + fn to_u128(&self) -> Option { + default_value::to_u128(self) + } + + /** + Try convert this value into a text string. + */ + #[inline] + fn to_text(&self) -> Option<&str> { + default_value::to_text(self) + } + + /** + Try convert this value into a bitstring. + */ + #[inline] + fn to_binary(&self) -> Option<&[u8]> { + default_value::to_binary(self) + } +} + +macro_rules! impl_value_forward { + ({ $($r:tt)* } => $bind:ident => { $($forward:tt)* }) => { + $($r)* { + fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result { + let $bind = self; + ($($forward)*).stream(stream) + } + + #[inline] + fn tag(&self) -> Option { + let $bind = self; + ($($forward)*).tag() + } + + #[inline] + fn to_bool(&self) -> Option { + let $bind = self; + ($($forward)*).to_bool() + } + + #[inline] + fn to_f32(&self) -> Option { + let $bind = self; + ($($forward)*).to_f32() + } + + #[inline] + fn to_f64(&self) -> Option { + let $bind = self; + ($($forward)*).to_f64() + } + + #[inline] + fn to_i8(&self) -> Option { + let $bind = self; + ($($forward)*).to_i8() + } + + #[inline] + fn to_i16(&self) -> Option { + let $bind = self; + ($($forward)*).to_i16() + } + + #[inline] + fn to_i32(&self) -> Option { + let $bind = self; + ($($forward)*).to_i32() + } + + #[inline] + fn to_i64(&self) -> Option { + let $bind = self; + ($($forward)*).to_i64() + } + + #[inline] + fn to_i128(&self) -> Option { + let $bind = self; + ($($forward)*).to_i128() + } + + #[inline] + fn to_u8(&self) -> Option { + let $bind = self; + ($($forward)*).to_u8() + } + + #[inline] + fn to_u16(&self) -> Option { + let $bind = self; + ($($forward)*).to_u16() + } + + #[inline] + fn to_u32(&self) -> Option { + let $bind = self; + ($($forward)*).to_u32() + } + + #[inline] + fn to_u64(&self) -> Option { + let $bind = self; + ($($forward)*).to_u64() + } + + #[inline] + fn to_u128(&self) -> Option { + let $bind = self; + ($($forward)*).to_u128() + } + + #[inline] + fn to_text(&self) -> Option<&str> { + let $bind = self; + ($($forward)*).to_text() + } + + #[inline] + fn to_binary(&self) -> Option<&[u8]> { + let $bind = self; + ($($forward)*).to_binary() + } + } + }; +} + +impl_value_forward!({impl<'a, T: Value + ?Sized> Value for &'a T} => x => { **x }); + +#[cfg(feature = "alloc")] +mod alloc_support { + use super::*; + + use crate::std::boxed::Box; + + impl_value_forward!({impl Value for Box} => x => { **x }); +} + +pub mod default_value { + /*! + Default method implementations for [`Value`]s. + */ + + use super::*; + + /** + Get the tag of this value, if there is one. + */ + pub fn tag(value: &(impl Value + ?Sized)) -> Option { struct Extract { value: Option, set: bool, @@ -125,7 +378,7 @@ pub trait Value { set: false, }; - let _ = self.stream(&mut extract); + let _ = value.stream(&mut extract); extract.value } @@ -133,8 +386,7 @@ pub trait Value { /** Try convert this value into a boolean. */ - #[inline] - fn to_bool(&self) -> Option { + pub fn to_bool(value: &(impl Value + ?Sized)) -> Option { struct Extract(Option); impl<'sval> Stream<'sval> for Extract { @@ -185,15 +437,14 @@ pub trait Value { } let mut extract = Extract(None); - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.0 } /** Try convert this value into a 32bit binary floating point number. */ - #[inline] - fn to_f32(&self) -> Option { + pub fn to_f32(value: &(impl Value + ?Sized)) -> Option { struct Extract(Option); impl<'sval> Stream<'sval> for Extract { @@ -248,15 +499,14 @@ pub trait Value { } let mut extract = Extract(None); - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.0 } /** Try convert this value into a 64bit binary floating point number. */ - #[inline] - fn to_f64(&self) -> Option { + pub fn to_f64(value: &(impl Value + ?Sized)) -> Option { struct Extract(Option); impl<'sval> Stream<'sval> for Extract { @@ -307,47 +557,42 @@ pub trait Value { } let mut extract = Extract(None); - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.0 } /** Try convert this value into a signed 8bit integer. */ - #[inline] - fn to_i8(&self) -> Option { - self.to_i128().and_then(|value| value.try_into().ok()) + pub fn to_i8(value: &(impl Value + ?Sized)) -> Option { + value.to_i128().and_then(|value| value.try_into().ok()) } /** Try convert this value into a signed 16bit integer. */ - #[inline] - fn to_i16(&self) -> Option { - self.to_i128().and_then(|value| value.try_into().ok()) + pub fn to_i16(value: &(impl Value + ?Sized)) -> Option { + value.to_i128().and_then(|value| value.try_into().ok()) } /** Try convert this value into a signed 32bit integer. */ - #[inline] - fn to_i32(&self) -> Option { - self.to_i128().and_then(|value| value.try_into().ok()) + pub fn to_i32(value: &(impl Value + ?Sized)) -> Option { + value.to_i128().and_then(|value| value.try_into().ok()) } /** Try convert this value into a signed 64bit integer. */ - #[inline] - fn to_i64(&self) -> Option { - self.to_i128().and_then(|value| value.try_into().ok()) + pub fn to_i64(value: &(impl Value + ?Sized)) -> Option { + value.to_i128().and_then(|value| value.try_into().ok()) } /** Try convert this value into a signed 128bit integer. */ - #[inline] - fn to_i128(&self) -> Option { + pub fn to_i128(value: &(impl Value + ?Sized)) -> Option { struct Extract(Option); impl<'sval> Stream<'sval> for Extract { @@ -402,47 +647,42 @@ pub trait Value { } let mut extract = Extract(None); - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.0 } /** Try convert this value into an unsigned 8bit integer. */ - #[inline] - fn to_u8(&self) -> Option { - self.to_u128().and_then(|value| value.try_into().ok()) + pub fn to_u8(value: &(impl Value + ?Sized)) -> Option { + value.to_u128().and_then(|value| value.try_into().ok()) } /** Try convert this value into an unsigned 16bit integer. */ - #[inline] - fn to_u16(&self) -> Option { - self.to_u128().and_then(|value| value.try_into().ok()) + pub fn to_u16(value: &(impl Value + ?Sized)) -> Option { + value.to_u128().and_then(|value| value.try_into().ok()) } /** Try convert this value into an unsigned 32bit integer. */ - #[inline] - fn to_u32(&self) -> Option { - self.to_u128().and_then(|value| value.try_into().ok()) + pub fn to_u32(value: &(impl Value + ?Sized)) -> Option { + value.to_u128().and_then(|value| value.try_into().ok()) } /** Try convert this value into an unsigned 64bit integer. */ - #[inline] - fn to_u64(&self) -> Option { - self.to_u128().and_then(|value| value.try_into().ok()) + pub fn to_u64(value: &(impl Value + ?Sized)) -> Option { + value.to_u128().and_then(|value| value.try_into().ok()) } /** Try convert this value into an unsigned 128bit integer. */ - #[inline] - fn to_u128(&self) -> Option { + pub fn to_u128(value: &(impl Value + ?Sized)) -> Option { struct Extract(Option); impl<'sval> Stream<'sval> for Extract { @@ -497,15 +737,14 @@ pub trait Value { } let mut extract = Extract(None); - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.0 } /** Try convert this value into a text string. */ - #[inline] - fn to_text(&self) -> Option<&str> { + pub fn to_text(value: &(impl Value + ?Sized)) -> Option<&str> { struct Extract<'sval> { extracted: Option<&'sval str>, seen_fragment: bool, @@ -577,15 +816,14 @@ pub trait Value { seen_fragment: false, }; - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.extracted } /** Try convert this value into a bitstring. */ - #[inline] - fn to_binary(&self) -> Option<&[u8]> { + pub fn to_binary(value: &(impl Value + ?Sized)) -> Option<&[u8]> { struct Extract<'sval> { extracted: Option<&'sval [u8]>, seen_fragment: bool, @@ -669,125 +907,7 @@ pub trait Value { seen_fragment: false, }; - self.stream(&mut extract).ok()?; + value.stream(&mut extract).ok()?; extract.extracted } } - -macro_rules! impl_value_forward { - ({ $($r:tt)* } => $bind:ident => { $($forward:tt)* }) => { - $($r)* { - fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result { - let $bind = self; - ($($forward)*).stream(stream) - } - - #[inline] - fn tag(&self) -> Option { - let $bind = self; - ($($forward)*).tag() - } - - #[inline] - fn to_bool(&self) -> Option { - let $bind = self; - ($($forward)*).to_bool() - } - - #[inline] - fn to_f32(&self) -> Option { - let $bind = self; - ($($forward)*).to_f32() - } - - #[inline] - fn to_f64(&self) -> Option { - let $bind = self; - ($($forward)*).to_f64() - } - - #[inline] - fn to_i8(&self) -> Option { - let $bind = self; - ($($forward)*).to_i8() - } - - #[inline] - fn to_i16(&self) -> Option { - let $bind = self; - ($($forward)*).to_i16() - } - - #[inline] - fn to_i32(&self) -> Option { - let $bind = self; - ($($forward)*).to_i32() - } - - #[inline] - fn to_i64(&self) -> Option { - let $bind = self; - ($($forward)*).to_i64() - } - - #[inline] - fn to_i128(&self) -> Option { - let $bind = self; - ($($forward)*).to_i128() - } - - #[inline] - fn to_u8(&self) -> Option { - let $bind = self; - ($($forward)*).to_u8() - } - - #[inline] - fn to_u16(&self) -> Option { - let $bind = self; - ($($forward)*).to_u16() - } - - #[inline] - fn to_u32(&self) -> Option { - let $bind = self; - ($($forward)*).to_u32() - } - - #[inline] - fn to_u64(&self) -> Option { - let $bind = self; - ($($forward)*).to_u64() - } - - #[inline] - fn to_u128(&self) -> Option { - let $bind = self; - ($($forward)*).to_u128() - } - - #[inline] - fn to_text(&self) -> Option<&str> { - let $bind = self; - ($($forward)*).to_text() - } - - #[inline] - fn to_binary(&self) -> Option<&[u8]> { - let $bind = self; - ($($forward)*).to_binary() - } - } - }; -} - -impl_value_forward!({impl<'a, T: Value + ?Sized> Value for &'a T} => x => { **x }); - -#[cfg(feature = "alloc")] -mod alloc_support { - use super::*; - - use crate::std::boxed::Box; - - impl_value_forward!({impl Value for Box} => x => { **x }); -}