Skip to content

Commit

Permalink
Add arguments support to display_type
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiburt committed Jan 31, 2025
1 parent 175a8cd commit 25008da
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 36 deletions.
6 changes: 3 additions & 3 deletions tabled/examples/derive/display_with_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ pub struct Country {
capital: Option<String>,
}

fn display_option(opt: &Option<String>) -> String {
fn display_option(opt: &Option<String>, default: &str) -> String {
match opt {
Some(val) => val.to_uppercase(),
None => "UNKNOWN".to_string(),
None => default.to_string(),
}
}

#[derive(Tabled)]
#[tabled(display_type(Option<String>, "display_option"))]
#[tabled(display_type(Option<String>, "display_option", "UNKNOWN"))]
pub struct CountryDisplay {
name: String,
capital: Option<String>,
Expand Down
8 changes: 5 additions & 3 deletions tabled_derive/src/attributes/type_attr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use syn::{Attribute, TypePath};

use crate::{
attributes::FormatArg,
casing_style::CasingStyle,
error::Error,
parse::type_attr::{parse_type_attributes, TypeAttr, TypeAttrKind},
Expand All @@ -12,7 +13,7 @@ pub struct TypeAttributes {
pub inline: bool,
pub inline_value: Option<String>,
pub crate_name: Option<String>,
pub display_types: Vec<(TypePath, String)>,
pub display_types: Vec<(TypePath, String, Vec<FormatArg>)>,
}

impl TypeAttributes {
Expand Down Expand Up @@ -54,8 +55,9 @@ impl TypeAttributes {
TypeAttrKind::RenameAll(lit) => {
self.rename_all = Some(CasingStyle::from_lit(&lit)?);
}
TypeAttrKind::DisplayType(type_name, func) => {
self.display_types.push((type_name, func.value()));
TypeAttrKind::DisplayType(type_name, func, args) => {
let args = args.into_iter().map(FormatArg::new).collect();
self.display_types.push((type_name, func.value(), args));
}
}

Expand Down
76 changes: 48 additions & 28 deletions tabled_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,16 +510,7 @@ fn get_field_fields(
if let Some(func) = &attr.display_with {
let args = match &attr.display_with_args {
None => Some(quote!(&#field)),
Some(args) => match args.is_empty() {
true => None,
false => {
let args = args
.iter()
.map(|arg| fnarg_tokens(arg, fields, field_name))
.collect::<Vec<_>>();
Some(quote!( #(#args,)* ))
}
},
Some(args) => args_to_tokens(fields, field_name, args),
};

let result = match args {
Expand All @@ -529,19 +520,10 @@ fn get_field_fields(

return quote!(vec![::std::borrow::Cow::from(format!("{}", #result))]);
} else if let Some(custom_format) = &attr.format {
let args = match &attr.format_with_args {
None => None,
Some(args) => match args.is_empty() {
true => None,
false => {
let args = args
.iter()
.map(|arg| fnarg_tokens(arg, fields, field_name))
.collect::<Vec<_>>();
Some(quote!( #(#args,)* ))
}
},
};
let args = attr
.format_with_args
.as_ref()
.and_then(|args| args_to_tokens(fields, field_name, args));

let call = match args {
Some(args) => use_format(&args, custom_format),
Expand All @@ -551,23 +533,61 @@ fn get_field_fields(
return quote!(vec![::std::borrow::Cow::Owned(#call)]);
}

if let Some(func) = find_display_type(field_type, &type_attrs.display_types) {
let func = use_function(&quote!(&#field), &func);
if let Some(i) = find_display_type(field_type, &type_attrs.display_types) {
let (_, func, args) = &type_attrs.display_types[i];
let args = args_to_tokens_with(fields, field, field_name, args);
let func = use_function(&args, &func);

return quote!(vec![::std::borrow::Cow::from(format!("{}", #func))]);
}

quote!(vec![::std::borrow::Cow::Owned(format!("{}", #field))])
}

fn find_display_type(ty: &Type, types: &[(TypePath, String)]) -> Option<String> {
fn args_to_tokens(
fields: &Fields,
field_name: fn(usize, &Field) -> TokenStream,
args: &[FormatArg],
) -> Option<TokenStream> {
if args.is_empty() {
return None;
}

let args = args
.iter()
.map(|arg| fnarg_tokens(arg, fields, field_name))
.collect::<Vec<_>>();
Some(quote!( #(#args,)* ))
}

fn args_to_tokens_with(
fields: &Fields,
field: &TokenStream,
field_name: fn(usize, &Field) -> TokenStream,
args: &[FormatArg],
) -> TokenStream {
if args.is_empty() {
return quote!(&#field);
}

let mut out = vec![quote!(&#field)];
for arg in args {
let arg = fnarg_tokens(arg, fields, field_name);
out.push(arg);
}

quote!( #(#out,)* )
}

fn find_display_type(ty: &Type, types: &[(TypePath, String, Vec<FormatArg>)]) -> Option<usize> {
let path: &TypePath = match ty {
Type::Path(path) => path,
_ => return None,
};

for (display_type, display_func) in types {
for (i, (display_type, _, _)) in types.iter().enumerate() {
if display_type.path == path.path {
return Some(display_func.clone());
return Some(i);
}
}

Expand Down
18 changes: 16 additions & 2 deletions tabled_derive/src/parse/type_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub enum TypeAttrKind {
Inline(LitBool, Option<LitStr>),
RenameAll(LitStr),
Crate(LitStr),
DisplayType(TypePath, LitStr),
DisplayType(TypePath, LitStr, Punctuated<syn::Expr, Token!(,)>),
}

impl Parse for TypeAttr {
Expand Down Expand Up @@ -92,7 +92,21 @@ impl Parse for TypeAttr {
let _comma = nested.parse::<Token![,]>()?;
let lit = nested.parse::<LitStr>()?;

return Ok(Self::new(DisplayType(path, lit)));
let mut args: Punctuated<syn::Expr, token::Comma> = Punctuated::new();
if nested.peek(Token![,]) {
_ = nested.parse::<Token![,]>()?;
while !nested.is_empty() {
let val = nested.parse()?;
args.push_value(val);
if nested.is_empty() {
break;
}
let punct = nested.parse()?;
args.push_punct(punct);
}
}

return Ok(Self::new(DisplayType(path, lit, args)));
}

return Err(syn::Error::new(
Expand Down

0 comments on commit 25008da

Please sign in to comment.