Skip to content

Commit

Permalink
add support for using consts as indexes and labels
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Oct 3, 2023
1 parent c288c0e commit e93db07
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 73 deletions.
15 changes: 10 additions & 5 deletions derive/test/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand All @@ -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),
]
})
Expand Down Expand Up @@ -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,
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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::*;
Expand Down
69 changes: 51 additions & 18 deletions derive_macros/src/attr.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -13,6 +15,14 @@ pub(crate) struct TagAttr;
impl SvalAttribute for TagAttr {
type Result = syn::Path;

fn try_from_expr(&self, expr: &Expr) -> Option<Self::Result> {
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")
Expand All @@ -39,6 +49,14 @@ pub(crate) struct DataTagAttr;
impl SvalAttribute for DataTagAttr {
type Result = syn::Path;

fn try_from_expr(&self, expr: &Expr) -> Option<Self::Result> {
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")
Expand All @@ -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<Self::Result> {
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")
}
Expand All @@ -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<Self::Result> {
fn try_from_expr(&self, expr: &Expr) -> Option<Self::Result> {
match expr {
// Take `-` into account
Expr::Unary(ExprUnary {
Expand All @@ -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))
}
}

Expand Down Expand Up @@ -292,7 +325,7 @@ pub(crate) trait RawAttribute {
pub(crate) trait SvalAttribute: RawAttribute {
type Result: 'static;

fn from_expr(&self, expr: &Expr) -> Option<Self::Result> {
fn try_from_expr(&self, expr: &Expr) -> Option<Self::Result> {
if let Expr::Lit(lit) = expr {
Some(self.from_lit(&lit.lit))
} else {
Expand Down Expand Up @@ -363,7 +396,7 @@ pub(crate) fn get_unchecked<T: SvalAttribute>(
.flatten()
{
if value_key.is_ident(request_key) {
return Some(request.from_lit(&value));
return Some(request.try_from_expr(&value).expect("unexpected value"));
}
}

Expand All @@ -373,23 +406,23 @@ pub(crate) fn get_unchecked<T: SvalAttribute>(
fn sval_attr<'a>(
ctxt: &'a str,
attr: &'_ Attribute,
) -> Option<impl IntoIterator<Item = (Path, Lit)> + 'a> {
) -> Option<impl IntoIterator<Item = (Path, Expr)> + '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(())
})
Expand Down
20 changes: 10 additions & 10 deletions derive_macros/src/derive/derive_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path>,
label: Option<String>,
index: Option<isize>,
label: Option<LabelValue>,
index: Option<IndexValue>,
dynamic: bool,
}

Expand Down Expand Up @@ -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<LabelValue> {
self.label.clone()
}

pub(crate) fn index(&self) -> Option<Index> {
self.index.map(IndexAllocator::const_index_of)
self.index.clone().map(IndexAllocator::const_index_of)
}
}

Expand All @@ -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<Index>, discriminant: Option<isize>| {
let mut variant_index = |index: Option<Index>, discriminant: Option<IndexValue>| {
index.or_else(|| {
if attrs.dynamic {
None
Expand All @@ -89,7 +89,7 @@ pub(crate) fn derive_enum<'a>(
})
};

let variant_label = |label: Option<&str>, ident: &Ident| {
let variant_label = |label: Option<LabelValue>, ident: &Ident| {
if attrs.dynamic {
None
} else {
Expand Down Expand Up @@ -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;

Expand Down
14 changes: 7 additions & 7 deletions derive_macros/src/derive/derive_newtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path>,
label: Option<String>,
index: Option<isize>,
label: Option<LabelValue>,
index: Option<IndexValue>,
transparent: bool,
}

Expand Down Expand Up @@ -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<LabelValue> {
self.label.clone()
}

pub(crate) fn index(&self) -> Option<Index> {
self.index.map(IndexAllocator::const_index_of)
self.index.clone().map(IndexAllocator::const_index_of)
}

pub(crate) fn transparent(&self) -> bool {
Expand Down
14 changes: 7 additions & 7 deletions derive_macros/src/derive/derive_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path>,
label: Option<String>,
index: Option<isize>,
label: Option<LabelValue>,
index: Option<IndexValue>,
unlabeled_fields: bool,
unindexed_fields: bool,
}
Expand Down Expand Up @@ -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<LabelValue> {
self.label.clone()
}

pub(crate) fn index(&self) -> Option<Index> {
self.index.map(IndexAllocator::const_index_of)
self.index.clone().map(IndexAllocator::const_index_of)
}

pub(crate) fn unlabeled_fields(&self) -> bool {
Expand Down
14 changes: 7 additions & 7 deletions derive_macros/src/derive/derive_unit_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path>,
label: Option<String>,
index: Option<isize>,
label: Option<LabelValue>,
index: Option<IndexValue>,
}

impl UnitStructAttrs {
Expand All @@ -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<LabelValue> {
self.label.clone()
}

pub(crate) fn index(&self) -> Option<Index> {
self.index.map(IndexAllocator::const_index_of)
self.index.clone().map(IndexAllocator::const_index_of)
}
}

Expand Down
Loading

0 comments on commit e93db07

Please sign in to comment.