Skip to content

Commit

Permalink
Using closure encoding to avoid type confusion
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Mar 22, 2024
1 parent ad9c103 commit e6bec6c
Show file tree
Hide file tree
Showing 22 changed files with 565 additions and 210 deletions.
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- run: cargo +nightly run -p no-std-examples --example no-std-${{matrix.example}}

fuzz:
needs: [test, each_package]
needs: [test, each_package, recursive]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -55,7 +55,7 @@ jobs:
- run: cargo run --release -p tests --features test --bin fuzz -- --random

miri:
needs: [test, each_package]
needs: [test, each_package, recursive]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -86,6 +86,13 @@ jobs:
- run: cargo build -p ${{matrix.package}} --no-default-features --features parse-full
if: matrix.package == 'musli-json'

recursive:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo build --release -p tests --test recursive_models --features test

clippy:
runs-on: ubuntu-latest
steps:
Expand Down
7 changes: 2 additions & 5 deletions crates/musli-common/src/context/stack_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,9 @@ where
where
T: fmt::Display,
{
let Some(buf) = self.alloc.alloc() else {
return None;
};

let buf = self.alloc.alloc()?;
let mut string = BufString::new(buf);
_ = write!(string, "{}", value);
write!(string, "{value}").ok()?;
Some(string)
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/musli-descriptive/src/en.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ where
#[inline]
fn encode_unit_variant<T>(self, cx: &C, tag: &T) -> Result<(), C::Error>
where
T: Encode<C::Mode>,
T: ?Sized + Encode<C::Mode>,
{
let mut variant = self.encode_variant(cx)?;
tag.encode(cx, variant.encode_tag(cx)?)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/musli-json/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl<M> Encoding<M> {
W: Writer,
T: ?Sized + Encode<M>,
{
T::encode(value, cx, JsonEncoder::new(writer))
value.encode(cx, JsonEncoder::new(writer))
}

/// Encode the given value to a [`String`] using the current configuration.
Expand Down
123 changes: 68 additions & 55 deletions crates/musli-macros/src/en.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ fn encode_struct(cx: &Ctxt<'_>, e: &Build<'_>, st: &Body<'_>) -> Result<TokenStr
context_t,
encoder_t,
result_ok,
sequence_encoder_t,
struct_encoder_t,
..
} = e.tokens;

Expand Down Expand Up @@ -140,9 +138,10 @@ fn encode_struct(cx: &Ctxt<'_>, e: &Build<'_>, st: &Body<'_>) -> Result<TokenStr
encode = quote! {{
#enter
#(#decls)*
let mut #encoder_var = #encoder_t::<#c_param>::encode_struct(#encoder_var, #ctx_var, #len)?;
#(#encoders)*
let #output_var = #struct_encoder_t::<#c_param>::end(#encoder_var, #ctx_var)?;
let #output_var = #encoder_t::<#c_param>::encode_struct_fn(#encoder_var, #ctx_var, #len, |#encoder_var| {
#(#encoders)*
#result_ok(())
})?;
#leave
#output_var
}};
Expand All @@ -152,10 +151,11 @@ fn encode_struct(cx: &Ctxt<'_>, e: &Build<'_>, st: &Body<'_>) -> Result<TokenStr

encode = quote! {{
#enter
#(#decls)*
let mut #pack_var = #encoder_t::<#c_param>::encode_pack(#encoder_var, #ctx_var)?;
#(#encoders)*
let #output_var = #sequence_encoder_t::<#c_param>::end(#pack_var, #ctx_var)?;
let #output_var = #encoder_t::<#c_param>::encode_pack_fn(#encoder_var, #ctx_var, |#pack_var| {
#(#decls)*
#(#encoders)*
#result_ok(())
})?;
#leave
#output_var
}};
Expand Down Expand Up @@ -184,10 +184,11 @@ fn insert_fields(
} = *cx;

let Tokens {
struct_field_encoder_t,
struct_encoder_t,
sequence_encoder_t,
context_t,
result_ok,
sequence_encoder_t,
struct_encoder_t,
struct_field_encoder_t,
..
} = e.tokens;

Expand Down Expand Up @@ -237,19 +238,22 @@ fn insert_fields(
Packing::Tagged | Packing::Transparent => {
encode = quote! {
#enter
let mut #pair_encoder_var = #struct_encoder_t::<#c_param>::encode_field(&mut #encoder_var, #ctx_var)?;
let #field_encoder_var = #struct_field_encoder_t::<#c_param>::encode_field_name(&mut #pair_encoder_var, #ctx_var)?;
#encode_t_encode(&#tag, #ctx_var, #field_encoder_var)?;
let #value_encoder_var = #struct_field_encoder_t::<#c_param>::encode_field_value(&mut #pair_encoder_var, #ctx_var)?;
#encode_path(#access, #ctx_var, #value_encoder_var)?;
#struct_field_encoder_t::<#c_param>::end(#pair_encoder_var, #ctx_var)?;

#struct_encoder_t::<#c_param>::encode_field_fn(#encoder_var, #ctx_var, |#pair_encoder_var| {
let #field_encoder_var = #struct_field_encoder_t::<#c_param>::encode_field_name(#pair_encoder_var, #ctx_var)?;
#encode_t_encode(&#tag, #ctx_var, #field_encoder_var)?;
let #value_encoder_var = #struct_field_encoder_t::<#c_param>::encode_field_value(#pair_encoder_var, #ctx_var)?;
#encode_path(#access, #ctx_var, #value_encoder_var)?;
#result_ok(())
})?;

#leave
};
}
Packing::Packed => {
encode = quote! {
#enter
let #sequence_decoder_next_var = #sequence_encoder_t::<#c_param>::encode_next(&mut #pack_var, #ctx_var)?;
let #sequence_decoder_next_var = #sequence_encoder_t::<#c_param>::encode_next(#pack_var, #ctx_var)?;
#encode_path(#access, #ctx_var, #sequence_decoder_next_var)?;
#leave
};
Expand Down Expand Up @@ -337,12 +341,12 @@ fn encode_variant(
} = *cx;

let Tokens {
context_t,
encoder_t,
result_ok,
struct_encoder_t,
struct_field_encoder_t,
variant_encoder_t,
sequence_encoder_t,
context_t,
..
} = b.tokens;

Expand All @@ -367,21 +371,23 @@ fn encode_variant(
let decls = tests.iter().map(|t| &t.decl);

encode = quote! {{
let mut #pack_var = #encoder_t::<#c_param>::encode_pack(#encoder_var, #ctx_var)?;
#(#decls)*
#(#encoders)*
#sequence_encoder_t::<#c_param>::end(#pack_var, #ctx_var)?
#encoder_t::<#c_param>::encode_pack_fn(#encoder_var, #ctx_var, |#pack_var| {
#(#decls)*
#(#encoders)*
#result_ok(())
})?
}};
}
Packing::Tagged => {
let decls = tests.iter().map(|t| &t.decl);
let len = length_test(v.st.fields.len(), &tests);

encode = quote! {{
let mut #encoder_var = #encoder_t::<#c_param>::encode_struct(#encoder_var, #ctx_var, #len)?;
#(#decls)*
#(#encoders)*
#struct_encoder_t::<#c_param>::end(#encoder_var, #ctx_var)?
#encoder_t::<#c_param>::encode_struct_fn(#encoder_var, #ctx_var, #len, |#encoder_var| {
#(#decls)*
#(#encoders)*
#result_ok(())
})?
}};
}
}
Expand All @@ -393,14 +399,14 @@ fn encode_variant(
let tag_encoder = b.cx.ident("tag_encoder");

encode = quote! {{
let mut #variant_encoder = #encoder_t::<#c_param>::encode_variant(#encoder_var, #ctx_var)?;

let #tag_encoder = #variant_encoder_t::<#c_param>::encode_tag(&mut #variant_encoder, #ctx_var)?;
#encode_t_encode(&#tag, #ctx_var, #tag_encoder)?;

let #encoder_var = #variant_encoder_t::<#c_param>::encode_value(&mut #variant_encoder, #ctx_var)?;
#encode;
#variant_encoder_t::<#c_param>::end(#variant_encoder, #ctx_var)?
#encoder_t::<#c_param>::encode_variant_fn(#encoder_var, #ctx_var, |#variant_encoder| {
let #tag_encoder = #variant_encoder_t::<#c_param>::encode_tag(#variant_encoder, #ctx_var)?;
#encode_t_encode(&#tag, #ctx_var, #tag_encoder)?;

let #encoder_var = #variant_encoder_t::<#c_param>::encode_value(#variant_encoder, #ctx_var)?;
#encode;
#result_ok(())
})?
}};
}
}
Expand All @@ -414,11 +420,12 @@ fn encode_variant(
let decls = tests.iter().map(|t| &t.decl);

encode = quote! {{
let mut #encoder_var = #encoder_t::<#c_param>::encode_struct(#encoder_var, #ctx_var, 0)?;
#struct_encoder_t::<#c_param>::insert_field(&mut #encoder_var, #ctx_var, #field_tag, #tag)?;
#(#decls)*
#(#encoders)*
#struct_encoder_t::<#c_param>::end(#encoder_var, #ctx_var)?
#encoder_t::<#c_param>::encode_struct_fn(#encoder_var, #ctx_var, 0, |#encoder_var| {
#struct_encoder_t::<#c_param>::insert_field(#encoder_var, #ctx_var, #field_tag, #tag)?;
#(#decls)*
#(#encoders)*
#result_ok(())
})?
}};
}
EnumTagging::Adjacent {
Expand All @@ -440,20 +447,26 @@ fn encode_variant(
let content_tag = b.cx.ident("content_tag");

encode = quote! {{
let mut #struct_encoder = #encoder_t::<#c_param>::encode_struct(#encoder_var, #ctx_var, 2)?;
#struct_encoder_t::<#c_param>::insert_field(&mut #struct_encoder, #ctx_var, &#field_tag, #tag)?;
let mut #pair = #struct_encoder_t::<#c_param>::encode_field(&mut #struct_encoder, #ctx_var)?;
let #content_tag = #struct_field_encoder_t::<#c_param>::encode_field_name(&mut #pair, #ctx_var)?;
#encode_t_encode(&#content, #ctx_var, #content_tag)?;

let #content_struct = #struct_field_encoder_t::<#c_param>::encode_field_value(&mut #pair, #ctx_var)?;
let mut #encoder_var = #encoder_t::<#c_param>::encode_struct(#content_struct, #ctx_var, #len)?;
#(#decls)*
#(#encoders)*
#struct_encoder_t::<#c_param>::end(#encoder_var, #ctx_var)?;
#encoder_t::<#c_param>::encode_struct_fn(#encoder_var, #ctx_var, 2, |#struct_encoder| {
#struct_encoder_t::<#c_param>::insert_field(#struct_encoder, #ctx_var, &#field_tag, #tag)?;

#struct_encoder_t::<#c_param>::encode_field_fn(#struct_encoder, #ctx_var, |#pair| {
let #content_tag = #struct_field_encoder_t::<#c_param>::encode_field_name(#pair, #ctx_var)?;
#encode_t_encode(&#content, #ctx_var, #content_tag)?;

let #content_struct = #struct_field_encoder_t::<#c_param>::encode_field_value(#pair, #ctx_var)?;

#encoder_t::<#c_param>::encode_struct_fn(#content_struct, #ctx_var, #len, |#encoder_var| {
#(#decls)*
#(#encoders)*
#result_ok(())
})?;

#result_ok(())
})?;

#struct_field_encoder_t::<#c_param>::end(#pair, #ctx_var)?;
#struct_encoder_t::<#c_param>::end(#struct_encoder, #ctx_var)?
#result_ok(())
})?
}};
}
},
Expand Down
4 changes: 2 additions & 2 deletions crates/musli-macros/src/expander.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use syn::spanned::Spanned;

use crate::internals::attr::{self, DefaultTag, TypeAttr};
use crate::internals::build::Build;
use crate::internals::symbol::*;
use crate::internals::tokens::Tokens;
use crate::internals::ATTR;
use crate::internals::{Ctxt, Expansion, Mode, Only};

pub(crate) type Result<T, E = ()> = std::result::Result<T, E>;
Expand Down Expand Up @@ -233,7 +233,7 @@ pub(crate) trait Taggable {
e.cx.error_span(
self.span(),
format_args!(
"#[{ATTR}({DEFAULT_FIELD_NAME} = \"name\")] is not supported with unnamed fields",
"#[{ATTR}(default_field = \"name\")] is not supported on unnamed fields",
),
);
return Err(());
Expand Down
3 changes: 2 additions & 1 deletion crates/musli-macros/src/internals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ pub(crate) mod build;
mod ctxt;
mod expansion;
mod mode;
pub(crate) mod symbol;
pub(crate) mod tokens;

pub(crate) const ATTR: &str = "musli";

pub(crate) use self::attr::Only;
pub(crate) use self::ctxt::Ctxt;
pub(crate) use self::expansion::Expansion;
Expand Down
Loading

0 comments on commit e6bec6c

Please sign in to comment.