amplify

Derive Macro Display

Source
#[derive(Display)]
{
    // Attributes available to this derive:
    #[display]
}
Expand description

§Usage

  1. Generate Display descriptions using other formatting trait:
     #[derive(Display, Debug)]
     #[display(Debug)]
     enum Some {
         Once,
         Twice(u8)
     }
  2. Use existing function for displaying descriptions:
     #[macro_use] extern crate amplify;
    
     #[derive(Display)]
     #[display(Int::print)]
     union Int { uint: u32, int: i32 };
     impl Int {
         pub fn print(&self) -> String {
             s!("Integer representation")
         }
     }
    
     pub trait ToSpecialString {
         fn to_special_string(&self) -> String {
             s!("Special string")
         }
     }
    
     #[derive(Display)]
     #[display(Some::to_special_string)]
     struct Some { uint: u32, int: i32 };
     impl ToSpecialString for Some {}
    
     assert_eq!(
         format!("{}", Int { uint: 2 }),
         s!("Integer representation")
     );
    
     #[derive(Display)]
     #[display(some_fmt)]
     enum Enum { Once(u8), Twice };
     fn some_fmt(_: &Enum) -> String { s!("Some") }
     assert_eq!(format!("{}", Enum::Once(3)), s!("Some"))
    Formatting function must return [String] and take a single self argument (if you need formatting with streamed output, use one of existing formatting traits as shown in pt. 1).
  3. Custom format string:
     #[derive(Display)]
     #[display("({x}, {y})")]
     struct Point { x: u32, y: u32 }
     assert_eq!(format!("{}", Point { x: 0, y: 1 }), "(0, 1)");
    
     #[derive(Display)]
     #[display("[{vec}]")]
     struct Data { #[display(separator = ", ")] vec: Vec<String> }
     assert_eq!(format!("{}", Data { vec: vec!["foo".into(), "bar".into()]}),
         "[foo, bar]");
  4. Support for alternative formatting with alt parameter:
     #[derive(Display)]
     #[display("({x}, {y})", alt = "{x}:{y}")]
     struct Point { x: u32, y: u32 }
     assert_eq!(format!("{}", Point { x: 0, y: 1 }), "(0, 1)");
     assert_eq!(format!("{:#}", Point { x: 0, y: 1 }), "0:1");
  5. Use of doc comments for descrition representation. In this case doc comments may also contain formatting like in the case 3:
     #[macro_use] extern crate amplify;
    
     /// Example enum with doc comments converted into display
     #[derive(Display)]
     #[display(doc_comments)]
     enum Variants {
         /// Letter A.
         /// Multiline comments are also working, but joined together
         ///
         /// Empty line is replaced with line break
         /// \nYou may also use this way
         /// \n
         /// The above will still result in a single line break
         A,
         /// Letter B
         B,
         /// This comment is ignored
         #[display("Letter C")]
         C,
         /// Letter {0}
         Letter(String),
         /// You can omit parameters and just have a normal doc comment
         Number(u8),
         /// ... for variants with named fields as well
         Named { some: String }
     };
    
     assert_eq!(
         format!("{}", Variants::A),
         "Letter A. Multiline comments are also working, but joined \
         together\nEmpty line is replaced with line break\nYou may also use \
         this way\nThe above will still result in a single line break"
     );
     assert_eq!(format!("{}", Variants::C), "Letter C");
     assert_eq!(format!("{}", Variants::Letter(s!("K"))), "Letter K");
    You can also mix in this mode with other fors of display tags on a specific options; in this case doc comments are ignored
  6. Support of unit structs and newtypes:
     /// Some unit struct
     #[derive(Clone, Debug, Display, Error)]     
     #[display(doc_comments)]
     pub struct UnitStruct;
    
     /// displaying the wrapped type data: '{0}'.
     #[derive(Clone, PartialEq, Eq, Debug, Display)]
     #[display(doc_comments)]
     pub struct NewType(pub String);
  7. Print the name of enum variant in lowercase/uppercase:
     #[derive(Display)]
     #[display(lowercase)]
     enum Message {
         Quit,
         Move { x: i32, y: i32 },
         Write(String),
         ChangeColor(i32, i32, i32),
     }
    
     #[derive(Display)]
     #[display(uppercase)]
     enum Event {
         Init,
         Load(Message),
     }
    
    
     assert_eq!(format!("{}", Message::Quit), "quit");
     assert_eq!(format!("{}", Message::Move{ x: 1, y: 2 }),
         "move { x: 1, y: 2 }");
     assert_eq!(format!("{}", Message::Write(String::from("msg"))),
         "write(msg)");
     assert_eq!(format!("{}", Message::ChangeColor(255, 0, 0)),
         "changecolor(255, 0, 0)");
     assert_eq!(format!("{}", Event::Init), "INIT");
     assert_eq!(format!("{}", Event::Load(Message::ChangeColor(0, 255, 0))),
         "LOAD(changecolor(0, 255, 0))");

§Example

Advanced use with enums:

#[derive(Display)]
enum Test {
    Some,

    #[display("OtherName")]
    Other,

    /// Document comment working as display string
    Commented,

    Named {
        x: u8,
    },

    #[display("Custom{x}", alt = "this is alternative")]
    NamedCustom {
        x: u8,
    },

    #[display(inner)]
    Inner {
        a: String,
    },

    Unnamed(u16),

    // NB: Use indexes for tuple values
    #[display("Custom{0}")]
    UnnamedCustom(String),
}

assert_eq!(format!("{}", Test::Some), "Some");
assert_eq!(format!("{}", Test::Other), "OtherName");
assert_eq!(format!("{}", Test::Named { x: 1 }), "Named { .. }");
assert_eq!(format!("{}", Test::Unnamed(5)), "Unnamed(..)");
assert_eq!(format!("{}", Test::NamedCustom { x: 8 }), "Custom8");
assert_eq!(format!("{:#}", Test::NamedCustom { x: 8 }), "this is alternative");
assert_eq!(format!("{}", Test::UnnamedCustom("Test".to_string())), "CustomTest");

Use with tuple types:

#[derive(Clone, Copy, Debug, Display)]
#[display("{0}")]
struct Tuple(u8);

#[derive(Clone, Copy, Debug, Display)]
#[display(inner)] // `inner` is synonym to "{0}"
struct Tuple2(u8);

assert_eq!(format!("{}", Tuple(5)), format!("{}", Tuple2(5)))

Using inner enum variant representation, defaulting to the variant name if the variant does not have inner data:

use std::net::{IpAddr, Ipv4Addr};

#[derive(Clone, Copy, Debug, Display)]
#[display(inner)] // `inner` is synonym to "{0}"
enum Variants {
    First,
    Second,
    WithData(u8),
    WithComplexData(IpAddr),
};

assert_eq!(Variants::First.to_string(), "First");
assert_eq!(Variants::WithData(5).to_string(), "5");
assert_eq!(
    Variants::WithComplexData(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))).to_string(),
    "127.0.0.1"
);