Skip to content

Commit

Permalink
Add display_type support for matching generic types by name (without …
Browse files Browse the repository at this point in the history
…generic)
  • Loading branch information
zhiburt committed Feb 1, 2025
1 parent 25008da commit d027705
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
9 changes: 6 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,18 @@ pub struct Country {
capital: Option<String>,
}

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

#[derive(Tabled)]
#[tabled(display_type(Option<String>, "display_option", "UNKNOWN"))]
#[tabled(display_type(Option, "display_option", "UNKNOWN"))]
pub struct CountryDisplay {
name: String,
capital: Option<String>,
Expand Down
28 changes: 25 additions & 3 deletions tabled_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,15 +580,37 @@ fn args_to_tokens_with(
}

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

for (i, (display_type, _, _)) in types.iter().enumerate() {
if display_type.path == path.path {
// NOTICE:
// We do iteration in a back order to satisfy a later set argument first.
//
// TODO: Maybe we shall change the data structure for it rather then doing a reverse iteration?
// I am just saying it's dirty a little.
let args = types.iter().enumerate().rev();
for (i, (arg, _, _)) in args {
if arg.path == p.path {
return Some(i);
}

// NOTICE:
// There's a specical case where we wanna match a type without a generic,
// e.g. 'Option' with which we wanna match all 'Option's.
//
// Because in the scope we can only have 1 type name, it's considered to be good,
// and nothing must be broken.
let arg_segment = arg.path.segments.last();
let type_segment = p.path.segments.last();
if let Some(arg) = arg_segment {
if let Some(p) = type_segment {
if p.ident == arg.ident {
return Some(i);
}
}
}
}

None
Expand Down

0 comments on commit d027705

Please sign in to comment.