From 23ac23ca4311bbd4f2cc308e4b89d9c56e60bfab Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Thu, 2 Jan 2025 04:23:34 +0100 Subject: [PATCH] Add Allocator to Decode trait * Allow specifying a custom lifetime and allocator identifier --- asm/src/lib.rs | 3 +- crates/musli-core/src/alloc/raw_vec.rs | 2 +- crates/musli-core/src/context.rs | 2 +- crates/musli-core/src/de/as_decoder.rs | 1 + crates/musli-core/src/de/decode.rs | 10 +- crates/musli-core/src/de/decode_bytes.rs | 10 +- crates/musli-core/src/de/decode_packed.rs | 10 +- crates/musli-core/src/de/decode_trace.rs | 10 +- crates/musli-core/src/de/decoder.rs | 28 +++- crates/musli-core/src/de/entries_decoder.rs | 2 + crates/musli-core/src/de/entry_decoder.rs | 2 + crates/musli-core/src/de/map_decoder.rs | 4 +- crates/musli-core/src/de/mod.rs | 18 ++- crates/musli-core/src/de/sequence_decoder.rs | 5 +- crates/musli-core/src/de/utils.rs | 4 +- crates/musli-core/src/de/variant_decoder.rs | 2 + crates/musli-core/src/de/visitor.rs | 4 +- crates/musli-core/src/impls/alloc.rs | 146 ++++++++++++------- crates/musli-core/src/impls/mod.rs | 109 +++++++++----- crates/musli-core/src/impls/net.rs | 64 +++++--- crates/musli-core/src/impls/range.rs | 16 +- crates/musli-core/src/impls/tuples.rs | 19 ++- crates/musli-core/src/lib.rs | 3 + crates/musli-core/src/never.rs | 3 +- crates/musli-macros/src/de.rs | 73 ++++++---- crates/musli-macros/src/en.rs | 24 ++- crates/musli-macros/src/expander.rs | 112 ++++++++++++-- crates/musli-macros/src/internals/attr.rs | 67 +++++++-- crates/musli-macros/src/internals/build.rs | 85 ++++++++--- crates/musli-macros/src/internals/ctxt.rs | 36 ++++- crates/musli-macros/src/internals/mod.rs | 2 +- crates/musli-macros/src/internals/mode.rs | 75 ++++++++-- crates/musli-macros/src/internals/packed.rs | 26 ++-- crates/musli-macros/src/internals/tokens.rs | 3 + crates/musli/help/derives.md | 17 ++- crates/musli/src/alloc/default.rs | 4 +- crates/musli/src/alloc/disabled.rs | 4 +- crates/musli/src/alloc/stack.rs | 3 +- crates/musli/src/alloc/string.rs | 3 +- crates/musli/src/alloc/system.rs | 4 +- crates/musli/src/alloc/vec.rs | 4 +- crates/musli/src/compat.rs | 34 +++-- crates/musli/src/context/capture.rs | 4 +- crates/musli/src/context/context_error.rs | 2 +- crates/musli/src/context/default_context.rs | 4 +- crates/musli/src/context/error_marker.rs | 2 +- crates/musli/src/context/ignore.rs | 4 +- crates/musli/src/context/mod.rs | 2 +- crates/musli/src/context/same.rs | 4 +- crates/musli/src/descriptive/de.rs | 1 + crates/musli/src/descriptive/tag.rs | 9 +- crates/musli/src/json/de/key_decoder.rs | 1 + crates/musli/src/json/de/mod.rs | 1 + crates/musli/src/json/encoding.rs | 2 +- crates/musli/src/json/parser/string.rs | 4 +- crates/musli/src/lib.rs | 11 +- crates/musli/src/macros/internal.rs | 34 ++--- crates/musli/src/macros/mod.rs | 4 +- crates/musli/src/macros/test.rs | 131 ++++++++--------- crates/musli/src/storage/de.rs | 5 +- crates/musli/src/value/de.rs | 1 + crates/musli/src/value/error.rs | 2 +- crates/musli/src/value/mod.rs | 13 +- crates/musli/src/value/value.rs | 7 +- crates/musli/src/wire/de.rs | 1 + crates/musli/src/writer.rs | 4 +- crates/musli/tests/generic_bounds.rs | 4 +- crates/musli/tests/recursive_models.rs | 3 +- crates/musli/tests/serde_compat.rs | 21 ++- crates/musli/tests/skip_compat.rs | 4 +- crates/musli/tests/visitors.rs | 17 ++- tests/src/utils/musli.rs | 18 ++- 72 files changed, 933 insertions(+), 440 deletions(-) diff --git a/asm/src/lib.rs b/asm/src/lib.rs index f6ff160e6..63c2af39c 100644 --- a/asm/src/lib.rs +++ b/asm/src/lib.rs @@ -188,6 +188,7 @@ pub mod generic { #[cfg(feature = "musli")] pub mod musli { + use musli::alloc::System; use musli::context::{ErrorMarker as Error, Ignore}; use musli::options::{self, Options}; use musli::storage::Encoding; @@ -220,7 +221,7 @@ pub mod musli { #[inline(always)] pub fn decode<'buf, T>(buf: &'buf [u8]) -> Result where - T: Decode<'buf, Packed>, + T: Decode<'buf, Packed, System>, { let cx = Ignore::new(); ENCODING.from_slice_with(&cx, buf) diff --git a/crates/musli-core/src/alloc/raw_vec.rs b/crates/musli-core/src/alloc/raw_vec.rs index d3c4fcb63..5cbbe73ff 100644 --- a/crates/musli-core/src/alloc/raw_vec.rs +++ b/crates/musli-core/src/alloc/raw_vec.rs @@ -1,6 +1,6 @@ /// A raw buffer allocated through an [`Allocator`]. /// -/// [`Allocator`]: super::Allocator +/// [`Allocator`]: crate::Allocator /// /// ## Examples /// diff --git a/crates/musli-core/src/context.rs b/crates/musli-core/src/context.rs index af2e98e2d..bac4cc2e9 100644 --- a/crates/musli-core/src/context.rs +++ b/crates/musli-core/src/context.rs @@ -4,7 +4,7 @@ use core::error::Error; use core::fmt; use core::str; -use crate::alloc::Allocator; +use crate::Allocator; /// Provides ergonomic access to the serialization context. /// diff --git a/crates/musli-core/src/de/as_decoder.rs b/crates/musli-core/src/de/as_decoder.rs index 80d1cf54c..f90d0d3be 100644 --- a/crates/musli-core/src/de/as_decoder.rs +++ b/crates/musli-core/src/de/as_decoder.rs @@ -12,6 +12,7 @@ pub trait AsDecoder { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; diff --git a/crates/musli-core/src/de/decode.rs b/crates/musli-core/src/de/decode.rs index 8195bafa2..1634bebc9 100644 --- a/crates/musli-core/src/de/decode.rs +++ b/crates/musli-core/src/de/decode.rs @@ -1,3 +1,5 @@ +use crate::Allocator; + use super::Decoder; /// Trait governing how types are decoded. @@ -37,7 +39,11 @@ use super::Decoder; /// } /// } /// ``` -pub trait Decode<'de, M>: Sized { +pub trait Decode<'de, M, A> +where + Self: Sized, + A: Allocator, +{ /// Whether the type is packed. Packed types can be bitwise copied if the /// representation of the serialization format is identical to the memory /// layout of the type. @@ -53,5 +59,5 @@ pub trait Decode<'de, M>: Sized { /// Decode the given input. fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>; + D: Decoder<'de, Mode = M, Allocator = A>; } diff --git a/crates/musli-core/src/de/decode_bytes.rs b/crates/musli-core/src/de/decode_bytes.rs index fcb8f25f7..15878a994 100644 --- a/crates/musli-core/src/de/decode_bytes.rs +++ b/crates/musli-core/src/de/decode_bytes.rs @@ -1,3 +1,5 @@ +use crate::Allocator; + use super::Decoder; /// Trait governing how types are decoded as bytes. @@ -40,7 +42,11 @@ use super::Decoder; /// } /// } /// ``` -pub trait DecodeBytes<'de, M>: Sized { +pub trait DecodeBytes<'de, M, A> +where + Self: Sized, + A: Allocator, +{ /// Whether the type is packed. Packed types can be bitwise copied if the /// representation of the serialization format is identical to the memory /// layout of the type. @@ -53,5 +59,5 @@ pub trait DecodeBytes<'de, M>: Sized { /// Decode the given input as bytes. fn decode_bytes(decoder: D) -> Result where - D: Decoder<'de, Mode = M>; + D: Decoder<'de, Mode = M, Allocator = A>; } diff --git a/crates/musli-core/src/de/decode_packed.rs b/crates/musli-core/src/de/decode_packed.rs index f5299fa1d..db79599e3 100644 --- a/crates/musli-core/src/de/decode_packed.rs +++ b/crates/musli-core/src/de/decode_packed.rs @@ -1,3 +1,5 @@ +use crate::Allocator; + use super::Decoder; /// Trait governing how a type is decoded as a packed value. @@ -45,9 +47,13 @@ use super::Decoder; /// } /// } /// ``` -pub trait DecodePacked<'de, M>: Sized { +pub trait DecodePacked<'de, M, A> +where + Self: Sized, + A: Allocator, +{ /// Decode the given input as bytes. fn decode_packed(decoder: D) -> Result where - D: Decoder<'de, Mode = M>; + D: Decoder<'de, Mode = M, Allocator = A>; } diff --git a/crates/musli-core/src/de/decode_trace.rs b/crates/musli-core/src/de/decode_trace.rs index a9f317ce3..e47eea904 100644 --- a/crates/musli-core/src/de/decode_trace.rs +++ b/crates/musli-core/src/de/decode_trace.rs @@ -1,3 +1,5 @@ +use crate::Allocator; + use super::Decoder; /// Trait governing how types are decoded specifically for tracing. @@ -8,9 +10,13 @@ use super::Decoder; /// /// [`HashMap`]: std::collections::HashMap /// [`fmt::Display`]: std::fmt::Display -pub trait DecodeTrace<'de, M>: Sized { +pub trait DecodeTrace<'de, M, A> +where + Self: Sized, + A: Allocator, +{ /// Decode the given input. fn trace_decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>; + D: Decoder<'de, Mode = M, Allocator = A>; } diff --git a/crates/musli-core/src/de/decoder.rs b/crates/musli-core/src/de/decoder.rs index 105c4ed58..7ce2c47c3 100644 --- a/crates/musli-core/src/de/decoder.rs +++ b/crates/musli-core/src/de/decoder.rs @@ -4,7 +4,7 @@ use core::fmt; use crate::expecting::{self, Expecting}; use crate::hint::{MapHint, SequenceHint}; -use crate::Context; +use crate::{Allocator, Context}; use super::{ utils, AsDecoder, Decode, DecodeSliceBuilder, DecodeUnsized, DecodeUnsizedBytes, @@ -24,20 +24,34 @@ pub enum TryFastDecode { #[must_use = "Decoders must be consumed through one of its decode_* methods"] pub trait Decoder<'de>: Sized { /// Context associated with the decoder. - type Cx: Context; + type Cx: Context; /// Error associated with decoding. type Error; /// Mode associated with decoding. type Mode: 'static; + /// The allocator associated with the decoder. + type Allocator: Allocator; /// [`Decoder`] with a different context returned by /// [`Decoder::with_context`] - type WithContext: Decoder<'de, Cx = U, Error = U::Error, Mode = U::Mode> + type WithContext: Decoder< + 'de, + Cx = U, + Error = U::Error, + Mode = U::Mode, + Allocator = U::Allocator, + > where U: Context; /// Decoder returned by [`Decoder::decode_buffer`]. type DecodeBuffer: AsDecoder; /// Decoder returned by [`Decoder::decode_option`]. - type DecodeSome: Decoder<'de, Cx = Self::Cx, Error = Self::Error, Mode = Self::Mode>; + type DecodeSome: Decoder< + 'de, + Cx = Self::Cx, + Error = Self::Error, + Mode = Self::Mode, + Allocator = Self::Allocator, + >; /// Decoder used by [`Decoder::decode_pack`]. type DecodePack: SequenceDecoder<'de, Cx = Self::Cx>; /// Decoder returned by [`Decoder::decode_sequence`]. @@ -121,7 +135,7 @@ pub trait Decoder<'de>: Sized { #[inline] fn try_fast_decode(self) -> Result, Self::Error> where - T: Decode<'de, Self::Mode>, + T: Decode<'de, Self::Mode, Self::Allocator>, { Ok(TryFastDecode::Unsupported(self)) } @@ -132,7 +146,7 @@ pub trait Decoder<'de>: Sized { #[inline] fn decode(self) -> Result where - T: Decode<'de, Self::Mode>, + T: Decode<'de, Self::Mode, Self::Allocator>, { match self.try_fast_decode::()? { TryFastDecode::Ok(value) => Ok(value), @@ -1234,7 +1248,7 @@ pub trait Decoder<'de>: Sized { fn decode_slice(self) -> Result::Error> where V: DecodeSliceBuilder, - T: Decode<'de, Self::Mode>, + T: Decode<'de, Self::Mode, Self::Allocator>, { utils::default_decode_slice(self) } diff --git a/crates/musli-core/src/de/entries_decoder.rs b/crates/musli-core/src/de/entries_decoder.rs index 250701937..be37b58f7 100644 --- a/crates/musli-core/src/de/entries_decoder.rs +++ b/crates/musli-core/src/de/entries_decoder.rs @@ -19,6 +19,7 @@ pub trait EntriesDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; @@ -28,6 +29,7 @@ pub trait EntriesDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; diff --git a/crates/musli-core/src/de/entry_decoder.rs b/crates/musli-core/src/de/entry_decoder.rs index 27f200c60..ece0da87a 100644 --- a/crates/musli-core/src/de/entry_decoder.rs +++ b/crates/musli-core/src/de/entry_decoder.rs @@ -12,6 +12,7 @@ pub trait EntryDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; @@ -21,6 +22,7 @@ pub trait EntryDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, >; /// Access the context associated with the decoder. diff --git a/crates/musli-core/src/de/map_decoder.rs b/crates/musli-core/src/de/map_decoder.rs index 062768e4e..81fe7d32f 100644 --- a/crates/musli-core/src/de/map_decoder.rs +++ b/crates/musli-core/src/de/map_decoder.rs @@ -39,8 +39,8 @@ pub trait MapDecoder<'de> { /// Decode the next map entry as a tuple. fn entry(&mut self) -> Result, ::Error> where - K: Decode<'de, ::Mode>, - V: Decode<'de, ::Mode>, + K: Decode<'de, ::Mode, ::Allocator>, + V: Decode<'de, ::Mode, ::Allocator>, { let Some(mut entry) = self.decode_entry()? else { return Ok(None); diff --git a/crates/musli-core/src/de/mod.rs b/crates/musli-core/src/de/mod.rs index fa30b3560..cf2549465 100644 --- a/crates/musli-core/src/de/mod.rs +++ b/crates/musli-core/src/de/mod.rs @@ -78,12 +78,24 @@ pub use self::variant_decoder::VariantDecoder; mod visitor; pub use self::visitor::Visitor; +use crate::Allocator; + /// Decode to an owned value. /// /// This is a simpler bound to use than `for<'de> Decode<'de, M>`. -pub trait DecodeOwned: for<'de> Decode<'de, M> {} - -impl DecodeOwned for D where D: for<'de> Decode<'de, M> {} +pub trait DecodeOwned +where + Self: for<'de> Decode<'de, M, A>, + A: Allocator, +{ +} + +impl DecodeOwned for D +where + D: for<'de> Decode<'de, M, A>, + A: Allocator, +{ +} #[doc(hidden)] pub mod utils; diff --git a/crates/musli-core/src/de/sequence_decoder.rs b/crates/musli-core/src/de/sequence_decoder.rs index f6c9b93ff..0609cc69c 100644 --- a/crates/musli-core/src/de/sequence_decoder.rs +++ b/crates/musli-core/src/de/sequence_decoder.rs @@ -12,6 +12,7 @@ pub trait SequenceDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; @@ -42,7 +43,7 @@ pub trait SequenceDecoder<'de> { #[inline] fn next(&mut self) -> Result::Error> where - T: Decode<'de, ::Mode>, + T: Decode<'de, ::Mode, ::Allocator>, { self.decode_next()?.decode() } @@ -51,7 +52,7 @@ pub trait SequenceDecoder<'de> { #[inline] fn try_next(&mut self) -> Result, ::Error> where - T: Decode<'de, ::Mode>, + T: Decode<'de, ::Mode, ::Allocator>, { let Some(decoder) = self.try_decode_next()? else { return Ok(None); diff --git a/crates/musli-core/src/de/utils.rs b/crates/musli-core/src/de/utils.rs index 1fc850d3c..76ea0a682 100644 --- a/crates/musli-core/src/de/utils.rs +++ b/crates/musli-core/src/de/utils.rs @@ -1,3 +1,5 @@ +use crate::Context; + use super::{Decode, DecodeSliceBuilder, Decoder, SequenceDecoder}; /// Default implementation to decode a slice. @@ -6,7 +8,7 @@ pub fn default_decode_slice<'de, D, V, T>(decoder: D) -> Result where D: Decoder<'de>, V: DecodeSliceBuilder, - T: Decode<'de, D::Mode>, + T: Decode<'de, D::Mode, ::Allocator>, { use crate::Context; diff --git a/crates/musli-core/src/de/variant_decoder.rs b/crates/musli-core/src/de/variant_decoder.rs index 863b7b925..2b293fc62 100644 --- a/crates/musli-core/src/de/variant_decoder.rs +++ b/crates/musli-core/src/de/variant_decoder.rs @@ -12,6 +12,7 @@ pub trait VariantDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; @@ -21,6 +22,7 @@ pub trait VariantDecoder<'de> { Cx = Self::Cx, Error = ::Error, Mode = ::Mode, + Allocator = ::Allocator, > where Self: 'this; diff --git a/crates/musli-core/src/de/visitor.rs b/crates/musli-core/src/de/visitor.rs index c343bd344..d4cc7f7ea 100644 --- a/crates/musli-core/src/de/visitor.rs +++ b/crates/musli-core/src/de/visitor.rs @@ -190,7 +190,7 @@ where #[inline] fn visit_option(self, cx: C, _: Option) -> Result where - D: Decoder<'de, Cx = C, Error = C::Error, Mode = C::Mode>, + D: Decoder<'de, Cx = C, Error = C::Error, Mode = C::Mode, Allocator = C::Allocator>, { Err(cx.message(expecting::unsupported_type( &expecting::Option, @@ -256,7 +256,7 @@ where #[inline] fn visit_unknown(self, decoder: D) -> Result where - D: Decoder<'de, Cx = C, Error = C::Error, Mode = C::Mode>, + D: Decoder<'de, Cx = C, Error = C::Error, Mode = C::Mode, Allocator = C::Allocator>, { Err(decoder.cx().message(expecting::unsupported_type( &expecting::Any, diff --git a/crates/musli-core/src/impls/alloc.rs b/crates/musli-core/src/impls/alloc.rs index 90fc5af4e..b430c997d 100644 --- a/crates/musli-core/src/impls/alloc.rs +++ b/crates/musli-core/src/impls/alloc.rs @@ -30,7 +30,7 @@ use crate::en::{ }; use crate::hint::{MapHint, SequenceHint}; use crate::internal::size_hint; -use crate::Context; +use crate::{Allocator, Context}; #[cfg(all(feature = "std", any(unix, windows)))] use super::PlatformTag; @@ -54,7 +54,10 @@ impl Encode for String { } } -impl<'de, M> Decode<'de, M> for String { +impl<'de, M, A> Decode<'de, M, A> for String +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] @@ -95,7 +98,10 @@ impl<'de, M> Decode<'de, M> for String { } } -impl<'de, M> Decode<'de, M> for Box { +impl<'de, M, A> Decode<'de, M, A> for Box +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] @@ -107,16 +113,17 @@ impl<'de, M> Decode<'de, M> for Box { } } -impl<'de, M, T> Decode<'de, M> for Box<[T]> +impl<'de, M, A, T> Decode<'de, M, A> for Box<[T]> where - T: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok(decoder.decode::>()?.into()) } @@ -154,13 +161,16 @@ macro_rules! cow { } } - impl<'de, M> $decode<'de, M> for Cow<'de, $ty> { + impl<'de, M, A> $decode<'de, M, A> for Cow<'de, $ty> + where + A: Allocator, + { const $decode_packed: bool = false; #[inline] fn $decode_fn(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { struct Visitor; @@ -274,9 +284,10 @@ macro_rules! slice_sequence { } $(#[$($meta)*])* - impl<'de, M, T $(, $extra)*> Decode<'de, M> for $ty + impl<'de, M, A, T $(, $extra)*> Decode<'de, M, A> for $ty where - T: Decode<'de, M> $(+ $trait0 $(+ $trait)*)*, + A: Allocator, + T: Decode<'de, M, A> $(+ $trait0 $(+ $trait)*)*, $($extra: $extra_bound0 $(+ $extra_bound)*),* { const IS_BITWISE_DECODE: bool = false; @@ -284,13 +295,14 @@ macro_rules! slice_sequence { #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { - struct Builder<'de, M, T $(, $extra)*>($ty, PhantomData<(M, &'de ())>); + struct Builder<'de, M, A, T $(, $extra)*>($ty, PhantomData<(M, A, &'de ())>); - impl<'de, M, T $(, $extra)*> DecodeSliceBuilder for Builder<'de, M, T $(, $extra)*> + impl<'de, M, A, T $(, $extra)*> DecodeSliceBuilder for Builder<'de, M, A, T $(, $extra)*> where - T: Decode<'de, M> $(+ $trait0 $(+ $trait)*)*, + A: Allocator, + T: Decode<'de, M, A> $(+ $trait0 $(+ $trait)*)*, $($extra: $extra_bound0 $(+ $extra_bound)*),* { #[inline] @@ -411,9 +423,10 @@ macro_rules! sequence { } $(#[$($meta)*])* - impl<'de, M, T $(, $extra)*> Decode<'de, M> for $ty + impl<'de, M, A, T $(, $extra)*> Decode<'de, M, A> for $ty where - T: Decode<'de, M> $(+ $trait0 $(+ $trait)*)*, + A: Allocator, + T: Decode<'de, M, A> $(+ $trait0 $(+ $trait)*)*, $($extra: $extra_bound0 $(+ $extra_bound)*),* { const IS_BITWISE_DECODE: bool = false; @@ -421,7 +434,7 @@ macro_rules! sequence { #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { let $cx = decoder.cx(); @@ -497,16 +510,17 @@ where } } -impl<'de, M, T> Decode<'de, M> for VecDeque +impl<'de, M, A, T> Decode<'de, M, A> for VecDeque where - T: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok(VecDeque::from(Vec::decode(decoder)?)) } @@ -620,10 +634,11 @@ macro_rules! map { } $(#[$($meta)*])* - impl<'de, K, V, M $(, $extra)*> Decode<'de, M> for $ty + impl<'de, K, V, A, M $(, $extra)*> Decode<'de, M, A> for $ty where - K: Decode<'de, M> $(+ $key_bound0 $(+ $key_bound)*)*, - V: Decode<'de, M>, + A: Allocator, + K: Decode<'de, M, A> $(+ $key_bound0 $(+ $key_bound)*)*, + V: Decode<'de, M, A>, $($extra: $extra_bound0 $(+ $extra_bound)*),* { const IS_BITWISE_DECODE: bool = false; @@ -631,7 +646,7 @@ macro_rules! map { #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { decoder.decode_map(|$access| { let mut out = $with_capacity; @@ -646,16 +661,17 @@ macro_rules! map { } $(#[$($meta)*])* - impl<'de, K, V, M $(, $extra)*> DecodeTrace<'de, M> for $ty + impl<'de, K, V, A, M $(, $extra)*> DecodeTrace<'de, M, A> for $ty where - K: fmt::Display + Decode<'de, M> $(+ $key_bound0 $(+ $key_bound)*)*, - V: Decode<'de, M>, + A: Allocator, + K: fmt::Display + Decode<'de, M, A> $(+ $key_bound0 $(+ $key_bound)*)*, + V: Decode<'de, M, A>, $($extra: $extra_bound0 $(+ $extra_bound)*),* { #[inline] fn trace_decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { let $cx = decoder.cx(); @@ -707,13 +723,16 @@ impl Encode for CString { } } -impl<'de, M> Decode<'de, M> for CString { +impl<'de, M, A> Decode<'de, M, A> for CString +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de>, + D: Decoder<'de, Allocator = A>, { struct Visitor; @@ -775,40 +794,47 @@ macro_rules! smart_pointer { } } - impl<'de, M, T> Decode<'de, M> for $ty + impl<'de, M, A, T> Decode<'de, M, A> for $ty where - T: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok($ty::new(decoder.decode()?)) } } - impl<'de, M> DecodeBytes<'de, M> for $ty<[u8]> { + impl<'de, M, A> DecodeBytes<'de, M, A> for $ty<[u8]> + where + A: Allocator + { const DECODE_BYTES_PACKED: bool = false; #[inline] fn decode_bytes(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok($ty::from(>::decode_bytes(decoder)?)) } } - impl<'de, M> Decode<'de, M> for $ty { + impl<'de, M, A> Decode<'de, M, A> for $ty + where + A: Allocator, + { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok($ty::from(CString::decode(decoder)?)) } @@ -816,13 +842,17 @@ macro_rules! smart_pointer { #[cfg(all(feature = "std", any(unix, windows)))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))] - impl<'de, M> Decode<'de, M> for $ty where PlatformTag: Decode<'de, M> { + impl<'de, M, A> Decode<'de, M, A> for $ty + where + A: Allocator, + PlatformTag: Decode<'de, M, A>, + { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok($ty::from(PathBuf::decode(decoder)?)) } @@ -830,13 +860,17 @@ macro_rules! smart_pointer { #[cfg(all(feature = "std", any(unix, windows)))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))] - impl<'de, M> Decode<'de, M> for $ty where PlatformTag: Decode<'de, M> { + impl<'de, M, A> Decode<'de, M, A> for $ty + where + A: Allocator, + PlatformTag: Decode<'de, M, A>, + { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok($ty::from(OsString::decode(decoder)?)) } @@ -882,7 +916,7 @@ where { use std::os::windows::ffi::OsStrExt; - use crate::alloc::{Allocator, RawVec}; + use crate::alloc::RawVec; use crate::en::VariantEncoder; let cx = encoder.cx(); @@ -949,16 +983,17 @@ where #[cfg(all(feature = "std", any(unix, windows)))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))] -impl<'de, M> Decode<'de, M> for OsString +impl<'de, M, A> Decode<'de, M, A> for OsString where - PlatformTag: Decode<'de, M>, + A: Allocator, + PlatformTag: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { use crate::de::VariantDecoder; @@ -1067,16 +1102,17 @@ where #[cfg(all(feature = "std", any(unix, windows)))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))] -impl<'de, M> Decode<'de, M> for PathBuf +impl<'de, M, A> Decode<'de, M, A> for PathBuf where - PlatformTag: Decode<'de, M>, + A: Allocator, + PlatformTag: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok(PathBuf::from(decoder.decode::()?)) } @@ -1120,13 +1156,16 @@ impl EncodeBytes for Box<[u8]> { } } -impl<'de, M> DecodeBytes<'de, M> for Vec { +impl<'de, M, A> DecodeBytes<'de, M, A> for Vec +where + A: Allocator, +{ const DECODE_BYTES_PACKED: bool = false; #[inline] fn decode_bytes(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { struct Visitor; @@ -1176,13 +1215,16 @@ impl EncodeBytes for VecDeque { } } -impl<'de, M> DecodeBytes<'de, M> for VecDeque { +impl<'de, M, A> DecodeBytes<'de, M, A> for VecDeque +where + A: Allocator, +{ const DECODE_BYTES_PACKED: bool = false; #[inline] fn decode_bytes(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok(VecDeque::from(>::decode_bytes(decoder)?)) } diff --git a/crates/musli-core/src/impls/mod.rs b/crates/musli-core/src/impls/mod.rs index a8698619e..48504541d 100644 --- a/crates/musli-core/src/impls/mod.rs +++ b/crates/musli-core/src/impls/mod.rs @@ -19,7 +19,7 @@ use crate::de::{ UnsizedVisitor, VariantDecoder, }; use crate::en::{Encode, EncodeBytes, EncodePacked, Encoder, SequenceEncoder, VariantEncoder}; -use crate::Context; +use crate::{Allocator, Context}; /// Platform tag used by certain platform-specific implementations. #[cfg(feature = "std")] @@ -50,14 +50,17 @@ impl Encode for () { } } -impl<'de, M> Decode<'de, M> for () { +impl<'de, M, A> Decode<'de, M, A> for () +where + A: Allocator, +{ // Unit is always packed, since it is a ZST. const IS_BITWISE_DECODE: bool = true; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de>, + D: Decoder<'de, Allocator = A>, { decoder.decode_empty() } @@ -83,7 +86,10 @@ impl Encode for marker::PhantomData { } } -impl<'de, M, T> Decode<'de, M> for marker::PhantomData { +impl<'de, M, A, T> Decode<'de, M, A> for marker::PhantomData +where + A: Allocator, +{ // PhantomData is always packed, since it is a ZST. const IS_BITWISE_DECODE: bool = true; @@ -101,7 +107,10 @@ macro_rules! atomic_impl { ($size:literal $(, $ty:ident)*) => { $( #[cfg(target_has_atomic = $size)] - impl<'de, M> Decode<'de, M> for core::sync::atomic::$ty { + impl<'de, M, A> Decode<'de, M, A> for core::sync::atomic::$ty + where + A: Allocator + { const IS_BITWISE_DECODE: bool = true; fn decode(decoder: D) -> Result @@ -142,14 +151,17 @@ macro_rules! non_zero { } } - impl<'de, M> Decode<'de, M> for $ty { + impl<'de, M, A> Decode<'de, M, A> for $ty + where + A: Allocator, + { // Non zero types are not considered packed during decoding, because // they cannot inhabit the bit pattern of all zeros. const IS_BITWISE_DECODE: bool = false; fn decode(decoder: D) -> Result where - D: Decoder<'de>, + D: Decoder<'de, Allocator = A>, { let cx = decoder.cx(); let value = decoder.decode()?; @@ -220,9 +232,10 @@ where } } -impl<'de, M, T, const N: usize> Decode<'de, M> for [T; N] +impl<'de, M, T, A, const N: usize> Decode<'de, M, A> for [T; N] where - T: Decode<'de, M>, + T: Decode<'de, M, A>, + A: Allocator, { const IS_BITWISE_DECODE: bool = T::IS_BITWISE_DECODE && core::mem::size_of::() % core::mem::align_of::() == 0; @@ -230,7 +243,7 @@ where #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { let cx = decoder.cx(); let mark = cx.mark(); @@ -276,14 +289,15 @@ where } } -impl<'de, M, T, const N: usize> DecodePacked<'de, M> for [T; N] +impl<'de, M, A, T, const N: usize> DecodePacked<'de, M, A> for [T; N] where - T: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, { #[inline] fn decode_packed(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { let cx = decoder.cx(); @@ -321,7 +335,10 @@ macro_rules! impl_number { } } - impl<'de, M> Decode<'de, M> for $ty { + impl<'de, M, A> Decode<'de, M, A> for $ty + where + A: Allocator, + { const IS_BITWISE_DECODE: bool = true; #[inline] @@ -356,7 +373,10 @@ impl Encode for bool { } } -impl<'de, M> Decode<'de, M> for bool { +impl<'de, M, A> Decode<'de, M, A> for bool +where + A: Allocator, +{ // A boolean is not packed during decoding since every bit pattern that // comes in is not necessarily valid. const IS_BITWISE_DECODE: bool = false; @@ -391,7 +411,10 @@ impl Encode for char { } } -impl<'de, M> Decode<'de, M> for char { +impl<'de, M, A> Decode<'de, M, A> for char +where + A: Allocator, +{ // A char is not packed during decoding since it's not guaranteed to inhabit // a valid bit pattern of a u32 and can not be bitwise copied when encoded. const IS_BITWISE_DECODE: bool = false; @@ -438,7 +461,10 @@ impl Encode for str { } } -impl<'de, M> Decode<'de, M> for &'de str { +impl<'de, M, A> Decode<'de, M, A> for &'de str +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] @@ -553,7 +579,10 @@ where } } -impl<'de, M> Decode<'de, M> for &'de [u8] { +impl<'de, M, A> Decode<'de, M, A> for &'de [u8] +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] @@ -640,16 +669,17 @@ where } } -impl<'de, M, T> Decode<'de, M> for Option +impl<'de, M, A, T> Decode<'de, M, A> for Option where - T: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { if let Some(decoder) = decoder.decode_option()? { Ok(Some(decoder.decode()?)) @@ -695,18 +725,19 @@ where } } -impl<'de, M, T, U> Decode<'de, M> for Result +impl<'de, M, A, T, U> Decode<'de, M, A> for Result where - T: Decode<'de, M>, - U: Decode<'de, M>, - ResultTag: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, + U: Decode<'de, M, A>, + ResultTag: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { decoder.decode_variant(|variant| { let tag = variant.decode_tag()?.decode()?; @@ -741,16 +772,17 @@ where } } -impl<'de, M, T> Decode<'de, M> for Wrapping +impl<'de, M, T, A> Decode<'de, M, A> for Wrapping where - T: Decode<'de, M>, + T: Decode<'de, M, A>, + A: Allocator, { const IS_BITWISE_DECODE: bool = T::IS_BITWISE_DECODE; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok(Wrapping(decoder.decode()?)) } @@ -775,7 +807,10 @@ impl Encode for CStr { } } -impl<'de, M> Decode<'de, M> for &'de CStr { +impl<'de, M, A> Decode<'de, M, A> for &'de CStr +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] @@ -843,25 +878,31 @@ impl EncodeBytes for [u8; N] { } } -impl<'de, M> DecodeBytes<'de, M> for &'de [u8] { +impl<'de, M, A> DecodeBytes<'de, M, A> for &'de [u8] +where + A: Allocator, +{ const DECODE_BYTES_PACKED: bool = false; #[inline] fn decode_bytes(decoder: D) -> Result where - D: Decoder<'de>, + D: Decoder<'de, Allocator = A>, { Decode::decode(decoder) } } -impl<'de, M, const N: usize> DecodeBytes<'de, M> for [u8; N] { +impl<'de, M, A, const N: usize> DecodeBytes<'de, M, A> for [u8; N] +where + A: Allocator, +{ const DECODE_BYTES_PACKED: bool = true; #[inline] fn decode_bytes(decoder: D) -> Result where - D: Decoder<'de>, + D: Decoder<'de, Allocator = A>, { decoder.decode_array() } diff --git a/crates/musli-core/src/impls/net.rs b/crates/musli-core/src/impls/net.rs index 1f0e02508..622d95a99 100644 --- a/crates/musli-core/src/impls/net.rs +++ b/crates/musli-core/src/impls/net.rs @@ -1,10 +1,10 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::str::FromStr; -use crate::context::Context; use crate::de::{Decode, Decoder, SequenceDecoder, VariantDecoder}; use crate::en::{Encode, Encoder, SequenceEncoder, VariantEncoder}; use crate::mode::{Binary, Text}; +use crate::{Allocator, Context}; #[derive(Encode, Decode)] #[musli(crate)] @@ -64,7 +64,10 @@ impl Encode for Ipv4Addr { } } -impl<'de> Decode<'de, Binary> for Ipv4Addr { +impl<'de, A> Decode<'de, Binary, A> for Ipv4Addr +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -78,7 +81,10 @@ impl<'de> Decode<'de, Binary> for Ipv4Addr { } } -impl<'de> Decode<'de, Text> for Ipv4Addr { +impl<'de, A> Decode<'de, Text, A> for Ipv4Addr +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -135,7 +141,10 @@ impl Encode for Ipv6Addr { } } -impl<'de> Decode<'de, Binary> for Ipv6Addr { +impl<'de, A> Decode<'de, Binary, A> for Ipv6Addr +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -149,7 +158,10 @@ impl<'de> Decode<'de, Binary> for Ipv6Addr { } } -impl<'de> Decode<'de, Text> for Ipv6Addr { +impl<'de, A> Decode<'de, Text, A> for Ipv6Addr +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -193,18 +205,19 @@ where } } -impl<'de, M> Decode<'de, M> for IpAddr +impl<'de, M, A> Decode<'de, M, A> for IpAddr where - IpAddrTag: Decode<'de, M>, - Ipv4Addr: Decode<'de, M>, - Ipv6Addr: Decode<'de, M>, + A: Allocator, + IpAddrTag: Decode<'de, M, A>, + Ipv4Addr: Decode<'de, M, A>, + Ipv6Addr: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { decoder.decode_variant(|variant| { let tag = variant.decode_tag()?.decode()?; @@ -263,7 +276,10 @@ impl Encode for SocketAddrV4 { } } -impl<'de> Decode<'de, Binary> for SocketAddrV4 { +impl<'de, A> Decode<'de, Binary, A> for SocketAddrV4 +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -277,7 +293,10 @@ impl<'de> Decode<'de, Binary> for SocketAddrV4 { } } -impl<'de> Decode<'de, Text> for SocketAddrV4 { +impl<'de, A> Decode<'de, Text, A> for SocketAddrV4 +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -340,7 +359,10 @@ impl Encode for SocketAddrV6 { } } -impl<'de> Decode<'de, Binary> for SocketAddrV6 { +impl<'de, A> Decode<'de, Binary, A> for SocketAddrV6 +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -354,7 +376,10 @@ impl<'de> Decode<'de, Binary> for SocketAddrV6 { } } -impl<'de> Decode<'de, Text> for SocketAddrV6 { +impl<'de, A> Decode<'de, Text, A> for SocketAddrV6 +where + A: Allocator, +{ // Not packed since it doesn't have a strongly defined memory layout, even // though it has a particular size. const IS_BITWISE_DECODE: bool = false; @@ -398,18 +423,19 @@ where } } -impl<'de, M> Decode<'de, M> for SocketAddr +impl<'de, M, A> Decode<'de, M, A> for SocketAddr where - SocketAddrTag: Decode<'de, M>, - SocketAddrV4: Decode<'de, M>, - SocketAddrV6: Decode<'de, M>, + A: Allocator, + SocketAddrTag: Decode<'de, M, A>, + SocketAddrV4: Decode<'de, M, A>, + SocketAddrV6: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { decoder.decode_variant(|variant| { let tag = variant.decode_tag()?.decode()?; diff --git a/crates/musli-core/src/impls/range.rs b/crates/musli-core/src/impls/range.rs index df9805a6f..510036d8c 100644 --- a/crates/musli-core/src/impls/range.rs +++ b/crates/musli-core/src/impls/range.rs @@ -2,7 +2,7 @@ use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInc use crate::en::SequenceEncoder; use crate::hint::SequenceHint; -use crate::{Decode, Decoder, Encode, Encoder}; +use crate::{Allocator, Decode, Decoder, Encode, Encoder}; macro_rules! implement { ($ty:ident $(<$type:ident>)? { $($field:ident),* }, $count:expr) => { @@ -34,16 +34,17 @@ macro_rules! implement { } } - impl<'de, M, $($type)*> Decode<'de, M> for $ty $(<$type>)* + impl<'de, M, A, $($type)*> Decode<'de, M, A> for $ty $(<$type>)* where - $($type: Decode<'de, M>,)* + A: Allocator, + $($type: Decode<'de, M, A>,)* { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { let ($($field,)*) = decoder.decode()?; Ok($ty { $($field,)* }) @@ -81,16 +82,17 @@ macro_rules! implement_new { } } - impl<'de, M, T> Decode<'de, M> for $ty + impl<'de, M, A, T> Decode<'de, M, A> for $ty where - T: Decode<'de, M>, + A: Allocator, + T: Decode<'de, M, A>, { const IS_BITWISE_DECODE: bool = false; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { let ($($field,)*) = Decode::decode(decoder)?; Ok($ty::new($($field,)*)) diff --git a/crates/musli-core/src/impls/tuples.rs b/crates/musli-core/src/impls/tuples.rs index dbc588074..ef1b45258 100644 --- a/crates/musli-core/src/impls/tuples.rs +++ b/crates/musli-core/src/impls/tuples.rs @@ -3,6 +3,7 @@ use crate::de::{Decode, DecodePacked, Decoder, SequenceDecoder}; use crate::en::{Encode, EncodePacked, Encoder, SequenceEncoder}; use crate::hint::SequenceHint; +use crate::Allocator; macro_rules! count { (_) => { 1 }; @@ -72,10 +73,11 @@ macro_rules! declare { } } - impl<'de, M, $ty0, $($ty,)*> Decode<'de, M> for ($ty0, $($ty),*) + impl<'de, M, A, $ty0, $($ty,)*> Decode<'de, M, A> for ($ty0, $($ty),*) where - $ty0: Decode<'de, M>, - $($ty: Decode<'de, M>),* + A: Allocator, + $ty0: Decode<'de, M, A>, + $($ty: Decode<'de, M, A>),* { // It is harder to check that a tuple is packed, because we have to // ensure it doesn't contain any padding. @@ -84,7 +86,7 @@ macro_rules! declare { #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { static HINT: SequenceHint = SequenceHint::with_size(count!($ident0 $($ident)*)); @@ -115,15 +117,16 @@ macro_rules! declare { } } - impl<'de, M, $ty0, $($ty,)*> DecodePacked<'de, M> for ($ty0, $($ty),*) + impl<'de, M, A, $ty0, $($ty,)*> DecodePacked<'de, M, A> for ($ty0, $($ty),*) where - $ty0: Decode<'de, M>, - $($ty: Decode<'de, M>),* + A: Allocator, + $ty0: Decode<'de, M, A>, + $($ty: Decode<'de, M, A>),* { #[inline] fn decode_packed(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { decoder.decode_pack(|pack| { let $ident0 = pack.next()?; diff --git a/crates/musli-core/src/lib.rs b/crates/musli-core/src/lib.rs index dbddea3d7..2c30af5d6 100644 --- a/crates/musli-core/src/lib.rs +++ b/crates/musli-core/src/lib.rs @@ -17,6 +17,8 @@ extern crate alloc as rust_alloc; extern crate std; pub mod alloc; +#[doc(inline)] +pub use self::alloc::Allocator; mod context; #[doc(inline)] @@ -195,6 +197,7 @@ pub use musli_macros::visitor; /// Using these directly is not supported. #[doc(hidden)] pub mod __priv { + pub use crate::alloc::Allocator; pub use crate::context::Context; pub use crate::de::{ AsDecoder, Decode, DecodeBytes, DecodePacked, DecodeTrace, Decoder, EntryDecoder, diff --git a/crates/musli-core/src/never.rs b/crates/musli-core/src/never.rs index 455ebf746..e0d831f93 100644 --- a/crates/musli-core/src/never.rs +++ b/crates/musli-core/src/never.rs @@ -104,6 +104,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = Never<(), U> where @@ -138,7 +139,7 @@ where #[inline] fn decode(self) -> Result where - T: Decode<'de, Self::Mode>, + T: Decode<'de, Self::Mode, ::Allocator>, { match self._never {} } diff --git a/crates/musli-macros/src/de.rs b/crates/musli-macros/src/de.rs index 11d5cf23c..790206485 100644 --- a/crates/musli-macros/src/de.rs +++ b/crates/musli-macros/src/de.rs @@ -1,14 +1,13 @@ use proc_macro2::{Ident, Literal, Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use syn::punctuated::Punctuated; -use syn::spanned::Spanned; use syn::Token; use crate::expander::{NameMethod, StructKind}; use crate::internals::apply; use crate::internals::attr::{EnumTagging, Packing}; use crate::internals::build::{Body, Build, BuildData, Enum, Field, Variant}; -use crate::internals::{Import, Only, Result, Tokens}; +use crate::internals::{Import, Result, Tokens}; struct Ctxt<'a> { ctx_var: &'a Ident, @@ -18,7 +17,7 @@ struct Ctxt<'a> { trace_body: bool, } -pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { +pub(crate) fn expand_decode_entry(e: Build<'_, '_>) -> Result { e.validate_decode()?; e.cx.reset(); @@ -39,13 +38,7 @@ pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { let body = match &e.data { BuildData::Struct(st) => { - packed = crate::internals::packed( - &e, - st, - e.tokens.decode_t, - "IS_BITWISE_DECODE", - Only::Decode, - ); + packed = crate::internals::packed(&e, st); decode_struct(&cx, &e, st)? } BuildData::Enum(en) => { @@ -64,18 +57,8 @@ pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { let mut generics = e.input.generics.clone(); let type_ident = &e.input.ident; - let (lt, exists) = if let Some(existing) = generics.lifetimes().next() { - (existing.clone(), true) - } else { - let lt = syn::LifetimeParam::new(syn::Lifetime::new("'de", e.input.span())); - (lt, false) - }; - - if !exists { - generics.params.push(lt.clone().into()); - } - let Tokens { + allocator_t, context_t, result, decode_t, @@ -84,6 +67,32 @@ pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { .. } = e.tokens; + let lt = &e.p.lt; + + if !e.p.lt_exists { + generics + .params + .push(syn::GenericParam::Lifetime(syn::LifetimeParam { + attrs: Vec::new(), + lifetime: lt.clone(), + colon_token: None, + bounds: Punctuated::new(), + })); + } + + let allocator_ident = &e.p.allocator_ident; + + if !e.p.allocator_exists { + generics + .params + .push(syn::GenericParam::Type(allocator_ident.clone().into())); + + generics + .make_where_clause() + .predicates + .push(syn::parse_quote!(#allocator_ident: #allocator_t)); + } + if !e.bounds.is_empty() && !e.decode_bounds.is_empty() { generics.make_where_clause().predicates.extend( e.bounds @@ -102,13 +111,13 @@ pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { attributes.push(syn::parse_quote!(#[allow(clippy::just_underscores_and_digits)])); } - let mode_ident = e.expansion.mode_path(&e.tokens); + let mode_ident = e.expansion.mode_path(e.tokens); Ok(quote! { const _: () = { #[automatically_derived] #(#attributes)* - impl #impl_generics #decode_t<#lt, #mode_ident> for #type_ident #type_generics + impl #impl_generics #decode_t<#lt, #mode_ident, #allocator_ident> for #type_ident #type_generics #where_clause { const IS_BITWISE_DECODE: bool = #packed; @@ -116,7 +125,7 @@ pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { #[inline] fn decode<#d_param>(#decoder_var: #d_param) -> #result>::Error> where - #d_param: #decoder_t<#lt, Mode = #mode_ident>, + #d_param: #decoder_t<#lt, Mode = #mode_ident, Allocator = #allocator_ident>, { let #ctx_var = #decoder_t::cx(&#decoder_var); @@ -133,7 +142,7 @@ pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result { }) } -fn decode_struct(cx: &Ctxt<'_>, b: &Build<'_>, st: &Body<'_>) -> Result { +fn decode_struct(cx: &Ctxt<'_>, b: &Build<'_, '_>, st: &Body<'_>) -> Result { let Tokens { result, .. } = b.tokens; let body = match (st.kind, st.packing) { @@ -146,7 +155,7 @@ fn decode_struct(cx: &Ctxt<'_>, b: &Build<'_>, st: &Body<'_>) -> Result, b: &Build<'_>, en: &Enum) -> Result { +fn decode_enum(cx: &Ctxt<'_>, b: &Build<'_, '_>, en: &Enum) -> Result { let Ctxt { ctx_var, name_var, @@ -761,7 +770,7 @@ fn decode_variant( } /// Decode something empty. -fn decode_empty(cx: &Ctxt, b: &Build<'_>, st: &Body<'_>) -> Result { +fn decode_empty(cx: &Ctxt, b: &Build<'_, '_>, st: &Body<'_>) -> Result { let Ctxt { ctx_var, decoder_var, @@ -808,7 +817,7 @@ fn decode_empty(cx: &Ctxt, b: &Build<'_>, st: &Body<'_>) -> Result /// decoded. fn decode_tagged( cx: &Ctxt, - b: &Build<'_>, + b: &Build<'_, '_>, st: &Body<'_>, variant_tag: Option<&Ident>, ) -> Result { @@ -1094,7 +1103,7 @@ fn decode_tagged( } /// Decode a transparent value. -fn decode_transparent(cx: &Ctxt<'_>, b: &Build<'_>, st: &Body<'_>) -> Result { +fn decode_transparent(cx: &Ctxt<'_>, b: &Build<'_, '_>, st: &Body<'_>) -> Result { let Ctxt { decoder_var, ctx_var, @@ -1137,7 +1146,7 @@ fn decode_transparent(cx: &Ctxt<'_>, b: &Build<'_>, st: &Body<'_>) -> Result, b: &Build<'_>, st_: &Body<'_>) -> Result { +fn decode_packed(cx: &Ctxt<'_>, b: &Build<'_, '_>, st_: &Body<'_>) -> Result { let Ctxt { decoder_var, ctx_var, @@ -1219,7 +1228,7 @@ pub(crate) struct NameVariant<'a> { impl NameVariant<'_> { /// Generate the pattern for this output. - pub(crate) fn as_arm(&self, binding_var: &syn::Ident, option: Import<'_>) -> syn::Arm { + pub(crate) fn as_arm(&self, binding_var: &syn::Ident, option: &Import<'_>) -> syn::Arm { let path = &self.path; let arm = output_arm(self.pattern, self.name, binding_var); @@ -1242,7 +1251,7 @@ impl NameVariant<'_> { } fn unsized_arm<'a>( - b: &Build<'_>, + b: &Build<'_, '_>, span: Span, index: usize, name: &'a syn::Expr, diff --git a/crates/musli-macros/src/en.rs b/crates/musli-macros/src/en.rs index 9eb51f1b1..98a4db53d 100644 --- a/crates/musli-macros/src/en.rs +++ b/crates/musli-macros/src/en.rs @@ -5,7 +5,7 @@ use syn::Token; use crate::internals::attr::{EnumTagging, Packing}; use crate::internals::build::{Body, Build, BuildData, Enum, Variant}; -use crate::internals::{Only, Result, Tokens}; +use crate::internals::{Result, Tokens}; struct Ctxt<'a> { ctx_var: &'a syn::Ident, @@ -13,7 +13,7 @@ struct Ctxt<'a> { trace: bool, } -pub(crate) fn expand_insert_entry(e: Build<'_>) -> Result { +pub(crate) fn expand_insert_entry(e: Build<'_, '_>) -> Result { e.validate_encode()?; e.cx.reset(); @@ -42,13 +42,7 @@ pub(crate) fn expand_insert_entry(e: Build<'_>) -> Result { let body = match &e.data { BuildData::Struct(st) => { - packed = crate::internals::packed( - &e, - st, - e.tokens.encode_t, - "IS_BITWISE_ENCODE", - Only::Encode, - ); + packed = crate::internals::packed(&e, st); encode_map(&cx, &e, st)? } BuildData::Enum(en) => { @@ -80,7 +74,7 @@ pub(crate) fn expand_insert_entry(e: Build<'_>) -> Result { attributes.push(syn::parse_quote!(#[allow(clippy::just_underscores_and_digits)])); } - let mode_ident = e.expansion.mode_path(&e.tokens); + let mode_ident = e.expansion.mode_path(e.tokens); Ok(quote! { const _: () = { @@ -119,7 +113,7 @@ pub(crate) fn expand_insert_entry(e: Build<'_>) -> Result { } /// Encode a struct. -fn encode_map(cx: &Ctxt<'_>, b: &Build<'_>, st: &Body<'_>) -> Result { +fn encode_map(cx: &Ctxt<'_>, b: &Build<'_, '_>, st: &Body<'_>) -> Result { let Ctxt { ctx_var, encoder_var, @@ -206,7 +200,7 @@ struct FieldTest<'st> { fn insert_fields<'st>( cx: &Ctxt<'_>, - b: &Build<'_>, + b: &Build<'_, '_>, st: &'st Body<'_>, pack_var: &syn::Ident, ) -> Result<(Vec, Vec>)> { @@ -330,7 +324,7 @@ fn insert_fields<'st>( } /// Encode an internally tagged enum. -fn encode_enum(cx: &Ctxt<'_>, b: &Build<'_>, en: &Enum<'_>) -> Result { +fn encode_enum(cx: &Ctxt<'_>, b: &Build<'_, '_>, en: &Enum<'_>) -> Result { let Ctxt { ctx_var, .. } = *cx; let Tokens { @@ -365,7 +359,7 @@ fn encode_enum(cx: &Ctxt<'_>, b: &Build<'_>, en: &Enum<'_>) -> Result, - b: &Build<'_>, + b: &Build<'_, '_>, en: &Enum<'_>, v: &Variant<'_>, ) -> Result<(syn::PatStruct, TokenStream)> { @@ -590,7 +584,7 @@ struct LengthTest { } impl LengthTest { - fn build(&self, b: &Build<'_>) -> (syn::Stmt, syn::Ident) { + fn build(&self, b: &Build<'_, '_>) -> (syn::Stmt, syn::Ident) { let Tokens { map_hint, .. } = b.tokens; match self.kind { diff --git a/crates/musli-macros/src/expander.rs b/crates/musli-macros/src/expander.rs index 1b503c61d..bb4dee192 100644 --- a/crates/musli-macros/src/expander.rs +++ b/crates/musli-macros/src/expander.rs @@ -6,7 +6,7 @@ use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned; use crate::internals::attr::{self, ModeIdent, ModeKind, TypeAttr}; -use crate::internals::{Build, Ctxt, Expansion, Mode, NameAll, Only, Result, Tokens}; +use crate::internals::{Build, Ctxt, Expansion, Mode, NameAll, Only, Parameters, Result, Tokens}; #[derive(Clone, Copy)] pub(crate) enum UnsizedMethod { @@ -234,7 +234,12 @@ impl<'a> Expander<'a> { self.cx.into_errors() } - fn setup_builds<'b>(&'b self, modes: &'b [ModeIdent], only: Only) -> Result>> { + fn setup_builds<'tok, 'b>( + &'b self, + modes: &'b [ModeIdent], + tokens: &'tok Tokens<'b>, + only: Only, + ) -> Result>> { let mut builds = Vec::new(); let mut missing = BTreeMap::new(); @@ -243,31 +248,109 @@ impl<'a> Expander<'a> { missing.insert(&default.kind, default); } + let (lt, lt_exists) = 'out: { + if let Some(lt) = self.input.generics.lifetimes().next() { + break 'out (lt.lifetime.clone(), true); + } + + (syn::Lifetime::new("'__de", Span::call_site()), false) + }; + + let (allocator_ident, allocator_exists) = 'out: { + for p in self.input.generics.type_params() { + if p.ident == "A" { + break 'out (p.ident.clone(), true); + } + } + + ( + self.cx.type_with_span_permanent("__A", Span::call_site()), + false, + ) + }; + + let p = Parameters { + lt, + lt_exists, + allocator_ident, + allocator_exists, + }; + for mode_ident in modes { missing.remove(&mode_ident.kind); + let expansion = Expansion { mode_ident }; + + let mode = expansion.as_mode(tokens, only); + let p = self.decorate(&p, &mode); + builds.push(crate::internals::build::setup( - self, - Expansion { mode_ident }, - only, + self, expansion, mode, tokens, p, )?); } for (_, mode_ident) in missing { + let expansion = Expansion { mode_ident }; + + let mode = expansion.as_mode(tokens, only); + let p = self.decorate(&p, &mode); + builds.push(crate::internals::build::setup( - self, - Expansion { mode_ident }, - only, + self, expansion, mode, tokens, p, )?); } Ok(builds) } + fn decorate(&self, p: &Parameters, mode: &Mode<'_>) -> Parameters { + let (lt, lt_exists) = 'out: { + let list = self.type_attr.decode_bounds_lifetimes(mode); + + if let [_, rest @ ..] = list { + for (span, _) in rest { + self.cx + .error_span(*span, "More than one decoder lifetime bound is specified"); + } + } + + if let Some((_, ty)) = list.first() { + break 'out (ty, false); + } + + (&p.lt, p.lt_exists) + }; + + let (allocator_ident, allocator_exists) = 'out: { + let list = self.type_attr.decode_bounds_types(mode); + + if let [_, rest @ ..] = list { + for (span, _) in rest { + self.cx + .error_span(*span, "More than one decoder allocator bound is specified"); + } + } + + if let Some((_, ty)) = list.first() { + break 'out (ty, false); + } + + (&p.allocator_ident, p.allocator_exists) + }; + + Parameters { + lt: lt.clone(), + lt_exists, + allocator_ident: allocator_ident.clone(), + allocator_exists, + } + } + /// Expand Encode implementation. pub(crate) fn expand_encode(&self) -> Result { let modes = self.cx.modes(); - let builds = self.setup_builds(&modes, Only::Encode)?; + let tokens = self.tokens(); + let builds = self.setup_builds(&modes, &tokens, Only::Encode)?; let mut out = TokenStream::new(); @@ -281,7 +364,8 @@ impl<'a> Expander<'a> { /// Expand Decode implementation. pub(crate) fn expand_decode(&self) -> Result { let modes = self.cx.modes(); - let builds = self.setup_builds(&modes, Only::Decode)?; + let tokens = self.tokens(); + let builds = self.setup_builds(&modes, &tokens, Only::Decode)?; let mut out = TokenStream::new(); @@ -298,7 +382,7 @@ pub(crate) trait Taggable { /// The span of the taggable item. fn span(&self) -> Span; /// The rename configuration the taggable item currently has. - fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)>; + fn name(&self, mode: &Mode<'_>) -> Option<&(Span, syn::Expr)>; /// The index of the taggable item. fn index(&self) -> usize; } @@ -306,7 +390,7 @@ pub(crate) trait Taggable { /// Expand the given configuration to the appropriate tag expression. pub(crate) fn expand_name( taggable: &dyn Taggable, - mode: Mode<'_>, + mode: &Mode<'_>, name_all: NameAll, ident: Option<&syn::Ident>, ) -> syn::Expr { @@ -341,7 +425,7 @@ impl Taggable for FieldData<'_> { self.span } - fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)> { + fn name(&self, mode: &Mode<'_>) -> Option<&(Span, syn::Expr)> { self.attr.name(mode) } @@ -355,7 +439,7 @@ impl Taggable for VariantData<'_> { self.span } - fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)> { + fn name(&self, mode: &Mode<'_>) -> Option<&(Span, syn::Expr)> { self.attr.name_expr(mode) } diff --git a/crates/musli-macros/src/internals/attr.rs b/crates/musli-macros/src/internals/attr.rs index 3264323ac..b2197d7e8 100644 --- a/crates/musli-macros/src/internals/attr.rs +++ b/crates/musli-macros/src/internals/attr.rs @@ -109,7 +109,7 @@ macro_rules! layer { } impl $attr { - fn by_mode(&self, mode: Mode<'_>, access: A) -> Option<&O> + fn by_mode(&self, mode: &Mode<'_>, access: A) -> Option<&O> where A: Copy + Fn(&$layer) -> Option<&O>, O: ?Sized, @@ -123,7 +123,7 @@ macro_rules! layer { $( #[allow(unused)] - pub(crate) fn $single(&self, mode: Mode<'_>) -> Option<&(Span, $single_ty)> { + pub(crate) fn $single(&self, mode: &Mode<'_>) -> Option<&(Span, $single_ty)> { self.by_mode(mode, |m| { match mode.only { Only::Encode if m.$single.encode.is_some() => m.$single.encode.as_ref(), @@ -136,7 +136,7 @@ macro_rules! layer { $($( #[allow(unused)] - pub(crate) fn $multiple(&self, mode: Mode<'_>) -> &[(Span, $multiple_ty)] { + pub(crate) fn $multiple(&self, mode: &Mode<'_>) -> &[(Span, $multiple_ty)] { self.by_mode(mode, |m| { match mode.only { Only::Encode if !m.$multiple.encode.is_empty() => Some(&m.$multiple.encode[..]), @@ -260,24 +260,28 @@ layer! { bounds: syn::WherePredicate, /// Bounds to require for a `Decode` implementation. decode_bounds: syn::WherePredicate, + /// Lifetimes specified. + decode_bounds_lifetimes: syn::Lifetime, + /// Types specified. + decode_bounds_types: syn::Ident, } } impl TypeAttr { - pub(crate) fn is_name_type_ambiguous(&self, mode: Mode<'_>) -> bool { + pub(crate) fn is_name_type_ambiguous(&self, mode: &Mode<'_>) -> bool { self.name_type(mode).is_none() && self.name_all(mode).is_none() && self.name_method(mode).is_none() } - pub(crate) fn enum_tagging_span(&self, mode: Mode<'_>) -> Option { + pub(crate) fn enum_tagging_span(&self, mode: &Mode<'_>) -> Option { let tag = self.tag_value(mode); let content = self.content_value(mode); Some(tag.or(content)?.0) } /// Indicates the state of enum tagging. - pub(crate) fn enum_tagging(&self, mode: Mode<'_>) -> Option> { + pub(crate) fn enum_tagging(&self, mode: &Mode<'_>) -> Option> { let (_, tag_value) = self.tag_value(mode)?; let default_tag_type = build::determine_type(tag_value); @@ -414,6 +418,14 @@ pub(crate) fn type_attrs(cx: &Ctxt, attrs: &[syn::Attribute]) -> TypeAttr { // #[musli(decode_bound = {..})] if meta.path.is_ident("decode_bound") { + if meta.input.parse::>()?.is_some() { + parse_bound_types( + &meta, + &mut new.decode_bounds_lifetimes, + &mut new.decode_bounds_types, + )?; + } + meta.input.parse::()?; parse_bounds(&meta, &mut new.decode_bounds)?; return Ok(()); @@ -487,6 +499,40 @@ fn parse_name_all(meta: &syn::meta::ParseNestedMeta<'_>) -> Result, + types: &mut Vec<(Span, syn::Ident)>, +) -> syn::Result<()> { + let mut first = true; + let mut last = false; + + while !meta.input.is_empty() && !meta.input.peek(Token![>]) { + if !first { + last |= meta.input.parse::>()?.is_none(); + } + + 'out: { + if let Some(lt) = meta.input.parse::>()? { + lifetimes.push((lt.span(), lt)); + break 'out; + } + + let ident = meta.input.parse::()?; + types.push((ident.span(), ident)); + } + + first = false; + + if last { + break; + } + } + + meta.input.parse::]>()?; + Ok(()) +} + fn parse_bounds( meta: &syn::meta::ParseNestedMeta, out: &mut Vec<(Span, syn::WherePredicate)>, @@ -528,7 +574,7 @@ layer! { } impl VariantAttr { - pub(crate) fn is_name_type_ambiguous(&self, mode: Mode<'_>) -> bool { + pub(crate) fn is_name_type_ambiguous(&self, mode: &Mode<'_>) -> bool { self.name_type(mode).is_none() && self.name_all(mode).is_none() && self.name_method(mode).is_none() @@ -675,7 +721,7 @@ impl Field { /// Expand encode of the given field. pub(crate) fn encode_path_expanded<'a>( &self, - mode: Mode<'a>, + mode: &Mode<'a>, span: Span, ) -> (Span, DefaultOrCustom<'a>) { if let Some((span, encode_path)) = self.encode_path(mode) { @@ -690,14 +736,15 @@ impl Field { /// Expand decode of the given field. pub(crate) fn decode_path_expanded<'a>( &self, - mode: Mode<'a>, + mode: &Mode<'a>, span: Span, + allocator_ident: &syn::Ident, ) -> (Span, DefaultOrCustom<'a>) { if let Some((span, decode_path)) = self.decode_path(mode) { (*span, DefaultOrCustom::Custom(decode_path.clone())) } else { let field_encoding = self.encoding(mode).map(|&(_, e)| e).unwrap_or_default(); - let decode_path = mode.decode_t_decode(field_encoding); + let decode_path = mode.decode_t_decode(field_encoding, allocator_ident); (span, DefaultOrCustom::Default(decode_path)) } } diff --git a/crates/musli-macros/src/internals/build.rs b/crates/musli-macros/src/internals/build.rs index 60c0d6068..189feeab1 100644 --- a/crates/musli-macros/src/internals/build.rs +++ b/crates/musli-macros/src/internals/build.rs @@ -14,12 +14,19 @@ use super::attr::{DefaultOrCustom, EnumTagging, FieldEncoding, ModeKind, Packing use super::mode::ImportedMethod; use super::name::NameAll; use super::ATTR; -use super::{Ctxt, Expansion, Mode, Only, Result, Tokens}; +use super::{Ctxt, Expansion, Mode, Result, Tokens}; -pub(crate) struct Build<'a> { +pub(crate) struct Parameters { + pub(crate) lt: syn::Lifetime, + pub(crate) lt_exists: bool, + pub(crate) allocator_ident: syn::Ident, + pub(crate) allocator_exists: bool, +} + +pub(crate) struct Build<'tok, 'a> { + pub(crate) mode: Mode<'a>, pub(crate) input: &'a syn::DeriveInput, pub(crate) cx: &'a Ctxt, - pub(crate) tokens: Tokens<'a>, pub(crate) bounds: &'a [(Span, syn::WherePredicate)], pub(crate) decode_bounds: &'a [(Span, syn::WherePredicate)], pub(crate) expansion: Expansion<'a>, @@ -27,9 +34,11 @@ pub(crate) struct Build<'a> { pub(crate) decode_t_decode: ImportedMethod<'a>, pub(crate) encode_t_encode: ImportedMethod<'a>, pub(crate) enum_tagging_span: Option, + pub(crate) tokens: &'tok Tokens<'a>, + pub(crate) p: Parameters, } -impl Build<'_> { +impl Build<'_, '_> { /// Emit diagnostics for when we try to implement `Decode` for an enum which /// is marked as `#[musli(transparent)]`. pub(crate) fn encode_transparent_enum_diagnostics(&self, span: Span) { @@ -156,17 +165,16 @@ pub(crate) struct Field<'a> { /// Setup a build. /// /// Handles mode decoding, and construction of parameters which might give rise to errors. -pub(crate) fn setup<'a>( +pub(crate) fn setup<'tok, 'a>( e: &'a Expander, expansion: Expansion<'a>, - only: Only, -) -> Result> { - let tokens = e.tokens(); - let mode = expansion.as_mode(&tokens, only); - + mode: Mode<'a>, + tokens: &'tok Tokens<'a>, + p: Parameters, +) -> Result> { let data = match &e.data { - Data::Struct(data) => BuildData::Struct(setup_struct(e, mode, data)), - Data::Enum(data) => BuildData::Enum(setup_enum(e, mode, data)), + Data::Struct(data) => BuildData::Struct(setup_struct(e, &mode, data, &p.allocator_ident)), + Data::Enum(data) => BuildData::Enum(setup_enum(e, &mode, data, &p.allocator_ident)), Data::Union => { e.cx.error_span(e.input.ident.span(), "musli: not supported for unions"); return Err(()); @@ -177,24 +185,35 @@ pub(crate) fn setup<'a>( return Err(()); } - let decode_t_decode = mode.decode_t_decode(FieldEncoding::Default); + let decode_t_decode = mode.decode_t_decode(FieldEncoding::Default, &p.allocator_ident); let encode_t_encode = mode.encode_t_encode(FieldEncoding::Default); + let bounds = e.type_attr.bounds(&mode); + let decode_bounds = e.type_attr.decode_bounds(&mode); + let enum_tagging_span = e.type_attr.enum_tagging_span(&mode); + Ok(Build { + mode, input: e.input, cx: &e.cx, - tokens, - bounds: e.type_attr.bounds(mode), - decode_bounds: e.type_attr.decode_bounds(mode), + bounds, + decode_bounds, expansion, data, decode_t_decode, encode_t_encode, - enum_tagging_span: e.type_attr.enum_tagging_span(mode), + enum_tagging_span, + tokens, + p, }) } -fn setup_struct<'a>(e: &'a Expander, mode: Mode<'a>, data: &'a StructData<'a>) -> Body<'a> { +fn setup_struct<'a>( + e: &'a Expander, + mode: &Mode<'a>, + data: &'a StructData<'a>, + allocator_ident: &syn::Ident, +) -> Body<'a> { let mut unskipped_fields = Vec::with_capacity(data.fields.len()); let mut all_fields = Vec::with_capacity(data.fields.len()); @@ -220,7 +239,15 @@ fn setup_struct<'a>(e: &'a Expander, mode: Mode<'a>, data: &'a StructData<'a>) - let path = syn::Path::from(syn::Ident::new("Self", e.input.ident.span())); for f in &data.fields { - let field = Rc::new(setup_field(e, mode, f, name_all, packing, None)); + let field = Rc::new(setup_field( + e, + mode, + f, + name_all, + packing, + None, + allocator_ident, + )); if field.skip.is_none() { unskipped_fields.push(field.clone()); @@ -248,7 +275,12 @@ fn setup_struct<'a>(e: &'a Expander, mode: Mode<'a>, data: &'a StructData<'a>) - body } -fn setup_enum<'a>(e: &'a Expander, mode: Mode<'a>, data: &'a EnumData<'a>) -> Enum<'a> { +fn setup_enum<'a>( + e: &'a Expander, + mode: &Mode<'a>, + data: &'a EnumData<'a>, + allocator_ident: &syn::Ident, +) -> Enum<'a> { let mut variants = Vec::with_capacity(data.variants.len()); let mut fallback = None; @@ -296,7 +328,7 @@ fn setup_enum<'a>(e: &'a Expander, mode: Mode<'a>, data: &'a EnumData<'a>) -> En ); for v in &data.variants { - variants.push(setup_variant(e, mode, v, &mut fallback)); + variants.push(setup_variant(e, mode, v, &mut fallback, allocator_ident)); } Enum { @@ -317,9 +349,10 @@ fn setup_enum<'a>(e: &'a Expander, mode: Mode<'a>, data: &'a EnumData<'a>) -> En fn setup_variant<'a>( e: &'a Expander<'_>, - mode: Mode<'a>, + mode: &Mode<'a>, data: &'a VariantData<'a>, fallback: &mut Option<&'a syn::Ident>, + allocator_ident: &syn::Ident, ) -> Variant<'a> { let mut unskipped_fields = Vec::with_capacity(data.fields.len()); let mut all_fields = Vec::with_capacity(data.fields.len()); @@ -384,6 +417,7 @@ fn setup_variant<'a>( name_all, variant_packing, Some(&mut patterns), + allocator_ident, )); if field.skip.is_none() { @@ -422,14 +456,17 @@ fn setup_variant<'a>( fn setup_field<'a>( e: &'a Expander, - mode: Mode<'a>, + mode: &Mode<'a>, data: &'a FieldData<'a>, name_all: NameAll, packing: Packing, patterns: Option<&mut Punctuated>, + allocator_ident: &syn::Ident, ) -> Field<'a> { let encode_path = data.attr.encode_path_expanded(mode, data.span); - let decode_path = data.attr.decode_path_expanded(mode, data.span); + let decode_path = data + .attr + .decode_path_expanded(mode, data.span, allocator_ident); let name = expander::expand_name(data, mode, name_all, data.ident); let pattern = data.attr.pattern(mode).map(|(_, p)| p); diff --git a/crates/musli-macros/src/internals/ctxt.rs b/crates/musli-macros/src/internals/ctxt.rs index 4f1b6b172..6a6626670 100644 --- a/crates/musli-macros/src/internals/ctxt.rs +++ b/crates/musli-macros/src/internals/ctxt.rs @@ -152,11 +152,22 @@ impl Ctxt { } /// Build a type identifier with a span. - pub(crate) fn type_with_span( - &self, - #[cfg_attr(not(feature = "verbose"), allow(unused))] name: N, - span: Span, - ) -> syn::Ident + pub(crate) fn type_with_span(&self, name: N, span: Span) -> syn::Ident + where + N: fmt::Display, + { + self.type_with_span_inner(name, span, false) + } + + /// Build a type identifier with a span. + pub(crate) fn type_with_span_permanent(&self, name: N, span: Span) -> syn::Ident + where + N: fmt::Display, + { + self.type_with_span_inner(name, span, true) + } + + fn type_with_span_inner(&self, name: N, span: Span, permanent: bool) -> syn::Ident where N: fmt::Display, { @@ -164,13 +175,22 @@ impl Ctxt { #[cfg(not(feature = "verbose"))] { - let index = inner.types; - inner.types += 1; - _ = write!(inner.b1, "T{index}"); + _ = name; + + let index; + + if permanent { + _ = write!(inner.b1, "{name}"); + } else { + index = inner.types; + inner.types += 1; + _ = write!(inner.b1, "T{index}"); + } } #[cfg(feature = "verbose")] { + _ = permanent; _ = write!(inner.b1, "{name}"); } diff --git a/crates/musli-macros/src/internals/mod.rs b/crates/musli-macros/src/internals/mod.rs index c7cbc5974..3c5e54e9c 100644 --- a/crates/musli-macros/src/internals/mod.rs +++ b/crates/musli-macros/src/internals/mod.rs @@ -11,7 +11,7 @@ mod tokens; pub(crate) const ATTR: &str = "musli"; pub(crate) use self::attr::Only; -pub(crate) use self::build::Build; +pub(crate) use self::build::{Build, Parameters}; pub(crate) use self::ctxt::Ctxt; pub(crate) use self::expansion::Expansion; pub(crate) use self::mode::{ImportedMethod, Mode}; diff --git a/crates/musli-macros/src/internals/mode.rs b/crates/musli-macros/src/internals/mode.rs index 8bc194df7..f41b4f638 100644 --- a/crates/musli-macros/src/internals/mode.rs +++ b/crates/musli-macros/src/internals/mode.rs @@ -32,24 +32,43 @@ impl ToTokens for ModePath<'_> { } } -pub(crate) struct ImportedMethod<'a>(Import<'a>, ModePath<'a>, &'static str); +pub(crate) struct Trait<'a> { + import: Import<'a>, + mode: ModePath<'a>, + allocator_ident: Option, +} -impl ToTokens for ImportedMethod<'_> { +impl ToTokens for Trait<'_> { #[inline] fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let ImportedMethod(import, mode_path, name) = *self; - - import.to_tokens(tokens); + self.import.to_tokens(tokens); ::default().to_tokens(tokens); ::default().to_tokens(tokens); - mode_path.to_tokens(tokens); + self.mode.to_tokens(tokens); + + if let Some(ident) = &self.allocator_ident { + ::default().to_tokens(tokens); + ident.to_tokens(tokens); + } + ]>::default().to_tokens(tokens); + } +} + +pub(crate) struct ImportedMethod<'a> { + trait_t: Trait<'a>, + method: &'static str, +} + +impl ToTokens for ImportedMethod<'_> { + #[inline] + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + self.trait_t.to_tokens(tokens); ::default().to_tokens(tokens); - tokens.extend([TokenTree::Ident(Ident::new(name, Span::call_site()))]); + tokens.extend([TokenTree::Ident(Ident::new(self.method, Span::call_site()))]); } } -#[derive(Clone, Copy)] pub(crate) struct Mode<'a> { pub(crate) kind: Option<&'a ModeKind>, pub(crate) mode_path: ModePath<'a>, @@ -74,11 +93,38 @@ impl<'a> Mode<'a> { FieldEncoding::Default => (self.encode_t, "encode"), }; - ImportedMethod(encode_t, self.mode_path, name) + ImportedMethod { + trait_t: Trait { + import: encode_t, + mode: self.mode_path, + allocator_ident: None, + }, + method: name, + } + } + + /// Get the fully expanded trait. + pub(crate) fn as_trait_t(&self, allocator_ident: &syn::Ident) -> Trait<'a> { + match self.only { + Only::Encode => Trait { + import: self.encode_t, + mode: self.mode_path, + allocator_ident: None, + }, + Only::Decode => Trait { + import: self.decode_t, + mode: self.mode_path, + allocator_ident: Some(allocator_ident.clone()), + }, + } } /// Construct a typed decode call. - pub(crate) fn decode_t_decode(&self, encoding: FieldEncoding) -> ImportedMethod<'a> { + pub(crate) fn decode_t_decode( + &self, + encoding: FieldEncoding, + allocator_ident: &syn::Ident, + ) -> ImportedMethod<'a> { let (decode_t, name) = match encoding { FieldEncoding::Packed => (self.decode_packed_t, "decode_packed"), FieldEncoding::Bytes => (self.decode_bytes_t, "decode_bytes"), @@ -86,6 +132,13 @@ impl<'a> Mode<'a> { FieldEncoding::Default => (self.decode_t, "decode"), }; - ImportedMethod(decode_t, self.mode_path, name) + ImportedMethod { + trait_t: Trait { + import: decode_t, + mode: self.mode_path, + allocator_ident: Some(allocator_ident.clone()), + }, + method: name, + } } } diff --git a/crates/musli-macros/src/internals/packed.rs b/crates/musli-macros/src/internals/packed.rs index 0978aaf92..528fb7b57 100644 --- a/crates/musli-macros/src/internals/packed.rs +++ b/crates/musli-macros/src/internals/packed.rs @@ -3,15 +3,9 @@ use quote::quote; use super::attr::Packing; use super::build::{Body, Build}; -use super::{Import, Only, Tokens}; +use super::{Only, Tokens}; -pub(crate) fn packed( - e: &Build<'_>, - st: &Body<'_>, - trait_t: Import<'_>, - packed_field: &str, - only: Only, -) -> syn::Expr { +pub(crate) fn packed(e: &Build<'_, '_>, st: &Body<'_>) -> syn::Expr { let Tokens { offset_of, size_of, @@ -19,15 +13,21 @@ pub(crate) fn packed( .. } = e.tokens; - let base = match only { - Only::Encode => st.all_fields.iter().all(|f| f.encode_path.1.is_default()), - Only::Decode => st.all_fields.iter().all(|f| f.decode_path.1.is_default()), + let (base, packed_field) = match e.mode.only { + Only::Encode => ( + st.all_fields.iter().all(|f| f.encode_path.1.is_default()), + "IS_BITWISE_ENCODE", + ), + Only::Decode => ( + st.all_fields.iter().all(|f| f.decode_path.1.is_default()), + "IS_BITWISE_DECODE", + ), }; match st.packing { Packing::Packed if base && st.all_fields.len() == st.unskipped_fields.len() => { let packed_field = syn::Ident::new(packed_field, Span::call_site()); - let mode_ident = e.expansion.mode_path(&e.tokens); + let trait_t = e.mode.as_trait_t(&e.p.allocator_ident); let mut offsets = Vec::with_capacity(st.all_fields.len().saturating_sub(1)); let mut sizes = Vec::with_capacity(st.all_fields.len()); @@ -53,7 +53,7 @@ pub(crate) fn packed( for f in &st.all_fields { let ty = &f.ty; sizes.push(quote!(#size_of::<#ty>())); - packed.push(quote!(<#ty as #trait_t<#mode_ident>>::#packed_field)); + packed.push(quote!(<#ty as #trait_t>::#packed_field)); } syn::parse_quote! { diff --git a/crates/musli-macros/src/internals/tokens.rs b/crates/musli-macros/src/internals/tokens.rs index 0e1eb9a12..6951085c1 100644 --- a/crates/musli-macros/src/internals/tokens.rs +++ b/crates/musli-macros/src/internals/tokens.rs @@ -18,7 +18,9 @@ impl ToTokens for Import<'_> { } } +#[derive(Clone)] pub(crate) struct Tokens<'a> { + pub(crate) allocator_t: Import<'a>, pub(crate) as_decoder_t: Import<'a>, pub(crate) context_t: Import<'a>, pub(crate) decode_bytes_t: Import<'a>, @@ -57,6 +59,7 @@ pub(crate) struct Tokens<'a> { impl<'a> Tokens<'a> { pub(crate) fn new(prefix: &'a syn::Path) -> Self { Self { + allocator_t: Import(prefix, "Allocator"), as_decoder_t: Import(prefix, "AsDecoder"), context_t: Import(prefix, "Context"), decode_bytes_t: Import(prefix, "DecodeBytes"), diff --git a/crates/musli/help/derives.md b/crates/musli/help/derives.md index 7b2290424..00ef9e8ce 100644 --- a/crates/musli/help/derives.md +++ b/crates/musli/help/derives.md @@ -475,7 +475,7 @@ through heuristics. Such a type must also implement [`Decode`] (for `"sized"`),
-#### `#[musli(bound = {..})]` and `#[musli(decode_bound = {..})]` +#### `#[musli(bound = {..})]` and `#[musli(decode_bound<'de, A> = {..})]` These attributes can be used to apply bounds to an [`Encode`] or [`Decode`] implementation. @@ -484,9 +484,14 @@ These are necessary to use when a generic container is used to ensure that the given parameter implements the necessary bounds. `#[musli(bound = {..})]` applies to all implementations while -`#[musli(decode_bound = {..})]` only applies to the [`Decode`] -implementation. The latter allows for using the decode lifetime parameter -(which defaults to `'de`). +`#[musli(decode_bound<'de, A> = {..})]` only applies to the [`Decode`] +implementation. The latter allows for using the decode lifetime and allocator +parameter. If these parameters are not part of the type signature, they can be +specified in the `decode_bound` parameter directly like +`#[musli(decode_bound<'de, A> = {..})]`. + +An HRTB can also be used like `#[musli(decode_bound = {T: for<'de> +Decode<'de, Binary, A>})]`.
@@ -497,8 +502,8 @@ use musli::{Decode, Encode}; use musli::mode::{Binary, Text}; #[derive(Clone, Debug, PartialEq, Encode, Decode)] -#[musli(mode = Binary, bound = {T: Encode}, decode_bound = {T: Decode<'de, Binary>})] -#[musli(mode = Text, bound = {T: Encode}, decode_bound = {T: Decode<'de, Text>})] +#[musli(mode = Binary, bound = {T: Encode}, decode_bound
= {T: for<'de> Decode<'de, Binary, A>})] +#[musli(mode = Text, bound = {T: Encode}, decode_bound = {T: for<'de> Decode<'de, Text, A>})] pub struct GenericWithBound { value: T, } diff --git a/crates/musli/src/alloc/default.rs b/crates/musli/src/alloc/default.rs index 59e9fd02b..7ee87f1bf 100644 --- a/crates/musli/src/alloc/default.rs +++ b/crates/musli/src/alloc/default.rs @@ -1,6 +1,8 @@ use core::marker::PhantomData; -use super::{Allocator, RawVec}; +use crate::Allocator; + +use super::RawVec; #[cfg(not(feature = "alloc"))] use super::{Slice, SliceBuf}; #[cfg(feature = "alloc")] diff --git a/crates/musli/src/alloc/disabled.rs b/crates/musli/src/alloc/disabled.rs index b03099d40..3d4fc42dc 100644 --- a/crates/musli/src/alloc/disabled.rs +++ b/crates/musli/src/alloc/disabled.rs @@ -1,7 +1,9 @@ use core::marker::PhantomData; use core::ptr; -use super::{Allocator, RawVec}; +use crate::Allocator; + +use super::RawVec; /// An empty buffer. pub struct EmptyBuf { diff --git a/crates/musli/src/alloc/stack.rs b/crates/musli/src/alloc/stack.rs index 72a8a3b4f..f44e71735 100644 --- a/crates/musli/src/alloc/stack.rs +++ b/crates/musli/src/alloc/stack.rs @@ -8,7 +8,8 @@ use core::num::NonZeroU16; use core::ops::{Deref, DerefMut}; use core::ptr; -use super::{Allocator, RawVec}; +use super::RawVec; +use crate::Allocator; // We keep max bytes to 2^31, since that ensures that addition between two // magnitutes never overflow. diff --git a/crates/musli/src/alloc/string.rs b/crates/musli/src/alloc/string.rs index 01cec8eb9..fe08811f7 100644 --- a/crates/musli/src/alloc/string.rs +++ b/crates/musli/src/alloc/string.rs @@ -3,8 +3,9 @@ use core::ops::Deref; use core::str; use crate::fixed::CapacityError; +use crate::Allocator; -use super::{AllocError, Allocator, Vec}; +use super::{AllocError, Vec}; /// Wrapper around a buffer that is guaranteed to be a valid utf-8 string. pub struct String diff --git a/crates/musli/src/alloc/system.rs b/crates/musli/src/alloc/system.rs index 6a01229f8..ea43ca340 100644 --- a/crates/musli/src/alloc/system.rs +++ b/crates/musli/src/alloc/system.rs @@ -5,7 +5,9 @@ use core::ptr::NonNull; use rust_alloc::alloc; -use super::{Allocator, RawVec}; +use crate::Allocator; + +use super::RawVec; /// System buffer that can be used in combination with an [`Allocator`]. /// diff --git a/crates/musli/src/alloc/vec.rs b/crates/musli/src/alloc/vec.rs index a74a6813f..a70c20c57 100644 --- a/crates/musli/src/alloc/vec.rs +++ b/crates/musli/src/alloc/vec.rs @@ -5,7 +5,9 @@ use core::ops::{Deref, DerefMut}; use core::ptr; use core::slice; -use super::{Allocator, RawVec}; +use crate::Allocator; + +use super::RawVec; /// A vector backed by an [`Allocator`]. pub struct Vec diff --git a/crates/musli/src/compat.rs b/crates/musli/src/compat.rs index 0960b52b4..736c464bd 100644 --- a/crates/musli/src/compat.rs +++ b/crates/musli/src/compat.rs @@ -8,6 +8,7 @@ use crate::de::{Decode, DecodeBytes, DecodePacked, Decoder}; use crate::en::{Encode, EncodeBytes, EncodePacked, Encoder}; use crate::hint::SequenceHint; use crate::mode::{Binary, Text}; +use crate::Allocator; /// Ensures that the given value `T` is encoded as a sequence. /// @@ -46,13 +47,16 @@ impl Encode for Sequence<()> { } } -impl<'de, M> Decode<'de, M> for Sequence<()> { +impl<'de, M, A> Decode<'de, M, A> for Sequence<()> +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = true; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de>, + D: Decoder<'de, Allocator = A>, { decoder.decode_sequence(|_| Ok(Self(()))) } @@ -75,20 +79,21 @@ impl<'de, M> Decode<'de, M> for Sequence<()> { /// # Examples /// /// ``` -/// use musli::{Decode, Decoder}; +/// use musli::{Allocator, Decode, Decoder}; /// use musli::compat::Bytes; /// /// struct Struct { /// field: Vec, /// } /// -/// impl<'de, M> Decode<'de, M> for Struct +/// impl<'de, M, A> Decode<'de, M, A> for Struct /// where -/// Bytes>: Decode<'de, M> +/// A: Allocator, +/// Bytes>: Decode<'de, M, A> /// { /// fn decode(decoder: D) -> Result /// where -/// D: Decoder<'de, Mode = M>, +/// D: Decoder<'de, Mode = M, Allocator = A>, /// { /// let Bytes(field) = Decode::decode(decoder)?; /// @@ -100,8 +105,8 @@ impl<'de, M> Decode<'de, M> for Sequence<()> { /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] #[musli(crate, transparent)] -#[musli(mode = Binary, bound = {T: EncodeBytes}, decode_bound = {T: DecodeBytes<'de, Binary>})] -#[musli(mode = Text, bound = {T: EncodeBytes}, decode_bound = {T: DecodeBytes<'de, Text>})] +#[musli(mode = Binary, bound = {T: EncodeBytes}, decode_bound = {T: for<'de> DecodeBytes<'de, Binary, A>})] +#[musli(mode = Text, bound = {T: EncodeBytes}, decode_bound = {T: for<'de> DecodeBytes<'de, Text, A>})] #[repr(transparent)] pub struct Bytes(#[musli(bytes)] pub T); @@ -140,7 +145,7 @@ where /// # Examples /// /// ``` -/// use musli::{Decode, Decoder}; +/// use musli::{Allocator, Decode, Decoder}; /// use musli::compat::Packed; /// /// struct Struct { @@ -148,13 +153,14 @@ where /// field2: u32, /// } /// -/// impl<'de, M> Decode<'de, M> for Struct +/// impl<'de, M, A> Decode<'de, M, A> for Struct /// where -/// Packed<(u8, u32)>: Decode<'de, M> +/// A: Allocator, +/// Packed<(u8, u32)>: Decode<'de, M, A> /// { /// fn decode(decoder: D) -> Result /// where -/// D: Decoder<'de, Mode = M>, +/// D: Decoder<'de, Mode = M, Allocator = A>, /// { /// let Packed((field, field2)) = Decode::decode(decoder)?; /// @@ -167,7 +173,7 @@ where /// ``` #[derive(Encode, Decode)] #[musli(crate, transparent)] -#[musli(mode = Binary, bound = {T: EncodePacked}, decode_bound = {T: DecodePacked<'de, Binary>})] -#[musli(mode = Text, bound = {T: EncodePacked}, decode_bound = {T: DecodePacked<'de, Text>})] +#[musli(mode = Binary, bound = {T: EncodePacked}, decode_bound = {T: for<'de> DecodePacked<'de, Binary, A>})] +#[musli(mode = Text, bound = {T: EncodePacked}, decode_bound = {T: for<'de> DecodePacked<'de, Text, A>})] #[repr(transparent)] pub struct Packed(#[musli(packed)] pub T); diff --git a/crates/musli/src/context/capture.rs b/crates/musli/src/context/capture.rs index 8010285ca..b9cb49003 100644 --- a/crates/musli/src/context/capture.rs +++ b/crates/musli/src/context/capture.rs @@ -5,8 +5,8 @@ use core::marker::PhantomData; #[cfg(feature = "alloc")] use crate::alloc::System; -use crate::alloc::{self, Allocator, String}; -use crate::Context; +use crate::alloc::{self, String}; +use crate::{Allocator, Context}; use super::{ContextError, ErrorMarker}; diff --git a/crates/musli/src/context/context_error.rs b/crates/musli/src/context/context_error.rs index 62894a11e..c59536888 100644 --- a/crates/musli/src/context/context_error.rs +++ b/crates/musli/src/context/context_error.rs @@ -9,7 +9,7 @@ use core::error::Error; use core::fmt; #[cfg(any(feature = "alloc", feature = "std"))] -use crate::alloc::Allocator; +use crate::Allocator; #[cfg(feature = "alloc")] use rust_alloc::string::{String, ToString}; diff --git a/crates/musli/src/context/default_context.rs b/crates/musli/src/context/default_context.rs index d43f73e5a..c173c6e51 100644 --- a/crates/musli/src/context/default_context.rs +++ b/crates/musli/src/context/default_context.rs @@ -9,8 +9,8 @@ use core::slice; #[cfg(feature = "alloc")] use crate::alloc::System; -use crate::alloc::{self, Allocator, String, Vec}; -use crate::Context; +use crate::alloc::{self, String, Vec}; +use crate::{Allocator, Context}; use super::{Access, ErrorMarker, Shared}; diff --git a/crates/musli/src/context/error_marker.rs b/crates/musli/src/context/error_marker.rs index a6baf6c92..3e788b59a 100644 --- a/crates/musli/src/context/error_marker.rs +++ b/crates/musli/src/context/error_marker.rs @@ -22,7 +22,7 @@ impl core::error::Error for ErrorMarker {} #[cfg(test)] impl crate::context::ContextError for ErrorMarker where - A: crate::alloc::Allocator, + A: crate::Allocator, { #[inline] fn custom(_: A, _: T) -> Self diff --git a/crates/musli/src/context/ignore.rs b/crates/musli/src/context/ignore.rs index 7c5ecca7e..0f8c27033 100644 --- a/crates/musli/src/context/ignore.rs +++ b/crates/musli/src/context/ignore.rs @@ -4,10 +4,10 @@ use core::marker::PhantomData; #[cfg(feature = "alloc")] use crate::alloc::System; -use crate::alloc::{self, Allocator, String}; +use crate::alloc::{self, String}; #[cfg(test)] use crate::mode::Binary; -use crate::Context; +use crate::{Allocator, Context}; use super::ErrorMarker; diff --git a/crates/musli/src/context/mod.rs b/crates/musli/src/context/mod.rs index 9deba2c7b..de7e810c4 100644 --- a/crates/musli/src/context/mod.rs +++ b/crates/musli/src/context/mod.rs @@ -29,9 +29,9 @@ mod ignore; #[doc(inline)] pub use self::ignore::Ignore; -use crate::alloc::Allocator; #[cfg(feature = "alloc")] use crate::alloc::System; +use crate::Allocator; /// Construct a new default context using the provided allocator. /// diff --git a/crates/musli/src/context/same.rs b/crates/musli/src/context/same.rs index 046cb9230..21ecbcfa3 100644 --- a/crates/musli/src/context/same.rs +++ b/crates/musli/src/context/same.rs @@ -4,10 +4,10 @@ use core::marker::PhantomData; #[cfg(feature = "alloc")] use crate::alloc::System; -use crate::alloc::{self, Allocator, String}; +use crate::alloc::{self, String}; #[cfg(test)] use crate::mode::Binary; -use crate::Context; +use crate::{Allocator, Context}; use super::ContextError; #[cfg(test)] diff --git a/crates/musli/src/descriptive/de.rs b/crates/musli/src/descriptive/de.rs index 0dbb25976..5f6c9ae58 100644 --- a/crates/musli/src/descriptive/de.rs +++ b/crates/musli/src/descriptive/de.rs @@ -222,6 +222,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = SelfDecoder where diff --git a/crates/musli/src/descriptive/tag.rs b/crates/musli/src/descriptive/tag.rs index bf01b0fc1..f7cadf21b 100644 --- a/crates/musli/src/descriptive/tag.rs +++ b/crates/musli/src/descriptive/tag.rs @@ -5,7 +5,7 @@ use core::fmt; use core::mem; -use crate::{Decode, Decoder}; +use crate::{Allocator, Decode, Decoder}; /// Variant corresponding to marks. #[derive(Debug)] @@ -266,14 +266,17 @@ impl fmt::Debug for Tag { } } -impl<'de, M> Decode<'de, M> for Tag { +impl<'de, M, A> Decode<'de, M, A> for Tag +where + A: Allocator, +{ // Every bit pattern is valid for a tag. const IS_BITWISE_DECODE: bool = true; #[inline] fn decode(decoder: D) -> Result where - D: Decoder<'de, Mode = M>, + D: Decoder<'de, Mode = M, Allocator = A>, { Ok(Self::from_byte(decoder.decode_u8()?)) } diff --git a/crates/musli/src/json/de/key_decoder.rs b/crates/musli/src/json/de/key_decoder.rs index 5f14e2558..e4907865a 100644 --- a/crates/musli/src/json/de/key_decoder.rs +++ b/crates/musli/src/json/de/key_decoder.rs @@ -47,6 +47,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = JsonKeyDecoder where diff --git a/crates/musli/src/json/de/mod.rs b/crates/musli/src/json/de/mod.rs index acbfe5276..e91d319fc 100644 --- a/crates/musli/src/json/de/mod.rs +++ b/crates/musli/src/json/de/mod.rs @@ -109,6 +109,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = JsonDecoder where diff --git a/crates/musli/src/json/encoding.rs b/crates/musli/src/json/encoding.rs index cdf41fce1..6ebe7679f 100644 --- a/crates/musli/src/json/encoding.rs +++ b/crates/musli/src/json/encoding.rs @@ -90,7 +90,7 @@ where #[inline] pub fn from_str<'de, T>(string: &'de str) -> Result where - T: Decode<'de, Text>, + T: Decode<'de, Text, System>, { DEFAULT.from_str(string) } diff --git a/crates/musli/src/json/parser/string.rs b/crates/musli/src/json/parser/string.rs index ed3e42f62..e9355d9d6 100644 --- a/crates/musli/src/json/parser/string.rs +++ b/crates/musli/src/json/parser/string.rs @@ -1,7 +1,7 @@ #![allow(clippy::zero_prefixed_literal)] -use crate::alloc::{Allocator, Vec}; -use crate::Context; +use crate::alloc::Vec; +use crate::{Allocator, Context}; // Copied and adapter form the serde-json project under the MIT and Apache 2.0 // license. diff --git a/crates/musli/src/lib.rs b/crates/musli/src/lib.rs index 1ac81574c..2de3d9f81 100644 --- a/crates/musli/src/lib.rs +++ b/crates/musli/src/lib.rs @@ -359,6 +359,7 @@ //! We achieve this through the following methods: //! //! ``` +//! use musli::alloc::System; //! use musli::context::{ErrorMarker as Error, Ignore}; //! use musli::options::{self, Float, Integer, Width, Options}; //! use musli::storage::Encoding; @@ -383,7 +384,7 @@ //! #[inline] //! pub fn decode<'buf, T>(buf: &'buf [u8], alloc: &Slice<'_>) -> Result //! where -//! T: Decode<'buf, Packed>, +//! T: Decode<'buf, Packed, System>, //! { //! let cx = Ignore::with_alloc(alloc); //! ENCODING.from_slice_with(&cx, buf) @@ -680,6 +681,8 @@ pub use musli_core::{Context, Decode, Decoder, Encode, Encoder}; pub use musli_core::__priv; pub mod alloc; +#[doc(inline)] +pub use self::alloc::Allocator; pub mod descriptive; pub mod json; @@ -716,6 +719,7 @@ pub mod no_std; mod int; mod str; +use crate::alloc::System; use crate::mode::Binary; /// Test if the given type `T` is marked with the `#[musli(packed)]` attribute, @@ -733,7 +737,8 @@ where } /// Test if the given type `T` is marked with the `#[musli(packed)]` attribute, -/// and is bitwise encodeable in the [`Binary`] mode. +/// and is bitwise encodeable in the [`Binary`] mode using the [`System`] +/// allocator. /// /// See the [help section for `#[musli(packed)]`][help] for more information. /// @@ -741,7 +746,7 @@ where #[inline] pub const fn is_bitwise_decode() -> bool where - T: for<'de> Decode<'de, Binary>, + T: for<'de> Decode<'de, Binary, System>, { T::IS_BITWISE_DECODE } diff --git a/crates/musli/src/macros/internal.rs b/crates/musli/src/macros/internal.rs index 48834c318..42ed27a57 100644 --- a/crates/musli/src/macros/internal.rs +++ b/crates/musli/src/macros/internal.rs @@ -238,7 +238,7 @@ macro_rules! bare_encoding { pub fn decode<'de, R, T>(reader: R) -> Result where R: $reader_trait<'de>, - T: Decode<'de, $mode>, + T: Decode<'de, $mode, System>, { $default.decode(reader) } @@ -274,7 +274,7 @@ macro_rules! bare_encoding { #[inline] pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result where - T: Decode<'de, $mode>, + T: Decode<'de, $mode, System>, { $default.from_slice(bytes) } @@ -553,7 +553,7 @@ macro_rules! encoding_impls { pub fn decode<'de, R, T>(self, reader: R) -> Result where R: $reader_trait<'de>, - T: Decode<'de, $mode>, + T: Decode<'de, $mode, System>, { let cx = $crate::context::Same::with_alloc(System::new()); self.decode_with(&cx, reader) @@ -592,7 +592,7 @@ macro_rules! encoding_impls { #[inline] pub fn from_slice<'de, T>(self, bytes: &'de [u8]) -> Result where - T: Decode<'de, $mode>, + T: Decode<'de, $mode, System>, { let cx = $crate::context::Same::with_alloc(System::new()); self.from_slice_with(&cx, bytes) @@ -608,7 +608,7 @@ macro_rules! encoding_impls { #[inline] pub fn from_str<'de, T>(self, string: &'de str) -> Result where - T: Decode<'de, M>, + T: Decode<'de, M, System>, { self.from_slice(string.as_bytes()) } @@ -918,7 +918,7 @@ macro_rules! encoding_impls { where C: Context, R: $reader_trait<'de>, - T: Decode<'de, C::Mode>, + T: Decode<'de, C::Mode, C::Allocator>, { cx.clear(); let reader = $reader_trait::$into_reader(reader); @@ -966,7 +966,7 @@ macro_rules! encoding_impls { pub fn from_slice_with<'de, C, T>(self, cx: C, bytes: &'de [u8]) -> Result where C: Context, - T: Decode<'de, $mode>, + T: Decode<'de, $mode, C::Allocator>, { self.decode_with(cx, bytes) } @@ -985,7 +985,7 @@ macro_rules! encoding_impls { pub fn from_str_with<'de, C, T>(self, cx: C, string: &'de str) -> Result where C: Context, - T: Decode<'de, M>, + T: Decode<'de, M, C::Allocator>, { self.from_slice_with(cx, string.as_bytes()) } @@ -1001,7 +1001,7 @@ macro_rules! implement_error { #[cfg(feature = "alloc")] pub struct $id where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { err: Impl, } @@ -1010,14 +1010,14 @@ macro_rules! implement_error { #[cfg(not(feature = "alloc"))] pub struct $id where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { err: Impl, } impl core::fmt::Display for $id where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -1027,7 +1027,7 @@ macro_rules! implement_error { impl core::fmt::Debug for $id where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -1037,7 +1037,7 @@ macro_rules! implement_error { enum Impl where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { Message(crate::alloc::String), Alloc(crate::alloc::AllocError), @@ -1045,7 +1045,7 @@ macro_rules! implement_error { impl core::fmt::Display for Impl where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -1058,7 +1058,7 @@ macro_rules! implement_error { impl core::fmt::Debug for Impl where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -1075,13 +1075,13 @@ macro_rules! implement_error { impl core::error::Error for $id where - A: $crate::alloc::Allocator + A: $crate::Allocator { } impl $crate::context::ContextError for $id where - A: $crate::alloc::Allocator, + A: $crate::Allocator, { #[inline] fn custom(alloc: A, error: T) -> Self diff --git a/crates/musli/src/macros/mod.rs b/crates/musli/src/macros/mod.rs index fde5fb1dd..f6951b3d1 100644 --- a/crates/musli/src/macros/mod.rs +++ b/crates/musli/src/macros/mod.rs @@ -25,7 +25,9 @@ pub(crate) use self::internal::{bare_encoding, encoding_impls, implement_error}; ) ))] mod test; +#[cfg(all(feature = "test", feature = "alloc"))] +pub use self::test::support; #[cfg(feature = "test")] -pub use self::test::{__test_extra, __test_matrix, assert_decode_eq, assert_roundtrip_eq, support}; +pub use self::test::{__test_extra, __test_matrix, assert_decode_eq, assert_roundtrip_eq}; #[cfg(feature = "test")] pub(crate) use self::test::{test_fns, test_include_if}; diff --git a/crates/musli/src/macros/test.rs b/crates/musli/src/macros/test.rs index 21974dade..68b3734f2 100644 --- a/crates/musli/src/macros/test.rs +++ b/crates/musli/src/macros/test.rs @@ -13,9 +13,10 @@ macro_rules! test_fns { /// Roundtrip encode the given value. #[doc(hidden)] #[track_caller] + #[cfg(feature = "alloc")] pub fn rt(value: T) -> T where - T: $crate::en::Encode + $crate::de::DecodeOwned, + T: $crate::en::Encode + $crate::de::DecodeOwned, T: ::core::fmt::Debug + ::core::cmp::PartialEq, M: 'static, { @@ -44,64 +45,63 @@ macro_rules! test_fns { } } - $crate::alloc::default(|alloc| { - let mut cx = $crate::context::with_alloc(alloc); - cx.include_type(); + let mut cx = $crate::context::with_alloc($crate::alloc::System::new()); + cx.include_type(); - let out = match encoding.to_vec_with(&cx, &value) { - Ok(out) => out, + let out = match encoding.to_vec_with(&cx, &value) { + Ok(out) => out, + Err(..) => { + let error = cx.report(); + panic!("{WHAT}: {}: failed to encode:\n{error}", type_name::()) + } + }; + + let decoded: T = match encoding.from_slice_with(&cx, out.as_slice()) { + Ok(decoded) => decoded, + Err(..) => { + let out = FormatBytes(&out); + let error = cx.report(); + panic!("{WHAT}: {}: failed to decode:\nValue: {value:?}\nBytes: {out}\n{error}", type_name::()) + } + }; + + assert_eq!(decoded, value, "{WHAT}: {}: roundtrip does not match\nValue: {value:?}", type_name::()); + + $crate::macros::test_include_if! { + $($(#[$option])*)* => + let value_decode: $crate::value::Value = match encoding.from_slice_with(&cx, out.as_slice()) { + Ok(decoded) => decoded, Err(..) => { + let out = FormatBytes(&out); let error = cx.report(); - panic!("{WHAT}: {}: failed to encode:\n{error}", type_name::()) + panic!("{WHAT}: {}: failed to decode to value type:\nValue: {value:?}\nBytes:{out}\n{error}", type_name::()) } }; - let decoded: T = match encoding.from_slice_with(&cx, out.as_slice()) { + let value_decoded: T = match $crate::value::decode_with(&cx, &value_decode) { Ok(decoded) => decoded, Err(..) => { let out = FormatBytes(&out); let error = cx.report(); - panic!("{WHAT}: {}: failed to decode:\nValue: {value:?}\nBytes: {out}\n{error}", type_name::()) + panic!("{WHAT}: {}: failed to decode from value type:\nValue: {value:?}\nBytes: {out}\nBuffered value: {value_decode:?}\n{error}", type_name::()) } }; - assert_eq!(decoded, value, "{WHAT}: {}: roundtrip does not match\nValue: {value:?}", type_name::()); - - $crate::macros::test_include_if! { - $($(#[$option])*)* => - let value_decode: $crate::value::Value = match encoding.from_slice_with(&cx, out.as_slice()) { - Ok(decoded) => decoded, - Err(..) => { - let out = FormatBytes(&out); - let error = cx.report(); - panic!("{WHAT}: {}: failed to decode to value type:\nValue: {value:?}\nBytes:{out}\n{error}", type_name::()) - } - }; - - let value_decoded: T = match $crate::value::decode_with(&cx, &value_decode) { - Ok(decoded) => decoded, - Err(..) => { - let out = FormatBytes(&out); - let error = cx.report(); - panic!("{WHAT}: {}: failed to decode from value type:\nValue: {value:?}\nBytes: {out}\nBuffered value: {value_decode:?}\n{error}", type_name::()) - } - }; - - assert_eq!(value_decoded, value, "{WHAT}: {}: musli-value roundtrip does not match\nValue: {value:?}", type_name::()); - } + assert_eq!(value_decoded, value, "{WHAT}: {}: musli-value roundtrip does not match\nValue: {value:?}", type_name::()); + } - decoded - }) + decoded } /// Encode and then decode the given value once. #[doc(hidden)] #[track_caller] + #[cfg(feature = "alloc")] pub fn decode<'de, T, U, M>(value: T, out: &'de mut rust_alloc::vec::Vec, expected: &U) -> U where T: $crate::en::Encode, T: ::core::fmt::Debug + ::core::cmp::PartialEq, - U: $crate::de::Decode<'de, M>, + U: $crate::de::Decode<'de, M, $crate::alloc::System>, U: ::core::fmt::Debug + ::core::cmp::PartialEq, M: 'static, { @@ -130,43 +130,42 @@ macro_rules! test_fns { } } - $crate::alloc::default(|alloc| { - let mut cx = $crate::context::with_alloc(alloc); - cx.include_type(); + let mut cx = $crate::context::with_alloc($crate::alloc::System::new()); + cx.include_type(); - out.clear(); + out.clear(); - match encoding.to_writer_with(&cx, &mut *out, &value) { - Ok(()) => (), - Err(..) => { - let error = cx.report(); - panic!("{WHAT}: {}: failed to encode:\n{error}", type_name::()) - } - }; - - let actual = match encoding.from_slice_with(&cx, &*out) { - Ok(decoded) => decoded, - Err(..) => { - let out = FormatBytes(&*out); - let error = cx.report(); - panic!("{WHAT}: {}: failed to decode:\nValue: {value:?}\nBytes: {out}\n{error}", type_name::()) - } - }; + match encoding.to_writer_with(&cx, &mut *out, &value) { + Ok(()) => (), + Err(..) => { + let error = cx.report(); + panic!("{WHAT}: {}: failed to encode:\n{error}", type_name::()) + } + }; + + let actual = match encoding.from_slice_with(&cx, &*out) { + Ok(decoded) => decoded, + Err(..) => { + let out = FormatBytes(&*out); + let error = cx.report(); + panic!("{WHAT}: {}: failed to decode:\nValue: {value:?}\nBytes: {out}\n{error}", type_name::()) + } + }; - assert_eq!( - actual, - *expected, - "{WHAT}: decoded value does not match expected\nBytes: {}", - FormatBytes(&*out), - ); + assert_eq!( + actual, + *expected, + "{WHAT}: decoded value does not match expected\nBytes: {}", + FormatBytes(&*out), + ); - actual - }) + actual } /// Encode a value to bytes. #[doc(hidden)] #[track_caller] + #[cfg(feature = "alloc")] pub fn to_vec(value: T) -> rust_alloc::vec::Vec where T: $crate::en::Encode, @@ -435,9 +434,11 @@ macro_rules! __test_matrix { pub use __test_matrix; #[doc(hidden)] +#[cfg(feature = "alloc")] pub mod support { pub use rust_alloc::vec::Vec; + use crate::alloc::System; use crate::mode::Binary; use crate::value::{self, Value}; use crate::{Decode, Encode}; @@ -445,7 +446,7 @@ pub mod support { #[track_caller] pub fn musli_value_rt(expected: T) where - T: Encode + for<'de> Decode<'de, Binary>, + T: Encode + for<'de> Decode<'de, Binary, System>, T: PartialEq + core::fmt::Debug, { let value: Value = value::encode(&expected).expect("value: Encoding should succeed"); diff --git a/crates/musli/src/storage/de.rs b/crates/musli/src/storage/de.rs index f31158feb..4bf93cec3 100644 --- a/crates/musli/src/storage/de.rs +++ b/crates/musli/src/storage/de.rs @@ -56,6 +56,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = StorageDecoder where @@ -88,7 +89,7 @@ where #[inline] fn try_fast_decode(mut self) -> Result, Self::Error> where - T: Decode<'de, Self::Mode>, + T: Decode<'de, Self::Mode, Self::Allocator>, { if !const { is_native_fixed::() && T::IS_BITWISE_DECODE } { return Ok(TryFastDecode::Unsupported(self)); @@ -294,7 +295,7 @@ where fn decode_slice(mut self) -> Result::Error> where V: DecodeSliceBuilder, - T: Decode<'de, Self::Mode>, + T: Decode<'de, Self::Mode, Self::Allocator>, { // Check that the type is packed inside of the slice. if !is_bitwise_slice!(OPT, T) { diff --git a/crates/musli/src/value/de.rs b/crates/musli/src/value/de.rs index 0519ac51d..e4b003922 100644 --- a/crates/musli/src/value/de.rs +++ b/crates/musli/src/value/de.rs @@ -87,6 +87,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = ValueDecoder<'de, OPT, U> where diff --git a/crates/musli/src/value/error.rs b/crates/musli/src/value/error.rs index fe64a834b..4493a0183 100644 --- a/crates/musli/src/value/error.rs +++ b/crates/musli/src/value/error.rs @@ -5,8 +5,8 @@ use rust_alloc::boxed::Box; #[cfg(feature = "alloc")] use rust_alloc::string::ToString; -use crate::alloc::Allocator; use crate::context::ContextError; +use crate::Allocator; use super::type_hint::{NumberHint, TypeHint}; diff --git a/crates/musli/src/value/mod.rs b/crates/musli/src/value/mod.rs index 7cd528e22..73fb65a6c 100644 --- a/crates/musli/src/value/mod.rs +++ b/crates/musli/src/value/mod.rs @@ -23,6 +23,8 @@ pub use self::value::{AsValueDecoder, Value}; pub use error::Error; use crate::alloc; +#[cfg(feature = "alloc")] +use crate::alloc::System; use crate::mode::Binary; use crate::value::en::ValueEncoder; use crate::{Decode, Encode, Options}; @@ -46,16 +48,15 @@ where } /// Decode a [Value] into a type which implements [Decode]. +#[cfg(feature = "alloc")] pub fn decode<'de, T>(value: &'de Value) -> Result where - T: Decode<'de, Binary>, + T: Decode<'de, Binary, System>, { use crate::de::Decoder; - alloc::default(|alloc| { - let cx = crate::context::Same::::with_alloc(alloc); - value.decoder::(&cx).decode() - }) + let cx = crate::context::Same::::with_alloc(System::new()); + value.decoder::(&cx).decode() } /// Decode a [Value] into a type which implements [Decode] using a custom @@ -63,7 +64,7 @@ where pub fn decode_with<'de, C, T>(cx: C, value: &'de Value) -> Result where C: crate::Context, - T: Decode<'de, C::Mode>, + T: Decode<'de, C::Mode, C::Allocator>, { use crate::de::Decoder; diff --git a/crates/musli/src/value/value.rs b/crates/musli/src/value/value.rs index 4686021a8..73901aa5d 100644 --- a/crates/musli/src/value/value.rs +++ b/crates/musli/src/value/value.rs @@ -15,7 +15,7 @@ use crate::de::{ use crate::en::{Encode, Encoder}; #[cfg(feature = "alloc")] use crate::en::{MapEncoder, SequenceEncoder, VariantEncoder}; -use crate::{Context, Options}; +use crate::{Allocator, Context, Options}; use super::de::ValueDecoder; use super::type_hint::{NumberHint, TypeHint}; @@ -377,7 +377,10 @@ where } } -impl<'de, M> Decode<'de, M> for Value { +impl<'de, M, A> Decode<'de, M, A> for Value +where + A: Allocator, +{ const IS_BITWISE_DECODE: bool = false; #[inline] diff --git a/crates/musli/src/wire/de.rs b/crates/musli/src/wire/de.rs index bc11ecd7c..93c05308a 100644 --- a/crates/musli/src/wire/de.rs +++ b/crates/musli/src/wire/de.rs @@ -209,6 +209,7 @@ where type Cx = C; type Error = C::Error; type Mode = C::Mode; + type Allocator = C::Allocator; type WithContext = WireDecoder where diff --git a/crates/musli/src/writer.rs b/crates/musli/src/writer.rs index d8e5af526..b98dbb385 100644 --- a/crates/musli/src/writer.rs +++ b/crates/musli/src/writer.rs @@ -9,8 +9,8 @@ pub use self::slice_mut_writer::SliceMutWriter; use core::fmt; -use crate::alloc::{Allocator, Vec}; -use crate::Context; +use crate::alloc::Vec; +use crate::{Allocator, Context}; mod sealed { use super::Writer; diff --git a/crates/musli/tests/generic_bounds.rs b/crates/musli/tests/generic_bounds.rs index 5403780cb..2d74d8da4 100644 --- a/crates/musli/tests/generic_bounds.rs +++ b/crates/musli/tests/generic_bounds.rs @@ -2,8 +2,8 @@ use musli::mode::{Binary, Text}; use musli::{Decode, Encode}; #[derive(Clone, Debug, PartialEq, Encode, Decode)] -#[musli(mode = Binary, bound = {T: Encode}, decode_bound = {T: Decode<'de, Binary>})] -#[musli(mode = Text, bound = {T: Encode}, decode_bound = {T: Decode<'de, Text>})] +#[musli(mode = Binary, bound = {T: Encode}, decode_bound = {T: for<'de> Decode<'de, Binary, A>})] +#[musli(mode = Text, bound = {T: Encode}, decode_bound = {T: for<'de> Decode<'de, Text, A>})] pub struct GenericWithBound { value: T, } diff --git a/crates/musli/tests/recursive_models.rs b/crates/musli/tests/recursive_models.rs index aa948c736..1675b71c9 100644 --- a/crates/musli/tests/recursive_models.rs +++ b/crates/musli/tests/recursive_models.rs @@ -10,6 +10,7 @@ //! = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_models`) //! ``` +use musli::alloc::System; use musli::de::DecodeOwned; use musli::mode::Binary; use musli::{Decode, Encode}; @@ -23,7 +24,7 @@ where pub(crate) fn decode(buf: &[u8]) -> musli::storage::Result where - T: DecodeOwned, + T: DecodeOwned, { musli::storage::from_slice(buf) } diff --git a/crates/musli/tests/serde_compat.rs b/crates/musli/tests/serde_compat.rs index 29df056e6..1d4597622 100644 --- a/crates/musli/tests/serde_compat.rs +++ b/crates/musli/tests/serde_compat.rs @@ -27,6 +27,8 @@ where T: DeserializeOwned; mod value { + use musli::alloc::System; + use super::*; #[track_caller] @@ -36,7 +38,7 @@ mod value { + fmt::Debug + Generate + Encode - + DecodeOwned + + DecodeOwned + Serialize + DeserializeOwned, { @@ -46,7 +48,12 @@ mod value { #[track_caller] pub(super) fn guided(module: &str, value: fn(&mut Rng) -> T) where - T: Eq + fmt::Debug + Encode + DecodeOwned + Serialize + DeserializeOwned, + T: Eq + + fmt::Debug + + Encode + + DecodeOwned + + Serialize + + DeserializeOwned, { macro_rules! do_try { ($expr:expr, $msg:expr) => { @@ -100,12 +107,14 @@ mod value { macro_rules! tester { ($module:ident, $mode:ty $(,)?) => { mod $module { + use musli::alloc::System; + use super::*; #[track_caller] pub(super) fn random(module: &str) where - T: Encode<$mode> + DecodeOwned<$mode>, + T: Encode<$mode> + DecodeOwned<$mode, System>, T: Eq + fmt::Debug + Generate + Serialize + DeserializeOwned, { guided(module, ::generate); @@ -114,7 +123,7 @@ macro_rules! tester { #[track_caller] pub(super) fn guided(module: &str, value: fn(&mut Rng) -> T) where - T: Encode<$mode> + DecodeOwned<$mode>, + T: Encode<$mode> + DecodeOwned<$mode, System>, T: Eq + fmt::Debug + Serialize + DeserializeOwned, { macro_rules! do_try { @@ -210,8 +219,8 @@ struct Struct { #[derive(Debug, PartialEq, Eq, Generate, Encode, Decode, Serialize, Deserialize)] #[generate(crate)] -#[musli(mode = Binary, bound = {T: Encode}, decode_bound = {T: Decode<'de, Binary>})] -#[musli(mode = Text, bound = {T: Encode}, decode_bound = {T: Decode<'de, Text>})] +#[musli(mode = Binary, bound = {T: Encode}, decode_bound = {T: for<'de> Decode<'de, Binary, A>})] +#[musli(mode = Text, bound = {T: Encode}, decode_bound = {T: for<'de> Decode<'de, Text, A>})] struct StructWith { a: u32, b: T, diff --git a/crates/musli/tests/skip_compat.rs b/crates/musli/tests/skip_compat.rs index bb1e44810..8e5c77ed3 100644 --- a/crates/musli/tests/skip_compat.rs +++ b/crates/musli/tests/skip_compat.rs @@ -28,8 +28,8 @@ pub enum OtherEnum { } #[derive(Debug, PartialEq, Encode, Decode)] -#[musli(mode = Binary, bound = {M: Encode}, decode_bound = {M: Decode<'de, Binary>})] -#[musli(mode = Text, bound = {M: Encode}, decode_bound = {M: Decode<'de, Text>})] +#[musli(mode = Binary, bound = {M: Encode}, decode_bound = {M: for<'de> Decode<'de, Binary, A>})] +#[musli(mode = Text, bound = {M: Encode}, decode_bound = {M: for<'de> Decode<'de, Text, A>})] pub struct SimpleStructFrom where M: Generate, diff --git a/crates/musli/tests/visitors.rs b/crates/musli/tests/visitors.rs index d1f82009d..fb9fb0fc8 100644 --- a/crates/musli/tests/visitors.rs +++ b/crates/musli/tests/visitors.rs @@ -1,14 +1,17 @@ use std::fmt; use musli::de::UnsizedVisitor; -use musli::{Context, Decode, Decoder}; +use musli::{Allocator, Context, Decode, Decoder}; #[derive(Debug, PartialEq)] pub struct BytesReference<'de> { data: &'de [u8], } -impl<'de, M> Decode<'de, M> for BytesReference<'de> { +impl<'de, M, A> Decode<'de, M, A> for BytesReference<'de> +where + A: Allocator, +{ #[inline] fn decode(decoder: D) -> Result where @@ -65,7 +68,10 @@ pub struct StringReference<'de> { data: &'de str, } -impl<'de, M> Decode<'de, M> for StringReference<'de> { +impl<'de, M, A> Decode<'de, M, A> for StringReference<'de> +where + A: Allocator, +{ #[inline] fn decode(decoder: D) -> Result where @@ -121,7 +127,10 @@ pub enum OwnedFn { B, } -impl<'de, M> Decode<'de, M> for OwnedFn { +impl<'de, M, A> Decode<'de, M, A> for OwnedFn +where + A: Allocator, +{ fn decode(decoder: D) -> Result where D: Decoder<'de>, diff --git a/tests/src/utils/musli.rs b/tests/src/utils/musli.rs index da1b7d6ad..efdf3cf40 100644 --- a/tests/src/utils/musli.rs +++ b/tests/src/utils/musli.rs @@ -3,6 +3,7 @@ pub mod musli_json { use alloc::vec::Vec; + use musli::alloc::System; use musli::json::Encoding; use musli::json::Error; use musli::mode::Text; @@ -28,7 +29,7 @@ pub mod musli_json { pub fn decode<'buf, T>(buffer: &'buf [u8]) -> Result where - T: Decode<'buf, Text>, + T: Decode<'buf, Text, System>, { ENCODING.from_slice(buffer) } @@ -40,6 +41,7 @@ pub mod musli_packed { use alloc::vec; use alloc::vec::Vec; + use musli::alloc::System; use musli::context::{ErrorMarker as Error, Ignore}; use musli::options::{self, Options}; use musli::storage::Encoding; @@ -67,7 +69,7 @@ pub mod musli_packed { pub fn decode<'buf, T>(buf: &'buf [u8]) -> Result where - T: Decode<'buf, Packed>, + T: Decode<'buf, Packed, System>, { let cx = Ignore::new(); ENCODING.from_slice_with(&cx, buf) @@ -79,6 +81,7 @@ pub mod musli_packed { pub mod musli_storage { use alloc::vec::Vec; + use musli::alloc::System; use musli::mode::Binary; use musli::options::{self, Options}; use musli::storage::{Encoding, Error}; @@ -105,7 +108,7 @@ pub mod musli_storage { pub fn decode<'buf, T>(buf: &'buf [u8]) -> Result where - T: Decode<'buf, Binary>, + T: Decode<'buf, Binary, System>, { ENCODING.from_slice(buf) } @@ -116,6 +119,7 @@ pub mod musli_storage { pub mod musli_wire { use alloc::vec::Vec; + use musli::alloc::System; use musli::mode::Binary; use musli::wire::Encoding; use musli::wire::Error; @@ -141,7 +145,7 @@ pub mod musli_wire { pub fn decode<'buf, T>(buf: &'buf [u8]) -> Result where - T: Decode<'buf, Binary>, + T: Decode<'buf, Binary, System>, { ENCODING.from_slice(buf) } @@ -152,6 +156,7 @@ pub mod musli_wire { pub mod musli_descriptive { use alloc::vec::Vec; + use musli::alloc::System; use musli::descriptive::Encoding; use musli::descriptive::Error; use musli::mode::Binary; @@ -177,7 +182,7 @@ pub mod musli_descriptive { pub fn decode<'buf, T>(buf: &'buf [u8]) -> Result where - T: Decode<'buf, Binary>, + T: Decode<'buf, Binary, System>, { ENCODING.from_slice(buf) } @@ -186,6 +191,7 @@ pub mod musli_descriptive { #[cfg(feature = "musli-value")] #[crate::benchmarker(as_bytes_disabled)] pub mod musli_value { + use musli::alloc::System; use musli::mode::Binary; use musli::value::Value; use musli::{Decode, Encode}; @@ -199,7 +205,7 @@ pub mod musli_value { pub fn decode(buf: &Value) -> Result where - for<'a> T: Decode<'a, Binary>, + for<'a> T: Decode<'a, Binary, System>, { musli::value::decode(buf) }