Skip to content

Commit

Permalink
Less verbose expansion
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Mar 29, 2024
1 parent 951e7e1 commit 4f50ede
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 42 deletions.
1 change: 1 addition & 0 deletions crates/musli-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ path = "src/lib.rs"

[features]
test = []
verbose = []

[dependencies]
proc-macro2 = "1.0.79"
Expand Down
11 changes: 7 additions & 4 deletions crates/musli-macros/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct Ctxt<'a> {

pub(crate) fn expand_decode_entry(e: Build<'_>) -> Result<TokenStream> {
e.validate_decode()?;
e.cx.reset();

let ctx_var = e.cx.ident("ctx");
let root_decoder_var = e.cx.ident("decoder");
Expand Down Expand Up @@ -128,6 +129,7 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result<TokenStream> {
option_some,
result,
skip,
str_ty,
struct_decoder_t,
struct_field_decoder_t,
variant_decoder_t,
Expand Down Expand Up @@ -206,7 +208,7 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result<TokenStream> {
#result::Ok(match string {
#(#arms,)*
string => {
if !#buf_t::write(&mut #variant_alloc_var, str::as_bytes(string)) {
if !#buf_t::write(&mut #variant_alloc_var, #str_ty::as_bytes(string)) {
return #result::Err(#context_t::alloc_failed(#ctx_var));
}

Expand Down Expand Up @@ -405,7 +407,7 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result<TokenStream> {
#result::Ok(match string {
#field_tag => Outcome::Tag,
string => {
if !#buf_t::write(&mut #field_alloc_var, str::as_bytes(string)) {
if !#buf_t::write(&mut #field_alloc_var, #str_ty::as_bytes(string)) {
Outcome::AllocErr
} else {
Outcome::Err
Expand Down Expand Up @@ -562,7 +564,7 @@ fn decode_enum(cx: &Ctxt<'_>, e: &Build<'_>, en: &Enum) -> Result<TokenStream> {
#tag => Outcome::Tag,
#content => Outcome::Content,
string => {
if !#buf_t::write(&mut #field_alloc_var, str::as_bytes(string)) {
if !#buf_t::write(&mut #field_alloc_var, #str_ty::as_bytes(string)) {
Outcome::AllocErr
} else {
Outcome::Err
Expand Down Expand Up @@ -710,6 +712,7 @@ fn decode_tagged(
} = *cx;

let Tokens {
str_ty,
buf_t,
context_t,
decoder_t,
Expand Down Expand Up @@ -828,7 +831,7 @@ fn decode_tagged(
#result::Ok(match string {
#(#patterns,)*
string => {
if !#buf_t::write(&mut #field_alloc_var, str::as_bytes(string)) {
if !#buf_t::write(&mut #field_alloc_var, #str_ty::as_bytes(string)) {
return #result::Err(#context_t::alloc_failed(#ctx_var));
}

Expand Down
15 changes: 8 additions & 7 deletions crates/musli-macros/src/en.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct Ctxt<'a> {

pub(crate) fn expand_insert_entry(e: Build<'_>) -> Result<TokenStream> {
e.validate_encode()?;
e.cx.reset();

let type_ident = &e.input.ident;

Expand Down Expand Up @@ -159,17 +160,17 @@ fn encode_struct(cx: &Ctxt<'_>, e: &Build<'_>, st: &Body<'_>) -> Result<TokenStr
Ok(quote!(#result::Ok(#encode)))
}

struct FieldTest {
struct FieldTest<'st> {
decl: TokenStream,
var: syn::Ident,
var: &'st syn::Ident,
}

fn insert_fields(
fn insert_fields<'st>(
cx: &Ctxt<'_>,
e: &Build<'_>,
st: &Body<'_>,
st: &'st Body<'_>,
pack_var: &syn::Ident,
) -> Result<(Vec<TokenStream>, Vec<FieldTest>)> {
) -> Result<(Vec<TokenStream>, Vec<FieldTest<'st>>)> {
let Ctxt {
ctx_var,
encoder_var,
Expand Down Expand Up @@ -254,7 +255,7 @@ fn insert_fields(
};

if let Some((_, skip_encoding_if_path)) = f.skip_encoding_if.as_ref() {
let var = e.cx.ident_with_span(&format!("t{}", f.index), f.span);
let var = &f.var;

let decl = quote! {
let #var = !#skip_encoding_if_path(#access);
Expand Down Expand Up @@ -488,7 +489,7 @@ fn encode_variant(
Ok((pattern, encode))
}

fn length_test(count: usize, tests: &[FieldTest]) -> Punctuated<TokenStream, Token![+]> {
fn length_test(count: usize, tests: &[FieldTest<'_>]) -> Punctuated<TokenStream, Token![+]> {
let mut punctuated = Punctuated::<_, Token![+]>::new();
let count = count.saturating_sub(tests.len());
punctuated.push(quote!(#count));
Expand Down
4 changes: 2 additions & 2 deletions crates/musli-macros/src/internals/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ fn setup_field<'a>(
};

let var = match &member {
syn::Member::Named(ident) => e.cx.field_ident(ident),
syn::Member::Unnamed(index) => quote::format_ident!("_{}", index.index),
syn::Member::Named(ident) => e.cx.ident_with_span(&ident.to_string(), ident.span(), "f_"),
syn::Member::Unnamed(index) => e.cx.ident_with_span(&index.index.to_string(), index.span, "f_"),
};

Ok(Field {
Expand Down
62 changes: 34 additions & 28 deletions crates/musli-macros/src/internals/ctxt.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use std::cell::RefCell;
use std::collections::HashSet;
use std::fmt::{self, Write};
#[cfg(not(feature = "verbose"))]
use std::collections::HashMap;

use proc_macro2::Span;

struct Inner {
b1: String,
b2: String,
modes: HashSet<syn::Path>,
errors: Vec<syn::Error>,
names: HashMap<String, usize>,
}

pub(crate) struct Ctxt {
Expand All @@ -21,9 +23,9 @@ impl Ctxt {
Self {
inner: RefCell::new(Inner {
b1: String::new(),
b2: String::new(),
modes: HashSet::new(),
errors: Vec::new(),
names: HashMap::new(),
}),
}
}
Expand Down Expand Up @@ -64,43 +66,47 @@ impl Ctxt {
self.inner.borrow().modes.iter().cloned().collect()
}

/// Build an identifier with the given name, escaped so it's harder to conflict with.
pub(crate) fn ident(&self, name: &str) -> syn::Ident {
let name = format!("i_{name}");
syn::Ident::new(&name, Span::call_site())
pub(crate) fn reset(&self) {
let mut inner = self.inner.borrow_mut();
inner.names.clear();
}

/// Build an identifier with the given name, escaped so it's harder to conflict with.
pub(crate) fn ident_with_span(&self, name: &str, span: Span) -> syn::Ident {
let name = format!("i_{name}");
syn::Ident::new(&name, span)
}

/// Build a type identifier with a span.
pub(crate) fn type_with_span(&self, name: &str, span: Span) -> syn::Ident {
let name = format!("T{name}");
syn::Ident::new(&name, span)
pub(crate) fn ident(&self, name: &str) -> syn::Ident {
self.ident_with_span(name, Span::call_site(), "")
}

/// Escape an ident so it's harder to conflict with, preserving idents span
pub(crate) fn field_ident(&self, ident: &syn::Ident) -> syn::Ident {
/// Build an identifier with the given name, escaped so it's harder to conflict with.
pub(crate) fn ident_with_span(&self, name: &str, span: Span, extra: &str) -> syn::Ident {
let mut inner = self.inner.borrow_mut();

let Inner { b1, b2, .. } = &mut *inner;

write!(b1, "{ident}").unwrap();

if let Some(rest) = b1.strip_prefix('_') {
write!(b2, "_f_{rest}").unwrap()
let index = if let Some(index) = inner.names.get(name) {
*index
} else {
write!(b2, "f_{ident}").unwrap()
let index = inner.names.len();
inner.names.insert(name.to_owned(), index);
index
};

#[cfg(not(feature = "verbose"))]
{
_ = write!(inner.b1, "_{extra}{index}");
}

let ident = syn::Ident::new(b2, ident.span());

b1.clear();
b2.clear();
#[cfg(feature = "verbose")]
{
let name = name.strip_prefix("_").unwrap_or(name);
_ = write!(inner.b1, "_{extra}{name}");
}

let ident = syn::Ident::new(&inner.b1, span);
inner.b1.clear();
ident
}

/// Build a type identifier with a span.
pub(crate) fn type_with_span(&self, name: &str, span: Span) -> syn::Ident {
let name = format!("T{name}");
syn::Ident::new(&name, span)
}
}
7 changes: 7 additions & 0 deletions crates/musli-macros/src/internals/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub(crate) struct Tokens {
pub(crate) pack_encoder_t: syn::Path,
pub(crate) result: syn::Path,
pub(crate) skip: syn::Path,
pub(crate) str_ty: syn::Path,
pub(crate) struct_decoder_t: syn::Path,
pub(crate) struct_encoder_t: syn::Path,
pub(crate) struct_field_decoder_t: syn::Path,
Expand Down Expand Up @@ -49,6 +50,7 @@ impl Tokens {
option_none: core(span, ["option", "Option", "None"]),
option_some: core(span, ["option", "Option", "Some"]),
pack_decoder_t: path(span, prefix, ["de", "PackDecoder"]),
str_ty: primitive(span, "str"),
struct_decoder_t: path(span, prefix, ["de", "StructDecoder"]),
struct_field_decoder_t: path(span, prefix, ["de", "StructFieldDecoder"]),
struct_encoder_t: path(span, prefix, ["en", "StructEncoder"]),
Expand Down Expand Up @@ -86,3 +88,8 @@ fn core<const N: usize>(span: Span, segments: [&'static str; N]) -> syn::Path {

path
}

fn primitive(span: Span, primitive: &'static str) -> syn::Path {
let core = syn::Ident::new(primitive, span);
syn::Path::from(core)
}
2 changes: 1 addition & 1 deletion crates/musli-zerocopy-macros/src/zero_copy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ fn process_fields<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> Fields<'a> {

let variable = match &member {
syn::Member::Named(ident) => ident.clone(),
syn::Member::Unnamed(index) => quote::format_ident!("_{}", index.index),
syn::Member::Unnamed(index) => quote::format_ident!("_f{}", index.index),
};

output.assigns.push(match &member {
Expand Down
1 change: 1 addition & 0 deletions crates/musli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"]
default = ["std", "alloc"]
std = []
alloc = []
verbose = ["musli-macros/verbose"]

[dependencies]
musli-macros = { version = "=0.0.107", path = "../musli-macros" }
1 change: 1 addition & 0 deletions crates/tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ publish = false
default = ["std", "alloc", "test"]
std = ["musli?/std", "musli-storage?/std", "musli-wire?/std", "musli-descriptive?/std", "musli-json?/std", "musli-zerocopy?/std", "rand/std", "serde_json?/std", "rkyv?/std", "serde?/std"]
alloc = ["musli?/alloc", "musli-storage?/alloc", "musli-wire?/alloc", "musli-descriptive?/alloc", "musli-json?/alloc", "musli-zerocopy?/alloc"]
verbose = ["musli?/verbose"]
extra = ["rkyv", "dlhn", "serde_cbor"]
full = ["rmp-serde", "bincode", "postcard", "musli-json", "serde_json", "bitcode", "bitcode-derive"]
text = ["musli-json", "serde_json"]
Expand Down

0 comments on commit 4f50ede

Please sign in to comment.