diff --git a/crates/musli-descriptive/src/de.rs b/crates/musli-descriptive/src/de.rs index 9dfa5ca6d..81cb45b65 100644 --- a/crates/musli-descriptive/src/de.rs +++ b/crates/musli-descriptive/src/de.rs @@ -5,9 +5,9 @@ use core::mem::take; use alloc::vec::Vec; use musli::de::{ - Decode, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, NumberHint, NumberVisitor, - PackDecoder, SequenceDecoder, SizeHint, Skip, StructDecoder, StructFieldDecoder, - StructFieldsDecoder, TupleDecoder, TypeHint, ValueVisitor, VariantDecoder, Visit, Visitor, + Decode, DecodeUnsized, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, NumberHint, + NumberVisitor, PackDecoder, SequenceDecoder, SizeHint, Skip, StructDecoder, StructFieldDecoder, + StructFieldsDecoder, TupleDecoder, TypeHint, ValueVisitor, VariantDecoder, Visitor, }; use musli::hint::{StructHint, TupleHint, UnsizedStructHint}; use musli::Context; @@ -292,12 +292,12 @@ where } #[inline] - fn visit(self, f: F) -> Result + fn decode_unsized(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, F: FnOnce(&T) -> Result, { - self.cx.visit(self, f) + self.cx.decode_unsized(self, f) } #[inline] diff --git a/crates/musli-json/src/de/key_decoder.rs b/crates/musli-json/src/de/key_decoder.rs index 631bd4f36..f9ddc2173 100644 --- a/crates/musli-json/src/de/key_decoder.rs +++ b/crates/musli-json/src/de/key_decoder.rs @@ -1,7 +1,7 @@ use core::fmt; use musli::de::{ - Decode, Decoder, NumberHint, SizeHint, Skip, TypeHint, ValueVisitor, Visit, Visitor, + Decode, DecodeUnsized, Decoder, NumberHint, SizeHint, Skip, TypeHint, ValueVisitor, Visitor, }; use musli::Context; @@ -80,12 +80,12 @@ where } #[inline] - fn visit(self, f: F) -> Result + fn decode_unsized(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, F: FnOnce(&T) -> Result, { - self.cx.visit(self, f) + self.cx.decode_unsized(self, f) } #[inline] diff --git a/crates/musli-json/src/de/mod.rs b/crates/musli-json/src/de/mod.rs index 897054796..55b9490b2 100644 --- a/crates/musli-json/src/de/mod.rs +++ b/crates/musli-json/src/de/mod.rs @@ -26,8 +26,8 @@ use core::str; use alloc::vec::Vec; use musli::de::{ - Decode, Decoder, NumberHint, NumberVisitor, SequenceDecoder, SizeHint, Skip, TypeHint, - ValueVisitor, Visit, Visitor, + Decode, DecodeUnsized, Decoder, NumberHint, NumberVisitor, SequenceDecoder, SizeHint, Skip, + TypeHint, ValueVisitor, Visitor, }; use musli::hint::{StructHint, TupleHint, UnsizedStructHint}; use musli::Context; @@ -155,12 +155,12 @@ where } #[inline] - fn visit(self, f: F) -> Result + fn decode_unsized(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, F: FnOnce(&T) -> Result, { - self.cx.visit(self, f) + self.cx.decode_unsized(self, f) } #[inline] diff --git a/crates/musli-macros/src/de.rs b/crates/musli-macros/src/de.rs index 9c8998703..53d3d2f82 100644 --- a/crates/musli-macros/src/de.rs +++ b/crates/musli-macros/src/de.rs @@ -194,7 +194,19 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { let name_type; match en.name_method { - NameMethod::Visit => { + NameMethod::Value => { + for v in &en.variants { + variant_output_tags.push((v, v.name.clone(), v.name.clone())); + } + + let decode_t_decode = &e.decode_t_decode; + + decode_tag = quote!(#decode_t_decode(#ctx_var, #variant_decoder_var)?); + output_enum = None; + fallback = quote!(_ => #fallback); + name_type = en.name_type.clone(); + } + NameMethod::Unsized(method) => { let mut tag_variants = Vec::new(); let output_type = e.cx.type_with_span("VariantTag", en.span); @@ -209,9 +221,10 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { let arms = tag_variants.iter().map(|o| o.as_arm(option_some)); let visit_type = &en.name_type; + let method = method.as_method_name(); decode_tag = quote! { - #decoder_t::visit(#variant_decoder_var, |#value_var: &#visit_type| { + #decoder_t::#method(#variant_decoder_var, |#value_var: &#visit_type| { #result_ok(match #value_var { #(#arms,)* _ => #option_none, @@ -256,18 +269,6 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { fallback = quote!(#option_none => { #fallback }); name_type = syn::parse_quote!(#option<#output_type>); } - NameMethod::Value => { - for v in &en.variants { - variant_output_tags.push((v, v.name.clone(), v.name.clone())); - } - - let decode_t_decode = &e.decode_t_decode; - - decode_tag = quote!(#decode_t_decode(#ctx_var, #variant_decoder_var)?); - output_enum = None; - fallback = quote!(_ => #fallback); - name_type = en.name_type.clone(); - } } let Some(enum_tagging) = en.enum_tagging else { @@ -395,7 +396,7 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { } }; } - NameMethod::Visit => { + NameMethod::Unsized(method) => { outcome_enum = Some(quote! { enum #outcome_type { Tag, Skip } }); @@ -407,9 +408,10 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { }); let visit_type = &en.name_type; + let method = method.as_method_name(); let decode_outcome = quote! { - #decoder_t::visit(#field_name_var, |#value_var: &#visit_type| { + #decoder_t::#method(#field_name_var, |#value_var: &#visit_type| { #result_ok(match #value_var { #field_tag => #outcome_type::Tag, #value_var => { @@ -532,7 +534,36 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { let decode_match; match en.name_method { - NameMethod::Visit => { + NameMethod::Value => { + field_alloc = None; + + decode_match = quote! { + match #decode_t_decode(#ctx_var, decoder)? { + #tag => { + let #variant_decoder_var = #struct_field_decoder_t::decode_field_value(#entry_var)?; + #tag_var = #option_some(#decode_tag); + } + #content => { + let #option_some(#variant_tag_var) = #tag_var else { + return #result_err(#context_t::invalid_field_tag(#ctx_var, #type_name, &#tag)); + }; + + let #body_decoder_var = #struct_field_decoder_t::decode_field_value(#entry_var)?; + + break #result_ok(match #variant_tag_var { + #(#patterns,)* + #fallback + }); + } + #field_var => { + if #skip_field(#entry_var)? { + return #result_err(#context_t::invalid_field_tag(#ctx_var, #type_name, &#field_var)); + } + } + } + }; + } + NameMethod::Unsized(method) => { outcome_enum = quote! { enum #outcome_type { Tag, Content, Skip } }; @@ -544,9 +575,10 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { }); let visit_type = &en.name_type; + let method = method.as_method_name(); decode_match = quote! { - let outcome = #decoder_t::visit(#field_name_var, |#value_var: &#visit_type| { + let outcome = #decoder_t::#method(#field_name_var, |#value_var: &#visit_type| { #result_ok(match #value_var { #tag => #outcome_type::Tag, #content => #outcome_type::Content, @@ -585,35 +617,6 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result { } }; } - NameMethod::Value => { - field_alloc = None; - - decode_match = quote! { - match #decode_t_decode(#ctx_var, decoder)? { - #tag => { - let #variant_decoder_var = #struct_field_decoder_t::decode_field_value(#entry_var)?; - #tag_var = #option_some(#decode_tag); - } - #content => { - let #option_some(#variant_tag_var) = #tag_var else { - return #result_err(#context_t::invalid_field_tag(#ctx_var, #type_name, &#tag)); - }; - - let #body_decoder_var = #struct_field_decoder_t::decode_field_value(#entry_var)?; - - break #result_ok(match #variant_tag_var { - #(#patterns,)* - #fallback - }); - } - #field_var => { - if #skip_field(#entry_var)? { - return #result_err(#context_t::invalid_field_tag(#ctx_var, #type_name, &#field_var)); - } - } - } - }; - } }; let enter = cx.trace.then(|| { @@ -859,7 +862,7 @@ fn decode_tagged( name_type = st.name_type.clone(); } - NameMethod::Visit => { + NameMethod::Unsized(method) => { let mut outputs = Vec::new(); let output_type = e.cx.type_with_span("TagVisitorOutput", e.input.ident.span()); @@ -904,9 +907,10 @@ fn decode_tagged( }); let visit_type = &st.name_type; + let method = method.as_method_name(); decode_tag = quote! { - #decoder_t::visit(#struct_decoder_var, |#value_var: &#visit_type| { + #decoder_t::#method(#struct_decoder_var, |#value_var: &#visit_type| { #result_ok(match #value_var { #(#patterns,)* #value_var => { diff --git a/crates/musli-macros/src/expander.rs b/crates/musli-macros/src/expander.rs index 0ed44dc2a..babfc5210 100644 --- a/crates/musli-macros/src/expander.rs +++ b/crates/musli-macros/src/expander.rs @@ -7,13 +7,29 @@ use crate::internals::name::NameAll; use crate::internals::tokens::Tokens; use crate::internals::{Ctxt, Expansion, Mode, Only, Result}; -#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy)] +pub(crate) enum UnsizedMethod { + Default, + Bytes, +} + +impl UnsizedMethod { + /// Get corresponding decoder method name to use. + pub(crate) fn as_method_name(&self) -> syn::Ident { + match self { + Self::Default => syn::Ident::new("decode_unsized", Span::call_site()), + Self::Bytes => syn::Ident::new("decode_unsized_bytes", Span::call_site()), + } + } +} + +#[derive(Default, Clone, Copy)] pub(crate) enum NameMethod { - /// Load the tag by visit. - Visit, /// Load the tag by value. #[default] Value, + /// Load the tag by visit. + Unsized(UnsizedMethod), } pub(crate) struct FieldData<'a> { diff --git a/crates/musli-macros/src/internals/build.rs b/crates/musli-macros/src/internals/build.rs index 6fe6e8734..8bfd2d8c8 100644 --- a/crates/musli-macros/src/internals/build.rs +++ b/crates/musli-macros/src/internals/build.rs @@ -6,7 +6,7 @@ use syn::Token; use crate::de::{build_call, build_reference}; use crate::expander::{ - self, Data, EnumData, Expander, FieldData, NameMethod, StructData, VariantData, + self, Data, EnumData, Expander, FieldData, NameMethod, StructData, UnsizedMethod, VariantData, }; use super::attr::{EnumTagging, Packing}; @@ -135,7 +135,7 @@ impl Body<'_> { pub(crate) fn name_local_type(&self) -> syn::Type { match self.name_method { - NameMethod::Visit => syn::Type::Reference(syn::TypeReference { + NameMethod::Unsized(..) => syn::Type::Reference(syn::TypeReference { and_token: ::default(), lifetime: None, mutability: None, @@ -169,7 +169,7 @@ impl Enum<'_> { pub(crate) fn name_local_type(&self) -> syn::Type { match self.name_method { - NameMethod::Visit => syn::Type::Reference(syn::TypeReference { + NameMethod::Unsized(..) => syn::Type::Reference(syn::TypeReference { and_token: ::default(), lifetime: None, mutability: None, @@ -546,14 +546,21 @@ fn split_name( fn determine_name_method(ty: &syn::Type) -> (NameMethod, Option) { match ty { - syn::Type::Path(syn::TypePath { qself: None, path }) => { - if path.is_ident("str") { - return (NameMethod::Visit, Some(NameAll::Name)); - } - } - syn::Type::Slice(..) => { - return (NameMethod::Visit, None); + syn::Type::Path(syn::TypePath { qself: None, path }) if path.is_ident("str") => { + return ( + NameMethod::Unsized(UnsizedMethod::Default), + Some(NameAll::Name), + ); } + syn::Type::Slice(syn::TypeSlice { elem, .. }) => match &**elem { + syn::Type::Path(syn::TypePath { qself: None, path }) if path.is_ident("u8") => { + return ( + NameMethod::Unsized(UnsizedMethod::Bytes), + Some(NameAll::Name), + ); + } + _ => {} + }, _ => {} } diff --git a/crates/musli-macros/src/internals/name.rs b/crates/musli-macros/src/internals/name.rs index 64919313d..4144ccc29 100644 --- a/crates/musli-macros/src/internals/name.rs +++ b/crates/musli-macros/src/internals/name.rs @@ -1,7 +1,7 @@ use core::fmt; use core::mem::take; -use crate::expander::NameMethod; +use crate::expander::{NameMethod, UnsizedMethod}; #[derive(Default, Debug, Clone, Copy)] #[allow(clippy::enum_variant_names)] @@ -41,7 +41,7 @@ impl NameAll { pub(crate) fn name_method(&self) -> NameMethod { match self { NameAll::Index => NameMethod::Value, - _ => NameMethod::Visit, + _ => NameMethod::Unsized(UnsizedMethod::Default), } } diff --git a/crates/musli-macros/src/types.rs b/crates/musli-macros/src/types.rs index 03d8a7760..d13c281a3 100644 --- a/crates/musli-macros/src/types.rs +++ b/crates/musli-macros/src/types.rs @@ -30,7 +30,8 @@ pub(super) enum Extra { pub(crate) enum Fn { Decode, - Visit, + DecodeUnsized, + DecodeUnsizedBytes, } pub(super) const ENCODER_TYPES: &[(&str, Extra)] = &[ @@ -66,7 +67,11 @@ pub(super) const DECODER_TYPES: &[(&str, Extra)] = &[ ("DecodeVariant", Extra::None), ]; -pub(super) const DECODER_FNS: &[(&str, Fn)] = &[("decode", Fn::Decode), ("visit", Fn::Visit)]; +pub(super) const DECODER_FNS: &[(&str, Fn)] = &[ + ("decode", Fn::Decode), + ("decode_unsized", Fn::DecodeUnsized), + ("decode_unsized_bytes", Fn::DecodeUnsizedBytes), +]; pub(super) const VISITOR_TYPES: &[(&str, Extra)] = &[ ("String", Extra::Visitor(Ty::Str)), @@ -233,15 +238,27 @@ impl Types { } })); } - Fn::Visit => { + Fn::DecodeUnsized => { + self.item_impl.items.push(syn::ImplItem::Verbatim(quote::quote! { + #[inline(always)] + fn decode_unsized(self, f: F) -> Result + where + T: ?Sized + #crate_path::de::DecodeUnsized<'de, Self::Mode>, + F: FnOnce(&T) -> Result::Error> + { + self.cx.decode_unsized(self, f) + } + })); + } + Fn::DecodeUnsizedBytes => { self.item_impl.items.push(syn::ImplItem::Verbatim(quote::quote! { #[inline(always)] - fn visit(self, f: F) -> Result + fn decode_unsized_bytes(self, f: F) -> Result where - T: ?Sized + #crate_path::de::Visit<'de, Self::Mode>, + T: ?Sized + #crate_path::de::DecodeUnsizedBytes<'de, Self::Mode>, F: FnOnce(&T) -> Result::Error> { - self.cx.visit(self, f) + self.cx.decode_unsized_bytes(self, f) } })); } diff --git a/crates/musli-storage/src/de.rs b/crates/musli-storage/src/de.rs index 78e1a0ae3..6bb820d75 100644 --- a/crates/musli-storage/src/de.rs +++ b/crates/musli-storage/src/de.rs @@ -4,9 +4,9 @@ use core::fmt; use alloc::vec::Vec; use musli::de::{ - Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, PackDecoder, SequenceDecoder, - SizeHint, StructDecoder, StructFieldDecoder, StructFieldsDecoder, TupleDecoder, ValueVisitor, - VariantDecoder, Visit, + DecodeUnsized, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, PackDecoder, + SequenceDecoder, SizeHint, StructDecoder, StructFieldDecoder, StructFieldsDecoder, + TupleDecoder, ValueVisitor, VariantDecoder, }; use musli::hint::{StructHint, TupleHint}; use musli::{Context, Decode}; @@ -83,12 +83,12 @@ where } #[inline] - fn visit(self, f: F) -> Result + fn decode_unsized(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, F: FnOnce(&T) -> Result, { - self.cx.visit(self, f) + self.cx.decode_unsized(self, f) } #[inline] diff --git a/crates/musli-value/src/de.rs b/crates/musli-value/src/de.rs index 93ef3af6a..0908b5fd5 100644 --- a/crates/musli-value/src/de.rs +++ b/crates/musli-value/src/de.rs @@ -4,9 +4,9 @@ use core::slice; #[cfg(feature = "alloc")] use musli::de::ValueVisitor; use musli::de::{ - AsDecoder, Decode, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, NumberHint, - PackDecoder, SequenceDecoder, SizeHint, Skip, StructDecoder, StructFieldDecoder, - StructFieldsDecoder, TupleDecoder, TypeHint, VariantDecoder, Visit, Visitor, + AsDecoder, Decode, DecodeUnsized, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, + NumberHint, PackDecoder, SequenceDecoder, SizeHint, Skip, StructDecoder, StructFieldDecoder, + StructFieldsDecoder, TupleDecoder, TypeHint, VariantDecoder, Visitor, }; #[cfg(feature = "alloc")] use musli::hint::{StructHint, TupleHint, UnsizedStructHint}; @@ -91,12 +91,12 @@ impl<'a, 'de, C: ?Sized + Context, const OPT: Options> Decoder<'de> } #[inline] - fn visit(self, f: F) -> Result + fn decode_unsized(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, F: FnOnce(&T) -> Result, { - self.cx.visit(self, f) + self.cx.decode_unsized(self, f) } #[inline] diff --git a/crates/musli-wire/src/de.rs b/crates/musli-wire/src/de.rs index 83b040334..c8e533d00 100644 --- a/crates/musli-wire/src/de.rs +++ b/crates/musli-wire/src/de.rs @@ -5,9 +5,9 @@ use core::mem::take; use alloc::vec::Vec; use musli::de::{ - Decode, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, PackDecoder, SequenceDecoder, - SizeHint, Skip, StructDecoder, StructFieldDecoder, StructFieldsDecoder, TupleDecoder, - ValueVisitor, VariantDecoder, Visit, + Decode, DecodeUnsized, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, PackDecoder, + SequenceDecoder, SizeHint, Skip, StructDecoder, StructFieldDecoder, StructFieldsDecoder, + TupleDecoder, ValueVisitor, VariantDecoder, }; use musli::hint::{StructHint, TupleHint}; use musli::Context; @@ -261,12 +261,12 @@ where } #[inline] - fn visit(self, f: F) -> Result + fn decode_unsized(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, F: FnOnce(&T) -> Result, { - self.cx.visit(self, f) + self.cx.decode_unsized(self, f) } #[inline] diff --git a/crates/musli/src/context.rs b/crates/musli/src/context.rs index 7f2964852..894081d33 100644 --- a/crates/musli/src/context.rs +++ b/crates/musli/src/context.rs @@ -3,7 +3,7 @@ use core::fmt; use core::str; -use crate::de::{DecodeBytes, Visit}; +use crate::de::{DecodeBytes, DecodeUnsized, DecodeUnsizedBytes}; use crate::{Buf, Decode, Decoder}; #[cfg(feature = "std")] @@ -45,15 +45,15 @@ pub trait Context { T::decode(self, decoder) } - /// Decode the given visit using the associated mode. + /// Decode the given unsized value using the associated mode. #[inline] - fn visit<'de, T, D, F, O>(&self, decoder: D, f: F) -> Result + fn decode_unsized<'de, T, D, F, O>(&self, decoder: D, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, D: Decoder<'de, Cx = Self, Mode = Self::Mode>, F: FnOnce(&T) -> Result, { - T::visit(self, decoder, f) + T::decode_unsized(self, decoder, f) } /// Decode the given input as bytes using the associated mode. @@ -65,6 +65,17 @@ pub trait Context { T::decode_bytes(self, decoder) } + /// Decode the given unsized value as bytes using the associated mode. + #[inline] + fn decode_unsized_bytes<'de, T, D, F, O>(&self, decoder: D, f: F) -> Result + where + T: ?Sized + DecodeUnsizedBytes<'de, Self::Mode>, + D: Decoder<'de, Cx = Self, Mode = Self::Mode>, + F: FnOnce(&T) -> Result, + { + T::decode_unsized_bytes(self, decoder, f) + } + /// Allocate a buffer. fn alloc(&self) -> Option>; diff --git a/crates/musli/src/de/visit.rs b/crates/musli/src/de/decode_unsized.rs similarity index 67% rename from crates/musli/src/de/visit.rs rename to crates/musli/src/de/decode_unsized.rs index e904c2931..ce54edef8 100644 --- a/crates/musli/src/de/visit.rs +++ b/crates/musli/src/de/decode_unsized.rs @@ -3,15 +3,19 @@ use crate::Context; use super::Decoder; -/// A trait implemented for types which can be visited by reference. +/// A trait implemented for types which can only be decoded by reference. /// /// This is used for types like `str` which are unsized, and might require /// internal allocating to properly decode. Simply using the `Decode` /// implementation would restrict it to only be used through `&'de str` which /// would demand an exact reference to data from the decoded source. -pub trait Visit<'de, M = DefaultMode> { +pub trait DecodeUnsized<'de, M = DefaultMode> { /// Decode the given input using a closure as visitor. - fn visit(cx: &D::Cx, decoder: D, f: F) -> Result::Error> + fn decode_unsized( + cx: &D::Cx, + decoder: D, + f: F, + ) -> Result::Error> where D: Decoder<'de, Mode = M>, F: FnOnce(&Self) -> Result; diff --git a/crates/musli/src/de/visit_bytes.rs b/crates/musli/src/de/decode_unsized_bytes.rs similarity index 63% rename from crates/musli/src/de/visit_bytes.rs rename to crates/musli/src/de/decode_unsized_bytes.rs index f20dc65b5..3f1af1329 100644 --- a/crates/musli/src/de/visit_bytes.rs +++ b/crates/musli/src/de/decode_unsized_bytes.rs @@ -5,18 +5,22 @@ use super::Decoder; /// A trait implemented for types which can be visited by reference. /// -/// This behaves the same as [`Visit`], but implicitly hints that the caller is -/// after bytes. +/// This behaves the same as [`DecodeUnsized`], but implicitly hints that the +/// caller is after bytes. /// /// This is used for types like `[u8]` which are unsized, and might require /// internal allocating to properly decode. Simply using the `Decode` /// implementation would restrict it to only be used through `&'de [u8]` which /// would demand an exact reference to data from the decoded source. /// -/// [`Visit`]: super::Visit -pub trait VisitBytes<'de, M = DefaultMode> { +/// [`DecodeUnsized`]: super::DecodeUnsized +pub trait DecodeUnsizedBytes<'de, M = DefaultMode> { /// Decode the given input using a closure as visitor. - fn visit_bytes(cx: &D::Cx, decoder: D, f: F) -> Result::Error> + fn decode_unsized_bytes( + cx: &D::Cx, + decoder: D, + f: F, + ) -> Result::Error> where D: Decoder<'de, Mode = M>, F: FnOnce(&Self) -> Result; diff --git a/crates/musli/src/de/decoder.rs b/crates/musli/src/de/decoder.rs index 521fa6b5a..da2b6d0b9 100644 --- a/crates/musli/src/de/decoder.rs +++ b/crates/musli/src/de/decoder.rs @@ -6,11 +6,10 @@ use crate::expecting::{self, Expecting}; use crate::hint::{StructHint, TupleHint, UnsizedStructHint}; use crate::Context; -use super::{NumberVisitor, StructDecoder, TypeHint, ValueVisitor, Visit, Visitor}; - use super::{ - AsDecoder, Decode, MapDecoder, MapEntriesDecoder, PackDecoder, SequenceDecoder, Skip, - StructFieldsDecoder, TupleDecoder, VariantDecoder, + AsDecoder, Decode, DecodeUnsized, DecodeUnsizedBytes, MapDecoder, MapEntriesDecoder, + NumberVisitor, PackDecoder, SequenceDecoder, Skip, StructDecoder, StructFieldsDecoder, + TupleDecoder, TypeHint, ValueVisitor, VariantDecoder, Visitor, }; /// Trait governing the implementation of a decoder. @@ -115,10 +114,17 @@ pub trait Decoder<'de>: Sized { where T: Decode<'de, Self::Mode>; - /// Visit a reference to a value through the specified closure. - fn visit(self, f: F) -> Result + /// Decode an unsized value by reference through the specified closure. + fn decode_unsized(self, f: F) -> Result + where + T: ?Sized + DecodeUnsized<'de, Self::Mode>, + F: FnOnce(&T) -> Result::Error>; + + /// Decode an unsized value as bytes by reference through the specified + /// closure. + fn decode_unsized_bytes(self, f: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsizedBytes<'de, Self::Mode>, F: FnOnce(&T) -> Result::Error>; /// Skip over the current next value. diff --git a/crates/musli/src/de/mod.rs b/crates/musli/src/de/mod.rs index 52cbd47f9..851cf267c 100644 --- a/crates/musli/src/de/mod.rs +++ b/crates/musli/src/de/mod.rs @@ -25,11 +25,11 @@ pub use self::as_decoder::AsDecoder; mod decode; pub use self::decode::{Decode, TraceDecode}; -mod visit; -pub use self::visit::Visit; +mod decode_unsized; +pub use self::decode_unsized::DecodeUnsized; -mod visit_bytes; -pub use self::visit_bytes::VisitBytes; +mod decode_unsized_bytes; +pub use self::decode_unsized_bytes::DecodeUnsizedBytes; mod decode_bytes; pub use self::decode_bytes::DecodeBytes; diff --git a/crates/musli/src/derives.rs b/crates/musli/src/derives.rs index f1d792e8b..a0163a4b0 100644 --- a/crates/musli/src/derives.rs +++ b/crates/musli/src/derives.rs @@ -304,6 +304,7 @@ //! //! The following values are treated specially: //! * `str` applies `#[musli(name_all = "name")]` by default. +//! * `[u8]` applies `#[musli(name_all = "name")]` by default. //! //! ``` //! use core::fmt; @@ -475,6 +476,7 @@ //! //! The following values are treated specially: //! * `str` applies `#[musli(name_all = "name")]` by default. +//! * `[u8]` applies `#[musli(name_all = "name")]` by default. //! //! ``` //! use core::fmt; diff --git a/crates/musli/src/impls/alloc.rs b/crates/musli/src/impls/alloc.rs index 511846346..e47dac29b 100644 --- a/crates/musli/src/impls/alloc.rs +++ b/crates/musli/src/impls/alloc.rs @@ -82,8 +82,6 @@ impl<'de, M> Decode<'de, M> for String { } } -visit!(String); - impl<'de, M> Decode<'de, M> for Box { #[inline] fn decode(_: &D::Cx, decoder: D) -> Result @@ -94,8 +92,6 @@ impl<'de, M> Decode<'de, M> for Box { } } -visit!(Box); - impl<'de, M, T> Decode<'de, M> for Box<[T]> where T: Decode<'de, M>, @@ -109,8 +105,6 @@ where } } -visit!({T} Box<[T]> where T: Decode<'de, M>); - macro_rules! cow { ( $encode:ident :: $encode_fn:ident, @@ -193,8 +187,6 @@ cow! { |reference| Cow::Owned(reference.to_owned()) } -visit!(Cow<'de, str>); - cow! { Encode::encode, Decode::decode, @@ -204,8 +196,6 @@ cow! { |reference| Cow::Owned(CStr::from_bytes_with_nul(reference).map_err(cx.map())?.to_owned()) } -visit!(Cow<'de, CStr>); - cow! { EncodeBytes::encode_bytes, DecodeBytes::decode_bytes, @@ -215,8 +205,6 @@ cow! { |reference| Cow::Owned(reference.to_owned()) } -visit_bytes!(Cow<'de, [u8]>); - macro_rules! sequence { ( $cx:ident, @@ -278,12 +266,6 @@ macro_rules! sequence { }) } } - - visit! { - {T, $($extra)*} $ty where - T: Decode<'de, M> $(+ $trait0 $(+ $trait)*)*, - $($extra: $extra_bound0 $(+ $extra_bound)*),* - } } } @@ -426,13 +408,6 @@ macro_rules! map { }) } } - - visit! { - {K, V, $($extra)*} $ty where - K: Decode<'de, M> $(+ $key_bound0 $(+ $key_bound)*)*, - V: Decode<'de, M>, - $($extra: $extra_bound0 $(+ $extra_bound)*),* - } } } @@ -498,8 +473,6 @@ impl<'de, M> Decode<'de, M> for CString { } } -visit!(CString); - macro_rules! smart_pointer { ($($ty:ident),* $(,)?) => { $( @@ -529,8 +502,6 @@ macro_rules! smart_pointer { } } - visit!({T} $ty where T: Decode<'de, M>); - impl<'de, M> DecodeBytes<'de, M> for $ty<[u8]> { #[inline] fn decode_bytes(cx: &D::Cx, decoder: D) -> Result @@ -541,8 +512,6 @@ macro_rules! smart_pointer { } } - visit_bytes!($ty<[u8]>); - impl<'de, M> Decode<'de, M> for $ty { #[inline] fn decode(cx: &D::Cx, decoder: D) -> Result @@ -553,8 +522,6 @@ macro_rules! smart_pointer { } } - visit!($ty); - #[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 { @@ -567,11 +534,6 @@ macro_rules! smart_pointer { } } - visit! { - #[cfg(all(feature = "std", any(unix, windows)))] - $ty - } - #[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 { @@ -583,29 +545,11 @@ macro_rules! smart_pointer { Ok($ty::from(OsString::decode(cx, decoder)?)) } } - - visit! { - #[cfg(all(feature = "std", any(unix, windows)))] - $ty - } )* }; } smart_pointer!(Box, Arc, Rc); -visit_deref!({T} Box<[T]> as [T] where T: Decode<'de, M>); - -visit_deref!(Box as CStr); - -visit_deref! { - #[cfg(all(feature = "std", any(unix, windows)))] - Box as Path -} - -visit_deref! { - #[cfg(all(feature = "std", any(unix, windows)))] - Box as OsStr -} #[cfg(all(feature = "std", any(unix, windows)))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))] @@ -732,11 +676,6 @@ impl<'de, M> Decode<'de, M> for OsString { } } -visit! { - #[cfg(all(feature = "std", any(unix, windows)))] - OsString -} - #[cfg(all(feature = "std", any(unix, windows)))] #[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", any(unix, windows)))))] impl Encode for Path { @@ -773,11 +712,6 @@ impl<'de, M> Decode<'de, M> for PathBuf { } } -visit! { - #[cfg(all(feature = "std", any(unix, windows)))] - PathBuf -} - impl EncodeBytes for Vec { #[inline] fn encode_bytes(&self, _: &E::Cx, encoder: E) -> Result @@ -832,8 +766,6 @@ impl<'de, M> DecodeBytes<'de, M> for Vec { } } -visit_bytes!(Vec); - impl EncodeBytes for VecDeque { #[inline] fn encode_bytes(&self, _: &E::Cx, encoder: E) -> Result @@ -854,5 +786,3 @@ impl<'de, M> DecodeBytes<'de, M> for VecDeque { Ok(VecDeque::from(>::decode_bytes(cx, decoder)?)) } } - -visit_bytes!(VecDeque); diff --git a/crates/musli/src/impls/mod.rs b/crates/musli/src/impls/mod.rs index cc3cfe683..9fa8995cd 100644 --- a/crates/musli/src/impls/mod.rs +++ b/crates/musli/src/impls/mod.rs @@ -1,78 +1,3 @@ -/// Forward implementation of `Visit` which simply decodes the value on the -/// stack allowing it to be visited. -macro_rules! visit { - ( - $(#[cfg($($meta:meta)*)])* - $({$($impl:tt)*})? $ty:ty $(where $($where:tt)*)? - ) => { - $( - #[cfg($($meta)*)] - #[cfg_attr(doc_cfg, doc(cfg($($meta)*)))] - )* - impl<'de, M $(, $($impl)*)*> $crate::de::Visit<'de, M> for $ty $(where $($where)*)? { - #[inline(always)] - fn visit(cx: &D::Cx, decoder: D, f: F) -> Result - where - D: $crate::de::Decoder<'de, Mode = M>, - F: FnOnce(&Self) -> Result, - { - let value = $crate::de::Decode::::decode(cx, decoder)?; - f(&value) - } - } - } -} - -/// Forward implementation of `Visit` which uses the deref implementation of something. -#[cfg(feature = "alloc")] -macro_rules! visit_deref { - ( - $(#[cfg($($meta:meta)*)])* - $({$($impl:tt)*})? $ty:ty as $other:ty $(where $($where:tt)*)? - ) => { - $( - #[cfg($($meta)*)] - #[cfg_attr(doc_cfg, doc(cfg($($meta)*)))] - )* - impl<'de, M $(, $($impl)*)*> $crate::de::Visit<'de, M> for $other $(where $($where)*)? { - #[inline(always)] - fn visit(cx: &D::Cx, decoder: D, f: F) -> Result - where - D: $crate::de::Decoder<'de, Mode = M>, - F: FnOnce(&Self) -> Result, - { - let value: $ty = $crate::de::Decode::::decode(cx, decoder)?; - f(&value) - } - } - } -} - -/// Forward implementation of `VisitBytes` which simply decodes the value on the -/// stack allowing it to be visited. -macro_rules! visit_bytes { - ( - $(#[cfg($($meta:meta)*)])* - $({$($impl:tt)*})? $ty:ty $(where $($where:tt)*)? - ) => { - $( - #[cfg($($meta)*)] - #[cfg_attr(doc_cfg, doc(cfg($($meta)*)))] - )* - impl<'de, M $(, $($impl)*)*> $crate::de::VisitBytes<'de, M> for $ty $(where $($where)*)? { - #[inline(always)] - fn visit_bytes(cx: &D::Cx, decoder: D, f: F) -> Result - where - D: $crate::de::Decoder<'de, Mode = M>, - F: FnOnce(&Self) -> Result, - { - let value = $crate::de::DecodeBytes::::decode_bytes(cx, decoder)?; - f(&value) - } - } - } -} - #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] mod alloc; @@ -89,7 +14,9 @@ use core::num::{ }; use core::{fmt, marker}; -use crate::de::{Decode, DecodeBytes, Decoder, ValueVisitor, VariantDecoder, Visit, VisitBytes}; +use crate::de::{ + Decode, DecodeBytes, DecodeUnsized, DecodeUnsizedBytes, Decoder, ValueVisitor, VariantDecoder, +}; use crate::en::{Encode, EncodeBytes, Encoder, SequenceEncoder, VariantEncoder}; use crate::hint::SequenceHint; use crate::Context; @@ -123,8 +50,6 @@ impl<'de, M> Decode<'de, M> for () { } } -visit!(()); - impl Encode for marker::PhantomData { #[inline] fn encode(&self, _: &E::Cx, encoder: E) -> Result @@ -146,8 +71,6 @@ impl<'de, M, T> Decode<'de, M> for marker::PhantomData { } } -visit!({T} marker::PhantomData); - macro_rules! atomic_impl { ($size:literal $(, $ty:ident)*) => { $( @@ -160,8 +83,6 @@ macro_rules! atomic_impl { decoder.decode().map(Self::new) } } - - visit!(core::sync::atomic::$ty); )* }; } @@ -200,8 +121,6 @@ macro_rules! non_zero { } } } - - visit!($ty); }; } @@ -267,8 +186,6 @@ impl<'de, M, const N: usize> Decode<'de, M> for [u8; N] { } } -visit!({const N: usize} [u8; N]); - macro_rules! impl_number { ($ty:ty, $read:ident, $write:ident) => { impl Encode for $ty { @@ -290,8 +207,6 @@ macro_rules! impl_number { decoder.$read() } } - - visit!($ty); }; } @@ -315,8 +230,6 @@ impl<'de, M> Decode<'de, M> for bool { } } -visit!(bool); - impl Encode for char { #[inline] fn encode(&self, _: &E::Cx, encoder: E) -> Result @@ -337,8 +250,6 @@ impl<'de, M> Decode<'de, M> for char { } } -visit!(char); - impl_number!(usize, decode_usize, encode_usize); impl_number!(isize, decode_isize, encode_isize); impl_number!(u8, decode_u8, encode_u8); @@ -393,9 +304,9 @@ impl<'de, M> Decode<'de, M> for &'de str { } } -impl<'de, M> Visit<'de, M> for str { +impl<'de, M> DecodeUnsized<'de, M> for str { #[inline] - fn visit(_: &D::Cx, decoder: D, f: F) -> Result + fn decode_unsized(_: &D::Cx, decoder: D, f: F) -> Result where D: Decoder<'de>, F: FnOnce(&Self) -> Result, @@ -478,9 +389,9 @@ impl<'de, M> Decode<'de, M> for &'de [u8] { } } -impl<'de, M> VisitBytes<'de, M> for [u8] { +impl<'de, M> DecodeUnsizedBytes<'de, M> for [u8] { #[inline] - fn visit_bytes(_: &D::Cx, decoder: D, f: F) -> Result + fn decode_unsized_bytes(_: &D::Cx, decoder: D, f: F) -> Result where D: Decoder<'de>, F: FnOnce(&Self) -> Result, @@ -542,8 +453,6 @@ where } } -visit!({T} Option where T: Decode<'de, M>); - #[derive(Encode, Decode)] #[musli(crate)] enum ResultTag { @@ -591,8 +500,6 @@ where } } -visit!({T, U} Result where T: Decode<'de, M>, U: Decode<'de, M>); - impl Encode for Wrapping where T: Encode, @@ -619,8 +526,6 @@ where } } -visit!({T} Wrapping where T: Decode<'de, M>); - impl Encode for CStr { #[inline] fn encode(&self, _: &E::Cx, encoder: E) -> Result @@ -642,6 +547,20 @@ impl<'de, M> Decode<'de, M> for &'de CStr { } } +impl<'de, M> DecodeUnsized<'de, M> for CStr { + #[inline(always)] + fn decode_unsized(cx: &D::Cx, decoder: D, f: F) -> Result + where + D: Decoder<'de, Mode = M>, + F: FnOnce(&Self) -> Result, + { + cx.decode_unsized_bytes(decoder, |bytes: &[u8]| { + let cstr = CStr::from_bytes_with_nul(bytes).map_err(cx.map())?; + f(cstr) + }) + } +} + impl EncodeBytes for [u8] { #[inline] fn encode_bytes(&self, _: &E::Cx, encoder: E) -> Result @@ -681,5 +600,3 @@ impl<'de, M, const N: usize> DecodeBytes<'de, M> for [u8; N] { decoder.decode_array() } } - -visit_bytes!({const N: usize} [u8; N]); diff --git a/crates/musli/src/impls/net.rs b/crates/musli/src/impls/net.rs index 5f5e1e227..654d7f828 100644 --- a/crates/musli/src/impls/net.rs +++ b/crates/musli/src/impls/net.rs @@ -23,8 +23,6 @@ impl<'de, M> Decode<'de, M> for Ipv4Addr { } } -visit!(Ipv4Addr); - impl Encode for Ipv6Addr { #[inline] fn encode(&self, _: &E::Cx, encoder: E) -> Result @@ -45,8 +43,6 @@ impl<'de, M> Decode<'de, M> for Ipv6Addr { } } -visit!(Ipv6Addr); - #[derive(Encode, Decode)] #[musli(crate)] enum IpAddrTag { @@ -86,8 +82,6 @@ impl<'de, M> Decode<'de, M> for IpAddr { } } -visit!(IpAddr); - impl Encode for SocketAddrV4 { #[inline] fn encode(&self, _: &E::Cx, encoder: E) -> Result @@ -112,8 +106,6 @@ impl<'de, M> Decode<'de, M> for SocketAddrV4 { } } -visit!(SocketAddrV4); - impl Encode for SocketAddrV6 { #[inline] fn encode(&self, _: &E::Cx, encoder: E) -> Result @@ -140,8 +132,6 @@ impl<'de, M> Decode<'de, M> for SocketAddrV6 { } } -visit!(SocketAddrV6); - #[derive(Encode, Decode)] #[musli(crate)] enum SocketAddrTag { @@ -180,5 +170,3 @@ impl<'de, M> Decode<'de, M> for SocketAddr { }) } } - -visit!(SocketAddr); diff --git a/crates/musli/src/impls/range.rs b/crates/musli/src/impls/range.rs index bab838507..6c73b554a 100644 --- a/crates/musli/src/impls/range.rs +++ b/crates/musli/src/impls/range.rs @@ -38,8 +38,6 @@ macro_rules! implement { Ok($ty { $($field,)* }) } } - - visit!({$($type)*} $ty $(<$type>)* where $($type: Decode<'de, M>,)*); } } @@ -76,8 +74,6 @@ macro_rules! implement_new { Ok($ty::new($($field,)*)) } } - - visit!({T} $ty where T: Decode<'de, M>); } } diff --git a/crates/musli/src/impls/tuples.rs b/crates/musli/src/impls/tuples.rs index 86e27a4a2..9fbae00f1 100644 --- a/crates/musli/src/impls/tuples.rs +++ b/crates/musli/src/impls/tuples.rs @@ -82,13 +82,6 @@ macro_rules! declare { } } - visit! { - {$ty0, $($ty,)*} ($ty0, $($ty),*) - where - $ty0: Decode<'de, M>, - $($ty: Decode<'de, M>),* - } - impl Encode for Packed<($ty0, $($ty),*)> where $ty0: Encode, @@ -126,13 +119,6 @@ macro_rules! declare { } } - visit! { - {$ty0, $($ty,)*} Packed<($ty0, $($ty),*)> - where - $ty0: Decode<'de, M>, - $($ty: Decode<'de, M>),* - } - declare!($(($ty, $ident)),*); }; } diff --git a/crates/musli/src/never.rs b/crates/musli/src/never.rs index 8d8b186fa..37239eee0 100644 --- a/crates/musli/src/never.rs +++ b/crates/musli/src/never.rs @@ -13,9 +13,9 @@ use core::marker; use crate::no_std::ToOwned; use crate::de::{ - AsDecoder, Decode, Decoder, MapDecoder, MapEntriesDecoder, MapEntryDecoder, NumberVisitor, - PackDecoder, SequenceDecoder, SizeHint, StructDecoder, StructFieldDecoder, StructFieldsDecoder, - TupleDecoder, ValueVisitor, VariantDecoder, Visit, + AsDecoder, Decode, DecodeUnsized, DecodeUnsizedBytes, Decoder, MapDecoder, MapEntriesDecoder, + MapEntryDecoder, NumberVisitor, PackDecoder, SequenceDecoder, SizeHint, StructDecoder, + StructFieldDecoder, StructFieldsDecoder, TupleDecoder, ValueVisitor, VariantDecoder, }; use crate::en::{ Encode, Encoder, MapEncoder, MapEntriesEncoder, MapEntryEncoder, PackEncoder, SequenceEncoder, @@ -141,9 +141,18 @@ impl<'de, C: ?Sized + Context> Decoder<'de> for Never<(), C> { } #[inline] - fn visit(self, _: F) -> Result + fn decode_unsized(self, _: F) -> Result where - T: ?Sized + Visit<'de, Self::Mode>, + T: ?Sized + DecodeUnsized<'de, Self::Mode>, + F: FnOnce(&T) -> Result, + { + match self._never {} + } + + #[inline] + fn decode_unsized_bytes(self, _: F) -> Result + where + T: ?Sized + DecodeUnsizedBytes<'de, Self::Mode>, F: FnOnce(&T) -> Result, { match self._never {}