diff --git a/tabled/examples/derive/display_with.rs b/tabled/examples/derive/display_with.rs index c1e89b53..5f61e1b8 100644 --- a/tabled/examples/derive/display_with.rs +++ b/tabled/examples/derive/display_with.rs @@ -10,8 +10,6 @@ //! * Attribute arguments can be directly overridden with static values, effectively ignoring the //! augmented fields natural value entirely. Even an entire object can be passed as context with `self`. -use std::borrow::Cow; - use tabled::{Table, Tabled}; #[derive(Tabled)] @@ -19,33 +17,38 @@ struct Country { name: String, #[tabled(display_with = "str::to_uppercase")] capital: String, - #[tabled(display_with("display_perimeter", self))] + #[tabled(display_with("perimeter", self, false))] area_km2: f32, + #[tabled(display_with("tabled::derive::display::option", "unknown"))] + currency: Option, } -impl Country { - fn new(name: &str, capital: &str, area_km2: f32) -> Self { - Self { - name: name.to_string(), - capital: capital.to_string(), - area_km2, - } - } -} - -fn display_perimeter(country: &Country) -> Cow<'_, str> { - if country.area_km2 > 1_000_000.0 { - "BIG".into() - } else { - "small".into() - } +fn perimeter<'a>(area: &f32, country: &Country, _milies: bool) -> String { + let is_big = *area > 1_000_000.0f32; + let big_sign = if is_big { "B" } else { "" }; + format!("{} {}", country.area_km2, big_sign) } fn main() { let data = [ - Country::new("Afghanistan", "Kabul", 652867.0), - Country::new("Angola", "Luanda", 1246700.0), - Country::new("Canada", "Ottawa", 9984670.0), + Country { + name: String::from("Afghanistan"), + capital: String::from("Kabul"), + area_km2: 652867.0, + currency: Some(String::from("Afghan afghani (AFN)")), + }, + Country { + name: String::from("Angola"), + capital: String::from("Luanda"), + area_km2: 1246700.0, + currency: None, + }, + Country { + name: String::from("Canada"), + capital: String::from("Ottawa"), + area_km2: 9984670.0, + currency: None, + }, ]; let table = Table::new(data); diff --git a/tabled/src/derive/display/mod.rs b/tabled/src/derive/display/mod.rs index 6345e032..18a912a8 100644 --- a/tabled/src/derive/display/mod.rs +++ b/tabled/src/derive/display/mod.rs @@ -5,6 +5,11 @@ use core::fmt::Debug; /// A function which is usefull in conjuntion with /// `#[tabled(display_with)]` and `#[tabled(display_type)]`. /// +/// It can be used with any [`Option`] type. +/// You must provide a second argument which represents a value be printed in case of [`None`]. +/// +/// # Example +/// /// ``` /// use tabled::Tabled; /// use tabled::derive::display; @@ -51,6 +56,9 @@ where /// A function which is usefull in conjuntion with /// `#[tabled(display_with)]` and `#[tabled(display_type)]`. /// +/// It can be used with any type which implements a [`Debug`]. +/// So rather then [`std::fmt::Display`] usage we will be using a debug implementation. +/// /// ``` /// use tabled::Tabled; /// use tabled::derive::display; @@ -63,12 +71,6 @@ where /// state: Option<&'a str> /// } /// -/// #[derive(Debug)] -/// pub enum State { -/// Proved, -/// Investigation, -/// } -/// /// let data = vec![ /// ZKP { application: "Decentralized Identity", state: Some("Proved") }, /// ZKP { application: "Voting Systems", state: Some("Investigation") }, @@ -96,3 +98,45 @@ where { format!("{:?}", value) } + +/// A function which is usefull in conjuntion with +/// `#[tabled(display_with)]` and `#[tabled(display_type)]`. +/// +/// It just returns an empty string. +/// +/// ``` +/// use tabled::Tabled; +/// use tabled::derive::display; +/// use testing_table::assert_table; +/// +/// #[derive(Tabled)] +/// pub struct ZKP<'a> { +/// application: &'a str, +/// #[tabled(display_with = "display::empty")] +/// state: Option<&'a str> +/// } +/// +/// let data = vec![ +/// ZKP { application: "Decentralized Identity", state: Some("Proved") }, +/// ZKP { application: "Voting Systems", state: Some("Investigation") }, +/// ZKP { application: "Privacy-Preserving Transactions", state: None }, +/// ]; +/// +/// let table = tabled::Table::new(data); +/// +/// assert_table!( +/// table, +/// r#"+---------------------------------+-------+"# +/// r#"| application | state |"# +/// r#"+---------------------------------+-------+"# +/// r#"| Decentralized Identity | |"# +/// r#"+---------------------------------+-------+"# +/// r#"| Voting Systems | |"# +/// r#"+---------------------------------+-------+"# +/// r#"| Privacy-Preserving Transactions | |"# +/// r#"+---------------------------------+-------+"# +/// ); +/// ``` +pub fn empty(_value: &T) -> String { + String::new() +} diff --git a/tabled/src/derive/mod.rs b/tabled/src/derive/mod.rs index 82de1b98..32b0e514 100644 --- a/tabled/src/derive/mod.rs +++ b/tabled/src/derive/mod.rs @@ -114,8 +114,8 @@ pub mod display; /// } /// /// impl MyRecord { -/// fn display_valid(&self) -> String { -/// match self.valid { +/// fn display_valid(_: &Option, s: &Self) -> String { +/// match s.valid { /// Some(s) => format!("is valid thing = {}", s), /// None => format!("is not valid"), /// } diff --git a/tabled/tests/derive/derive_test.rs b/tabled/tests/derive/derive_test.rs index ece97781..48eed99f 100644 --- a/tabled/tests/derive/derive_test.rs +++ b/tabled/tests/derive/derive_test.rs @@ -174,7 +174,7 @@ mod tuple { { 0 Some("v2") }, { ["0", "1"], ["0", "some 1 234"] }, pre: { - fn display_option(val: usize, text: &str) -> String { + fn display_option(_opt: &Option, val: usize, text: &str) -> String { format!("some {val} {text}") } } @@ -204,7 +204,7 @@ mod tuple { { ["0", "1"], ["0", "some v2"] }, pre: { impl TestType { - fn display_option(o: &TestType) -> String { + fn display_option(_opt: &Option, o: &TestType) -> String { match o.1 { Some(s) => format!("some {s}"), None => "none".to_string(), @@ -220,7 +220,7 @@ mod tuple { { 0 Some("v2") }, { ["0", "1"], ["0", "some v2"] }, pre: { - fn display_option(o: &TestType) -> String { + fn display_option(_opt: &Option, o: &TestType) -> String { match o.1 { Some(s) => format!("some {s}"), None => "none".to_string(), @@ -235,7 +235,7 @@ mod tuple { { 0 Some("v2") }, { ["0", "1"], ["0", "some 0.0"] }, pre: { - fn display_option(o1: u8, o2: u8) -> String { + fn display_option(_opt: &Option, o1: u8, o2: u8) -> String { format!("some {o1}.{o2}") } } @@ -364,7 +364,7 @@ mod enum_ { } }, { - fn display(_: &T) -> String { + fn display(_opt: &sstr, _: &T) -> String { "asd".to_string() } }, @@ -413,7 +413,7 @@ mod enum_ { }, { impl TestType { - fn format(&self) -> String { + fn format(_opt: &sstr, _: &Self) -> String { ID.to_string() } } @@ -439,7 +439,7 @@ mod enum_ { }, { impl TestType { - fn format(&self, _: sstr) -> String { + fn format(_opt: &sstr, _: &Self, _: sstr) -> String { ID.to_string() } } @@ -465,7 +465,7 @@ mod enum_ { }, { impl TestType { - fn format(&self, _: sstr) -> String { + fn format(_opt: &sstr, _: &Self, _: sstr) -> String { ID.to_string() } } @@ -1064,7 +1064,7 @@ mod structure { } } { - fn display_option(v1: usize, v2: usize, v3: usize) -> String { + fn display_option(_opt: &Option, v1: usize, v2: usize, v3: usize) -> String { format!("{v1} {v2} {v3}") } } @@ -1081,7 +1081,7 @@ mod structure { } } { - fn display_option(v1: &u8, v2: usize, v3: usize) -> String { + fn display_option(_opt: &Option, v1: &u8, v2: usize, v3: usize) -> String { format!("{v1} {v2} {v3}") } } @@ -1121,7 +1121,7 @@ mod structure { } { impl TestType { - fn display_option(o: &TestType) -> String { + fn display_option(_opt: &Option, o: &TestType) -> String { match o.f2 { Some(s) => format!("some {s}"), None => "none".to_string(), @@ -1143,8 +1143,8 @@ mod structure { } { impl TestType { - fn display_option(&self) -> String { - match self.f2 { + fn display_option(_opt: &Option, s: &Self) -> String { + match s.f2 { Some(s) => format!("some {s}"), None => "none".to_string(), } @@ -1164,7 +1164,7 @@ mod structure { } } { - fn display_option(o: &TestType) -> String { + fn display_option(_opt: &Option, o: &TestType) -> String { match o.f2 { Some(s) => format!("some {s}"), None => "none".to_string(), @@ -1186,7 +1186,7 @@ mod structure { } } { - fn display_option(v1: &[u8; 2], v4: String) -> String { + fn display_option(_opt: &Option, v1: &[u8; 2], v4: String) -> String { format!("{} {} {v4}", v1[0], v1[1]) } } @@ -1579,15 +1579,15 @@ fn test_macros_in_display_with() { national_currency_short: String, } - fn display_perimeter(country: &Country) -> std::borrow::Cow<'_, str> { + fn display_perimeter(_area: &f32, country: &Country) -> sstr { if country.area_km2 > 1_000_000.0 { - "Very Big Land".into() + "Very Big Land" } else { - "Big Land".into() + "Big Land" } } - fn display_capital(country: String) -> std::borrow::Cow<'static, str> { + fn display_capital(_capital: &str, country: String) -> std::borrow::Cow<'static, str> { format!("{country}!").into() } } diff --git a/tabled_derive/src/lib.rs b/tabled_derive/src/lib.rs index 817a3163..f095ebef 100644 --- a/tabled_derive/src/lib.rs +++ b/tabled_derive/src/lib.rs @@ -503,20 +503,19 @@ fn get_field_fields( field_name: FieldNameFn, type_attrs: &TypeAttributes, ) -> TokenStream { + // TODO: Remove this `format!`? + if attr.inline { return quote! { #field.fields() }; } if let Some(func) = &attr.display_with { let args = match &attr.display_with_args { - None => Some(quote!(&#field)), - Some(args) => args_to_tokens(fields, field_name, args), + Some(args) => args_to_tokens_with(fields, field, field_name, args), + None => quote!(&#field), }; - let result = match args { - Some(args) => use_function(&args, func), - None => use_function_no_args(func), - }; + let result = use_function(&args, func); return quote!(vec![::std::borrow::Cow::from(format!("{}", #result))]); } else if let Some(custom_format) = &attr.format { @@ -536,7 +535,7 @@ fn get_field_fields( 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); + let func = use_function(&args, func); return quote!(vec![::std::borrow::Cow::from(format!("{}", #func))]); }