From c288c0ebb412f752c22555ef7ff07cbf537e365e Mon Sep 17 00:00:00 2001 From: KodrAus Date: Wed, 4 Oct 2023 08:38:22 +1000 Subject: [PATCH 1/2] use an uncommon name for the Stream generic in derive --- derive/test/compile_fail/union.rs | 11 ++++ derive/test/compile_fail/union.stderr | 7 +++ derive/test/lib.rs | 20 ++++++ derive_macros/src/derive.rs | 39 +++++++++++- derive_macros/src/derive/derive_enum.rs | 62 +++++++++---------- derive_macros/src/derive/derive_newtype.rs | 35 +++++------ derive_macros/src/derive/derive_struct.rs | 35 +++++------ .../src/derive/derive_unit_struct.rs | 35 +++++------ derive_macros/src/derive/derive_void.rs | 21 +++---- 9 files changed, 158 insertions(+), 107 deletions(-) create mode 100644 derive/test/compile_fail/union.rs create mode 100644 derive/test/compile_fail/union.stderr diff --git a/derive/test/compile_fail/union.rs b/derive/test/compile_fail/union.rs new file mode 100644 index 00000000..130ac87b --- /dev/null +++ b/derive/test/compile_fail/union.rs @@ -0,0 +1,11 @@ +use sval_derive::*; + +#[derive(Value)] +pub union Union { + a: i32, + b: u32, +} + +fn main() { + +} \ No newline at end of file diff --git a/derive/test/compile_fail/union.stderr b/derive/test/compile_fail/union.stderr new file mode 100644 index 00000000..a188976a --- /dev/null +++ b/derive/test/compile_fail/union.stderr @@ -0,0 +1,7 @@ +error: proc-macro derive panicked + --> compile_fail/union.rs:3:10 + | +3 | #[derive(Value)] + | ^^^^^ + | + = help: message: unsupported container type diff --git a/derive/test/lib.rs b/derive/test/lib.rs index be6c17b4..447f5ba6 100644 --- a/derive/test/lib.rs +++ b/derive/test/lib.rs @@ -26,6 +26,26 @@ mod derive_struct { }) } + #[test] + fn generic() { + #[derive(Value)] + struct RecordTuple { + a: S, + } + + assert_tokens(&RecordTuple { a: 42 }, { + use sval_test::Token::*; + + &[ + RecordTupleBegin(None, Some(sval::Label::new("RecordTuple")), None, Some(1)), + RecordTupleValueBegin(None, sval::Label::new("a"), sval::Index::new(0)), + I32(42), + RecordTupleValueEnd(None, sval::Label::new("a"), sval::Index::new(0)), + RecordTupleEnd(None, Some(sval::Label::new("RecordTuple")), None), + ] + }) + } + #[test] fn indexed() { #[derive(Value)] diff --git a/derive_macros/src/derive.rs b/derive_macros/src/derive.rs index 31e5ae44..211de3cf 100644 --- a/derive_macros/src/derive.rs +++ b/derive_macros/src/derive.rs @@ -43,6 +43,43 @@ pub(crate) fn derive(input: DeriveInput) -> proc_macro2::TokenStream { derive_enum(&input.ident, &input.generics, variants.iter(), &attrs) } - _ => panic!("unimplemented"), + _ => panic!("unsupported container type"), + } +} + +fn impl_tokens( + impl_generics: syn::ImplGenerics, + ident: &syn::Ident, + ty_generics: syn::TypeGenerics, + bounded_where_clause: &syn::WhereClause, + stream_body: proc_macro2::TokenStream, + tag_body: Option, +) -> proc_macro2::TokenStream { + let stream_fn = quote!( + fn stream<'sval, __SvalStream: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut __SvalStream) -> sval::Result { + #stream_body + } + ); + + let tag_fn = if let Some(tag_body) = tag_body { + quote!( + fn tag(&self) -> Option { + #tag_body + } + ) + } else { + quote!() + }; + + quote! { + const _: () = { + extern crate sval; + + impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { + #stream_fn + + #tag_fn + } + }; } } diff --git a/derive_macros/src/derive/derive_enum.rs b/derive_macros/src/derive/derive_enum.rs index da0f3649..183b08f9 100644 --- a/derive_macros/src/derive/derive_enum.rs +++ b/derive_macros/src/derive/derive_enum.rs @@ -5,7 +5,7 @@ use crate::{ bound, derive::{ derive_newtype::NewtypeAttrs, derive_struct::StructAttrs, - derive_unit_struct::UnitStructAttrs, + derive_unit_struct::UnitStructAttrs, impl_tokens, }, index::{quote_optional_index, Index, IndexAllocator}, label::{label_or_ident, quote_optional_label}, @@ -178,47 +178,41 @@ pub(crate) fn derive_enum<'a>( } if attrs.dynamic { - quote! { - const _: () = { - extern crate sval; - - impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { - match self { - #(#variant_match_arms)* - } - - Ok(()) - } + impl_tokens( + impl_generics, + ident, + ty_generics, + &bounded_where_clause, + quote!({ + match self { + #(#variant_match_arms)* } - }; - } + + Ok(()) + }), + None, + ) } else { let tag = quote_optional_tag(attrs.tag()); let tag_owned = quote_optional_tag_owned(attrs.tag()); let label = quote_optional_label(Some(label_or_ident(attrs.label(), ident))); let index = quote_optional_index(attrs.index()); - quote! { - const _: () = { - extern crate sval; - - impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { - stream.enum_begin(#tag, #label, #index)?; - - match self { - #(#variant_match_arms)* - } + impl_tokens( + impl_generics, + ident, + ty_generics, + &bounded_where_clause, + quote!({ + stream.enum_begin(#tag, #label, #index)?; - stream.enum_end(#tag, #label, #index) - } - - fn tag(&self) -> Option { - #tag_owned - } + match self { + #(#variant_match_arms)* } - }; - } + + stream.enum_end(#tag, #label, #index) + }), + Some(tag_owned), + ) } } diff --git a/derive_macros/src/derive/derive_newtype.rs b/derive_macros/src/derive/derive_newtype.rs index d2f863d5..aa847f8f 100644 --- a/derive_macros/src/derive/derive_newtype.rs +++ b/derive_macros/src/derive/derive_newtype.rs @@ -1,8 +1,8 @@ use syn::{Attribute, Field, Generics, Ident, Path}; use crate::{ - attr::{self}, - bound, + attr, bound, + derive::impl_tokens, index::{Index, IndexAllocator}, label::label_or_ident, stream::stream_newtype, @@ -88,23 +88,18 @@ pub(crate) fn derive_newtype<'a>( let tag = quote_optional_tag_owned(attrs.tag()); - quote! { - const _: () = { - extern crate sval; - - impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { - match self { - #match_arm - } - - Ok(()) - } - - fn tag(&self) -> Option { - #tag - } + impl_tokens( + impl_generics, + ident, + ty_generics, + &bounded_where_clause, + quote!({ + match self { + #match_arm } - }; - } + + Ok(()) + }), + Some(tag), + ) } diff --git a/derive_macros/src/derive/derive_struct.rs b/derive_macros/src/derive/derive_struct.rs index 86ea7119..4d81b749 100644 --- a/derive_macros/src/derive/derive_struct.rs +++ b/derive_macros/src/derive/derive_struct.rs @@ -1,8 +1,8 @@ use syn::{Attribute, Fields, Generics, Ident, Path}; use crate::{ - attr::{self}, - bound, + attr, bound, + derive::impl_tokens, index::{Index, IndexAllocator}, label::label_or_ident, stream::{stream_record_tuple, RecordTupleTarget}, @@ -100,23 +100,18 @@ pub(crate) fn derive_struct<'a>( let tag = quote_optional_tag_owned(attrs.tag()); - quote! { - const _: () = { - extern crate sval; - - impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { - match self { - #match_arm - } - - Ok(()) - } - - fn tag(&self) -> Option { - #tag - } + impl_tokens( + impl_generics, + ident, + ty_generics, + &bounded_where_clause, + quote!({ + match self { + #match_arm } - }; - } + + Ok(()) + }), + Some(tag), + ) } diff --git a/derive_macros/src/derive/derive_unit_struct.rs b/derive_macros/src/derive/derive_unit_struct.rs index 24196021..26089aba 100644 --- a/derive_macros/src/derive/derive_unit_struct.rs +++ b/derive_macros/src/derive/derive_unit_struct.rs @@ -1,8 +1,8 @@ use syn::{Attribute, Generics, Ident, Path}; use crate::{ - attr::{self}, - bound, + attr, bound, + derive::impl_tokens, index::{Index, IndexAllocator}, label::label_or_ident, stream::stream_tag, @@ -62,23 +62,18 @@ pub(crate) fn derive_unit_struct<'a>( let tag = quote_optional_tag_owned(attrs.tag()); - quote! { - const _: () = { - extern crate sval; - - impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { - match self { - #match_arm - } - - Ok(()) - } - - fn tag(&self) -> Option { - #tag - } + impl_tokens( + impl_generics, + ident, + ty_generics, + &bounded_where_clause, + quote!({ + match self { + #match_arm } - }; - } + + Ok(()) + }), + Some(tag), + ) } diff --git a/derive_macros/src/derive/derive_void.rs b/derive_macros/src/derive/derive_void.rs index 148b4178..cd84decc 100644 --- a/derive_macros/src/derive/derive_void.rs +++ b/derive_macros/src/derive/derive_void.rs @@ -1,6 +1,6 @@ use syn::{Attribute, Generics, Ident}; -use crate::{attr, bound}; +use crate::{attr, bound, derive::impl_tokens}; pub(crate) struct VoidAttrs {} @@ -24,15 +24,12 @@ pub(crate) fn derive_void<'a>( let bound = parse_quote!(sval::Value); let bounded_where_clause = bound::where_clause_with_bound(&generics, bound); - quote! { - const _: () = { - extern crate sval; - - impl #impl_generics sval::Value for #ident #ty_generics #bounded_where_clause { - fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { - match *self {} - } - } - }; - } + impl_tokens( + impl_generics, + ident, + ty_generics, + &bounded_where_clause, + quote!({ match *self {} }), + None, + ) } From e93db075901c385d77d67ce7bcee6d60013b2ab9 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Wed, 4 Oct 2023 09:28:14 +1000 Subject: [PATCH 2/2] add support for using consts as indexes and labels --- derive/test/lib.rs | 15 ++-- derive_macros/src/attr.rs | 69 ++++++++++++++----- derive_macros/src/derive/derive_enum.rs | 20 +++--- derive_macros/src/derive/derive_newtype.rs | 14 ++-- derive_macros/src/derive/derive_struct.rs | 14 ++-- .../src/derive/derive_unit_struct.rs | 14 ++-- derive_macros/src/index.rs | 29 ++++++-- derive_macros/src/label.rs | 44 +++++++++--- .../src/stream/stream_record_tuple.rs | 9 ++- 9 files changed, 155 insertions(+), 73 deletions(-) diff --git a/derive/test/lib.rs b/derive/test/lib.rs index 447f5ba6..ab460163 100644 --- a/derive/test/lib.rs +++ b/derive/test/lib.rs @@ -48,10 +48,13 @@ mod derive_struct { #[test] fn indexed() { + const B_INDEX: sval::Index = sval::Index::new(3); + #[derive(Value)] struct RecordTuple { #[sval(index = 1)] a: i32, + #[sval(index = B_INDEX)] b: i32, } @@ -63,9 +66,9 @@ mod derive_struct { RecordTupleValueBegin(None, sval::Label::new("a"), sval::Index::new(1)), I32(42), RecordTupleValueEnd(None, sval::Label::new("a"), sval::Index::new(1)), - RecordTupleValueBegin(None, sval::Label::new("b"), sval::Index::new(2)), + RecordTupleValueBegin(None, sval::Label::new("b"), sval::Index::new(3)), I32(57), - RecordTupleValueEnd(None, sval::Label::new("b"), sval::Index::new(2)), + RecordTupleValueEnd(None, sval::Label::new("b"), sval::Index::new(3)), RecordTupleEnd(None, Some(sval::Label::new("RecordTuple")), None), ] }) @@ -140,7 +143,7 @@ mod derive_struct { fn data_tagged() { #[derive(Value)] struct RecordTuple { - #[sval(data_tag = "sval::tags::NUMBER")] + #[sval(data_tag = sval::tags::NUMBER)] a: i32, } @@ -236,7 +239,7 @@ mod derive_struct { const FIELD: sval::Tag = sval::Tag::new("field"); #[derive(Value)] - #[sval(tag = "CONTAINER", label = "record", index = 0)] + #[sval(tag = CONTAINER, label = "record", index = 0)] struct Record { #[sval(tag = "FIELD", label = "field0")] a: i32, @@ -329,8 +332,10 @@ mod derive_tuple { #[test] fn labeled() { + const B_LABEL: sval::Label<'static> = sval::Label::new("B"); + #[derive(Value)] - struct RecordTuple(#[sval(label = "A")] i32, #[sval(label = "B")] i32); + struct RecordTuple(#[sval(label = "A")] i32, #[sval(label = B_LABEL)] i32); assert_tokens(&RecordTuple(42, 43), { use sval_test::Token::*; diff --git a/derive_macros/src/attr.rs b/derive_macros/src/attr.rs index 12ba14f0..07d6bf7b 100644 --- a/derive_macros/src/attr.rs +++ b/derive_macros/src/attr.rs @@ -1,6 +1,8 @@ use std::collections::HashSet; -use syn::{spanned::Spanned, Attribute, Expr, ExprUnary, Lit, LitBool, Path, UnOp}; +use syn::{Attribute, Expr, ExprUnary, Lit, Path, UnOp}; + +use crate::{index::IndexValue, label::LabelValue}; /** The `tag` attribute. @@ -13,6 +15,14 @@ pub(crate) struct TagAttr; impl SvalAttribute for TagAttr { type Result = syn::Path; + fn try_from_expr(&self, expr: &Expr) -> Option { + match expr { + Expr::Lit(lit) => Some(self.from_lit(&lit.lit)), + Expr::Path(path) => Some(path.path.clone()), + _ => None, + } + } + fn from_lit(&self, lit: &Lit) -> Self::Result { if let Lit::Str(ref s) = lit { s.parse().expect("invalid value") @@ -39,6 +49,14 @@ pub(crate) struct DataTagAttr; impl SvalAttribute for DataTagAttr { type Result = syn::Path; + fn try_from_expr(&self, expr: &Expr) -> Option { + match expr { + Expr::Lit(lit) => Some(self.from_lit(&lit.lit)), + Expr::Path(path) => Some(path.path.clone()), + _ => None, + } + } + fn from_lit(&self, lit: &Lit) -> Self::Result { if let Lit::Str(ref s) = lit { s.parse().expect("invalid value") @@ -63,11 +81,19 @@ to use for the annotated item. pub(crate) struct LabelAttr; impl SvalAttribute for LabelAttr { - type Result = String; + type Result = LabelValue; + + fn try_from_expr(&self, expr: &Expr) -> Option { + match expr { + Expr::Lit(lit) => Some(self.from_lit(&lit.lit)), + Expr::Path(path) => Some(LabelValue::Ident(quote!(#path))), + _ => None, + } + } fn from_lit(&self, lit: &Lit) -> Self::Result { if let Lit::Str(ref s) = lit { - s.value() + LabelValue::Const(s.value()) } else { panic!("unexpected value") } @@ -88,10 +114,20 @@ to use for the annotated item. */ pub(crate) struct IndexAttr; +impl IndexAttr { + fn const_from_lit(&self, lit: &Lit) -> isize { + if let Lit::Int(ref n) = lit { + n.base10_parse().expect("invalid value") + } else { + panic!("unexpected value") + } + } +} + impl SvalAttribute for IndexAttr { - type Result = isize; + type Result = IndexValue; - fn from_expr(&self, expr: &Expr) -> Option { + fn try_from_expr(&self, expr: &Expr) -> Option { match expr { // Take `-` into account Expr::Unary(ExprUnary { @@ -100,22 +136,19 @@ impl SvalAttribute for IndexAttr { .. }) => { if let Expr::Lit(ref lit) = **expr { - Some(-(self.from_lit(&lit.lit))) + Some(IndexValue::Const(-(self.const_from_lit(&lit.lit)))) } else { None } } - Expr::Lit(lit) => Some(self.from_lit(&lit.lit)), + Expr::Lit(lit) => Some(IndexValue::Const(self.const_from_lit(&lit.lit))), + Expr::Path(path) => Some(IndexValue::Ident(quote!(#path))), _ => None, } } fn from_lit(&self, lit: &Lit) -> Self::Result { - if let Lit::Int(ref n) = lit { - n.base10_parse().expect("invalid value") - } else { - panic!("unexpected value") - } + IndexValue::Const(self.const_from_lit(lit)) } } @@ -292,7 +325,7 @@ pub(crate) trait RawAttribute { pub(crate) trait SvalAttribute: RawAttribute { type Result: 'static; - fn from_expr(&self, expr: &Expr) -> Option { + fn try_from_expr(&self, expr: &Expr) -> Option { if let Expr::Lit(lit) = expr { Some(self.from_lit(&lit.lit)) } else { @@ -363,7 +396,7 @@ pub(crate) fn get_unchecked( .flatten() { if value_key.is_ident(request_key) { - return Some(request.from_lit(&value)); + return Some(request.try_from_expr(&value).expect("unexpected value")); } } @@ -373,23 +406,23 @@ pub(crate) fn get_unchecked( fn sval_attr<'a>( ctxt: &'a str, attr: &'_ Attribute, -) -> Option + 'a> { +) -> Option + 'a> { if !attr.path().is_ident("sval") { return None; } let mut results = Vec::new(); attr.parse_nested_meta(|meta| { - let lit: Lit = match meta.value() { + let expr: Expr = match meta.value() { Ok(value) => value.parse()?, // If there isn't a value associated with the item // then use the boolean `true` - Err(_) => Lit::Bool(LitBool::new(true, meta.path.span())), + Err(_) => syn::parse_quote!(true), }; let path = meta.path; - results.push((path, lit)); + results.push((path, expr)); Ok(()) }) diff --git a/derive_macros/src/derive/derive_enum.rs b/derive_macros/src/derive/derive_enum.rs index 183b08f9..27e42260 100644 --- a/derive_macros/src/derive/derive_enum.rs +++ b/derive_macros/src/derive/derive_enum.rs @@ -7,16 +7,16 @@ use crate::{ derive_newtype::NewtypeAttrs, derive_struct::StructAttrs, derive_unit_struct::UnitStructAttrs, impl_tokens, }, - index::{quote_optional_index, Index, IndexAllocator}, - label::{label_or_ident, quote_optional_label}, + index::{quote_optional_index, Index, IndexAllocator, IndexValue}, + label::{label_or_ident, quote_optional_label, LabelValue}, stream::{stream_newtype, stream_record_tuple, stream_tag, RecordTupleTarget}, tag::{quote_optional_tag, quote_optional_tag_owned}, }; pub(crate) struct EnumAttrs { tag: Option, - label: Option, - index: Option, + label: Option, + index: Option, dynamic: bool, } @@ -56,12 +56,12 @@ impl EnumAttrs { self.tag.as_ref() } - pub(crate) fn label(&self) -> Option<&str> { - self.label.as_deref() + pub(crate) fn label(&self) -> Option { + self.label.clone() } pub(crate) fn index(&self) -> Option { - self.index.map(IndexAllocator::const_index_of) + self.index.clone().map(IndexAllocator::const_index_of) } } @@ -79,7 +79,7 @@ pub(crate) fn derive_enum<'a>( let mut variant_match_arms = Vec::new(); let mut index_allocator = IndexAllocator::new(); - let mut variant_index = |index: Option, discriminant: Option| { + let mut variant_index = |index: Option, discriminant: Option| { index.or_else(|| { if attrs.dynamic { None @@ -89,7 +89,7 @@ pub(crate) fn derive_enum<'a>( }) }; - let variant_label = |label: Option<&str>, ident: &Ident| { + let variant_label = |label: Option, ident: &Ident| { if attrs.dynamic { None } else { @@ -119,7 +119,7 @@ pub(crate) fn derive_enum<'a>( let discriminant = variant .discriminant .as_ref() - .and_then(|(_, discriminant)| attr::IndexAttr.from_expr(discriminant)); + .and_then(|(_, discriminant)| attr::IndexAttr.try_from_expr(discriminant)); let variant_ident = &variant.ident; diff --git a/derive_macros/src/derive/derive_newtype.rs b/derive_macros/src/derive/derive_newtype.rs index aa847f8f..6662826c 100644 --- a/derive_macros/src/derive/derive_newtype.rs +++ b/derive_macros/src/derive/derive_newtype.rs @@ -3,16 +3,16 @@ use syn::{Attribute, Field, Generics, Ident, Path}; use crate::{ attr, bound, derive::impl_tokens, - index::{Index, IndexAllocator}, - label::label_or_ident, + index::{Index, IndexAllocator, IndexValue}, + label::{label_or_ident, LabelValue}, stream::stream_newtype, tag::quote_optional_tag_owned, }; pub(crate) struct NewtypeAttrs { tag: Option, - label: Option, - index: Option, + label: Option, + index: Option, transparent: bool, } @@ -53,12 +53,12 @@ impl NewtypeAttrs { self.tag.as_ref() } - pub(crate) fn label(&self) -> Option<&str> { - self.label.as_deref() + pub(crate) fn label(&self) -> Option { + self.label.clone() } pub(crate) fn index(&self) -> Option { - self.index.map(IndexAllocator::const_index_of) + self.index.clone().map(IndexAllocator::const_index_of) } pub(crate) fn transparent(&self) -> bool { diff --git a/derive_macros/src/derive/derive_struct.rs b/derive_macros/src/derive/derive_struct.rs index 4d81b749..d6bd4efb 100644 --- a/derive_macros/src/derive/derive_struct.rs +++ b/derive_macros/src/derive/derive_struct.rs @@ -3,16 +3,16 @@ use syn::{Attribute, Fields, Generics, Ident, Path}; use crate::{ attr, bound, derive::impl_tokens, - index::{Index, IndexAllocator}, - label::label_or_ident, + index::{Index, IndexAllocator, IndexValue}, + label::{label_or_ident, LabelValue}, stream::{stream_record_tuple, RecordTupleTarget}, tag::quote_optional_tag_owned, }; pub(crate) struct StructAttrs { tag: Option, - label: Option, - index: Option, + label: Option, + index: Option, unlabeled_fields: bool, unindexed_fields: bool, } @@ -53,12 +53,12 @@ impl StructAttrs { self.tag.as_ref() } - pub(crate) fn label(&self) -> Option<&str> { - self.label.as_deref() + pub(crate) fn label(&self) -> Option { + self.label.clone() } pub(crate) fn index(&self) -> Option { - self.index.map(IndexAllocator::const_index_of) + self.index.clone().map(IndexAllocator::const_index_of) } pub(crate) fn unlabeled_fields(&self) -> bool { diff --git a/derive_macros/src/derive/derive_unit_struct.rs b/derive_macros/src/derive/derive_unit_struct.rs index 26089aba..58ce0578 100644 --- a/derive_macros/src/derive/derive_unit_struct.rs +++ b/derive_macros/src/derive/derive_unit_struct.rs @@ -3,16 +3,16 @@ use syn::{Attribute, Generics, Ident, Path}; use crate::{ attr, bound, derive::impl_tokens, - index::{Index, IndexAllocator}, - label::label_or_ident, + index::{Index, IndexAllocator, IndexValue}, + label::{label_or_ident, LabelValue}, stream::stream_tag, tag::quote_optional_tag_owned, }; pub(crate) struct UnitStructAttrs { tag: Option, - label: Option, - index: Option, + label: Option, + index: Option, } impl UnitStructAttrs { @@ -34,12 +34,12 @@ impl UnitStructAttrs { self.tag.as_ref() } - pub(crate) fn label(&self) -> Option<&str> { - self.label.as_deref() + pub(crate) fn label(&self) -> Option { + self.label.clone() } pub(crate) fn index(&self) -> Option { - self.index.map(IndexAllocator::const_index_of) + self.index.clone().map(IndexAllocator::const_index_of) } } diff --git a/derive_macros/src/index.rs b/derive_macros/src/index.rs index ac5e0b9c..b1e9d21d 100644 --- a/derive_macros/src/index.rs +++ b/derive_macros/src/index.rs @@ -11,16 +11,27 @@ impl IndexAllocator { } } - pub(crate) fn const_index_of(explicit: isize) -> Index { - Index::Explicit(quote!(#explicit)) + pub(crate) fn const_index_of(explicit: IndexValue) -> Index { + match explicit { + IndexValue::Const(explicit) => Index::Explicit(quote!(#explicit)), + IndexValue::Ident(explicit) => Index::Explicit(explicit), + } } - pub(crate) fn next_const_index(&mut self, explicit: Option) -> Index { - if let Some(index) = explicit { + pub(crate) fn next_const_index(&mut self, explicit: Option) -> Index { + if let Some(explicit) = explicit { self.explicit = true; + + let index = match explicit { + IndexValue::Const(explicit) => explicit, + // If we can't compute an index from the value then + // just increment the one we've got + _ => self.next_const_index, + }; + self.next_const_index = index + 1; - Index::Explicit(quote!(#index)) + Self::const_index_of(explicit) } else { let index = self.next_const_index; self.next_const_index += 1; @@ -36,7 +47,7 @@ impl IndexAllocator { pub(crate) fn next_computed_index( &mut self, ident: &syn::Ident, - explicit: Option, + explicit: Option, ) -> Index { match self.next_const_index(explicit) { Index::Implicit(_) => Index::Implicit(quote!({ @@ -49,6 +60,12 @@ impl IndexAllocator { } } +#[derive(Debug, Clone)] +pub(crate) enum IndexValue { + Const(isize), + Ident(proc_macro2::TokenStream), +} + #[derive(Debug, Clone)] pub(crate) enum Index { Implicit(proc_macro2::TokenStream), diff --git a/derive_macros/src/label.rs b/derive_macros/src/label.rs index 5a084770..e31a72c1 100644 --- a/derive_macros/src/label.rs +++ b/derive_macros/src/label.rs @@ -1,30 +1,54 @@ use syn::Ident; +#[derive(Debug, Clone)] +pub(crate) enum LabelValue { + Const(String), + Ident(proc_macro2::TokenStream), +} + #[derive(Debug, Clone)] pub(crate) enum Label { - Ident(String), - Text(String), + Implicit(proc_macro2::TokenStream), + Const(proc_macro2::TokenStream), + Ident(proc_macro2::TokenStream), } -pub(crate) fn label_or_ident<'a>(explicit: Option<&str>, ident: &Ident) -> Label { +fn explicit_label(explicit: LabelValue) -> Label { + match explicit { + LabelValue::Const(explicit) => Label::Const(quote!(#explicit)), + LabelValue::Ident(explicit) => Label::Ident(explicit), + } +} + +fn ident_label(ident: &Ident) -> Label { + Label::Implicit({ + let ident = ident.to_string(); + quote!(#ident) + }) +} + +pub(crate) fn label_or_ident<'a>(explicit: Option, ident: &Ident) -> Label { explicit - .map(|text| Label::Text(text.to_owned())) - .unwrap_or_else(|| Label::Ident(ident.to_string())) + .map(explicit_label) + .unwrap_or_else(|| ident_label(ident)) } pub(crate) fn optional_label_or_ident<'a>( - explicit: Option<&str>, + explicit: Option, ident: Option<&Ident>, ) -> Option