Derive Macro parse_display::Display

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

Derive Display.

§Helper attributes

#[derive(Display)] and #[derive(FromStr)] use common helper attributes.

  • #[derive(Display)] use #[display].
  • #[derive(FromStr)] use both #[display] and #[from_str], with #[from_str] having priority.

Helper attributes can be written in the following positions.

attribute#[display]#[from_str]structenumvariantfield
#[display("...")]
#[display(style = "...")]
#[display(with = ...)]
#[display(bound(...))]
#[display(crate = ...)]
#[display(dump)]
#[from_str(regex = "...")]
#[from_str(new = ...)]
#[from_str(ignore)]
#[from_str(default)]
#[from_str(default_fields(...))]

§#[display("...")]

Specifies the format using a syntax similar to std::format!().

However, unlike std::format!(), {} has the following meaning.

formatstructenumvariantfielddescription
{a}, {b}, {1}Use a field with the specified name.
{a.b.c}Use a nested field.
{:x}, {:?}Use format traits other than Display for self. (e.g. LowerHex, Debug)
{}Use a variant name of enum.
{}Use the field itself.

§Struct format

By writing #[display("..")], you can specify the format used by Display and FromStr.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
#[display("{a}-{b}")]
struct MyStruct {
  a: u32,
  b: u32,
}
assert_eq!(MyStruct { a:10, b:20 }.to_string(), "10-20");
assert_eq!("10-20".parse(), Ok(MyStruct { a:10, b:20 }));

#[derive(Display, FromStr, PartialEq, Debug)]
#[display("{0}+{1}")]
struct MyTuple(u32, u32);
assert_eq!(MyTuple(10, 20).to_string(), "10+20");
assert_eq!("10+20".parse(), Ok(MyTuple(10, 20)));

§Newtype pattern

If the struct has only one field, the format can be omitted. In this case, the only field is used.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
struct NewType(u32);
assert_eq!(NewType(10).to_string(), "10");
assert_eq!("10".parse(), Ok(NewType(10)));

§Enum format

In enum, you can specify the format for each variant.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
enum MyEnum {
  #[display("aaa")]
  VarA,
  #[display("bbb")]
  VarB,
}
assert_eq!(MyEnum::VarA.to_string(), "aaa");
assert_eq!(MyEnum::VarB.to_string(), "bbb");
assert_eq!("aaa".parse(), Ok(MyEnum::VarA));
assert_eq!("bbb".parse(), Ok(MyEnum::VarB));

In enum format, {} means variant name. Variant name style (e.g. snake_case, camelCase, …) can be specified by #[from_str(style = "...")].

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
enum MyEnum {
  #[display("aaa-{}")]
  VarA,
  #[display("bbb-{}")]
  VarB,
}
assert_eq!(MyEnum::VarA.to_string(), "aaa-VarA");
assert_eq!(MyEnum::VarB.to_string(), "bbb-VarB");
assert_eq!("aaa-VarA".parse(), Ok(MyEnum::VarA));
assert_eq!("bbb-VarB".parse(), Ok(MyEnum::VarB));

#[derive(Display, FromStr, PartialEq, Debug)]
#[display(style = "snake_case")]
enum MyEnumSnake {
  #[display("{}")]
  VarA,
}
assert_eq!(MyEnumSnake::VarA.to_string(), "var_a");
assert_eq!("var_a".parse(), Ok(MyEnumSnake::VarA));

By writing a format on enum instead of variant, you can specify the format common to multiple variants.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
#[display("xxx-{}")]
enum MyEnum {
  VarA,
  VarB,
}
assert_eq!(MyEnum::VarA.to_string(), "xxx-VarA");
assert_eq!(MyEnum::VarB.to_string(), "xxx-VarB");
assert_eq!("xxx-VarA".parse(), Ok(MyEnum::VarA));
assert_eq!("xxx-VarB".parse(), Ok(MyEnum::VarB));

§Unit variants

If all variants has no field, format can be omitted. In this case, variant name is used.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
enum MyEnum {
  VarA,
  VarB,
}
assert_eq!(MyEnum::VarA.to_string(), "VarA");
assert_eq!(MyEnum::VarB.to_string(), "VarB");
assert_eq!("VarA".parse(), Ok(MyEnum::VarA));
assert_eq!("VarB".parse(), Ok(MyEnum::VarB));

§Field format

You can specify the format of the field. In field format, {} means the field itself.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
#[display("{a}, {b}")]
struct MyStruct {
  #[display("a is {}")]
  a: u32,
  #[display("b is {}")]
  b: u32,
}
assert_eq!(MyStruct { a:10, b:20 }.to_string(), "a is 10, b is 20");
assert_eq!("a is 10, b is 20".parse(), Ok(MyStruct { a:10, b:20 }));

#[derive(Display, FromStr, PartialEq, Debug)]
#[display("{0}, {1}")]
struct MyTuple(#[display("first is {}")] u32, #[display("next is {}")] u32);
assert_eq!(MyTuple(10, 20).to_string(), "first is 10, next is 20");
assert_eq!("first is 10, next is 20".parse(), Ok(MyTuple(10, 20)));

#[derive(Display, FromStr, PartialEq, Debug)]
enum MyEnum {
  #[display("this is A {0}")]
  VarA(#[display("___{}___")] u32),
}
assert_eq!(MyEnum::VarA(10).to_string(), "this is A ___10___");
assert_eq!("this is A ___10___".parse(), Ok(MyEnum::VarA(10)));

§Nested field

You can use nested field, e.g. {x.a} .

use parse_display::{Display, FromStr};

#[derive(PartialEq, Debug, Default)]
struct X {
    a: u32,
    b: u32,
}

#[derive(FromStr, Display, PartialEq, Debug)]
#[display("{x.a}")]
struct Y {
    #[from_str(default)]
    x: X,
}
assert_eq!(Y { x: X { a: 10, b: 20 } }.to_string(), "10");
assert_eq!("10".parse(), Ok(Y { x: X { a: 10, b: 0 } }));

When using nested field, you need to use #[from_str(default)] to implement FromStr.

§Format parameter

Like std::format!(), format parameter can be specified.

use parse_display::{Display, FromStr};

#[derive(Display, PartialEq, Debug)]
#[display("{a:>04}")]
struct WithFormatParameter {
  a: u32,
}
assert_eq!(WithFormatParameter { a:5 }.to_string(), "0005");

§#[display(style = "...")]

By writing #[display(style = "...")], you can specify the variant name style. The following styles are available.

  • none
  • lowercase
  • UPPERCASE
  • snake_case
  • SNAKE_CASE
  • camelCase
  • CamelCase
  • kebab-case
  • KEBAB-CASE
  • Title Case
  • Title case
  • title case
  • TITLE CASE
use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
#[display(style = "snake_case")]
enum MyEnum {
  VarA,
  VarB,
}
assert_eq!(MyEnum::VarA.to_string(), "var_a");
assert_eq!("var_a".parse(), Ok(MyEnum::VarA));

#[derive(Display, FromStr, PartialEq, Debug)]
enum StyleExample {
  #[display(style = "none")]
  VarA1,
  #[display(style = "none")]
  varA2,
  #[display(style = "lowercase")]
  VarB,
  #[display(style = "UPPERCASE")]
  VarC,
  #[display(style = "snake_case")]
  VarD,
  #[display(style = "SNAKE_CASE")]
  VarE,
  #[display(style = "camelCase")]
  VarF,
  #[display(style = "CamelCase")]
  VarG1,
  #[display(style = "CamelCase")]
  varG2,
  #[display(style = "kebab-case")]
  VarH,
  #[display(style = "KEBAB-CASE")]
  VarI,
  #[display(style = "Title Case")]
  VarJ,
  #[display(style = "Title case")]
  VarK,
  #[display(style = "title case")]
  VarL,
  #[display(style = "TITLE CASE")]
  VarM,
}
assert_eq!(StyleExample::VarA1.to_string(), "VarA1");
assert_eq!(StyleExample::varA2.to_string(), "varA2");
assert_eq!(StyleExample::VarB.to_string(), "varb");
assert_eq!(StyleExample::VarC.to_string(), "VARC");
assert_eq!(StyleExample::VarD.to_string(), "var_d");
assert_eq!(StyleExample::VarE.to_string(), "VAR_E");
assert_eq!(StyleExample::VarF.to_string(), "varF");
assert_eq!(StyleExample::VarG1.to_string(), "VarG1");
assert_eq!(StyleExample::varG2.to_string(), "VarG2");
assert_eq!(StyleExample::VarH.to_string(), "var-h");
assert_eq!(StyleExample::VarI.to_string(), "VAR-I");
assert_eq!(StyleExample::VarJ.to_string(), "Var J");
assert_eq!(StyleExample::VarK.to_string(), "Var k");
assert_eq!(StyleExample::VarL.to_string(), "var l");
assert_eq!(StyleExample::VarM.to_string(), "VAR M");

§#[display(with = "...")], #[from_str(with = "...")]

You can customize Display and FromStr processing for a field by specifying the values that implements DisplayFormat and FromStrFormat.

If Display of the field is used when this attribute is not specified, the value specified for the attribute must implement DisplayFormat.

If FromStr of the field is used when this attribute is not specified, the value specified for the attribute must implement FromStrFormat.

See DisplayFormat and FromStrFormat for details.

§#[display(bound(...))], #[from_str(bound(...))]

By default, the type of field used in the format is added to the trait bound.

In Rust prior to 1.59, this behavior causes a compile error if you use fields of non public type in public struct.

#![deny(private_in_public)]
use parse_display::Display;

// private type `Inner<T>` in public interface (error E0446)
#[derive(Display)]
pub struct Outer<T>(Inner<T>);

#[derive(Display)]
struct Inner<T>(T);

By writing #[display(bound(...))], you can override the default behavior.

§Specify trait bound type

By specifying the type, you can specify the type that need to implement Display and FromStr.

use parse_display::{Display, FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
#[display(bound(T))]
pub struct Outer<T>(Inner<T>);

#[derive(Display, FromStr, PartialEq, Debug)]
struct Inner<T>(T);

assert_eq!(Outer(Inner(10)).to_string(), "10");
assert_eq!("10".parse(), Ok(Outer(Inner(10))));

§Specify where predicate

You can also specify the where predicate.

use parse_display::Display;

#[derive(Display)]
#[display(bound(T : std::fmt::Debug))]
pub struct Outer<T>(Inner<T>);

#[derive(Display)]
#[display("{0:?}")]
struct Inner<T>(T);

assert_eq!(Outer(Inner(10)).to_string(), "10");

§No trait bounds

You can also remove all trait bounds.

use parse_display::Display;

#[derive(Display)]
#[display(bound())]
pub struct Outer<T>(Inner<T>);

#[derive(Display)]
#[display("ABC")]
struct Inner<T>(T);

assert_eq!(Outer(Inner(10)).to_string(), "ABC");

§Default trait bounds

.. means default (automatically generated) trait bounds.

The following example specifies T1 as a trait bound in addition to the default trait bound T2.

use parse_display::Display;

pub struct Inner<T>(T);

#[derive(Display)]
#[display("{0.0}, {1}", bound(T1, ..))]
pub struct Outer<T1, T2>(Inner<T1>, T2);

assert_eq!(Outer(Inner(10), 20).to_string(), "10, 20");

You can use a different trait bound for Display and FromStr by specifying both #[display(bound(...))] and #[from_str(bound(...))].

use parse_display::*;
use std::{fmt::Display, str::FromStr};

#[derive(Display, FromStr, PartialEq, Debug)]
#[display(bound("T : Display"))]
#[from_str(bound("T : FromStr"))]
pub struct Outer<T>(Inner<T>);

#[derive(Display, FromStr, PartialEq, Debug)]
struct Inner<T>(T);

assert_eq!(Outer(Inner(10)).to_string(), "10");
assert_eq!("10".parse(), Ok(Outer(Inner(10))));

§#[display(crate = ...)]

Specify a path to the parse-display crate instance.

Used when ::parse_display is not an instance of parse-display, such as when a macro is re-exported or used from another macro.

§#[display(dump)], #[from_str(dump)]

Outputs the generated code as a compile error.

§#[from_str(regex = "...")]

Specify the format of the string to be input with FromStr. #[display("...")] is ignored, when this attribute is specified.

§Capture name

The capture name corresponds to the field name.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[from_str(regex = "(?<a>[0-9]+)__(?<b>[0-9]+)")]
struct MyStruct {
  a: u8,
  b: u8,
}

assert_eq!("10__20".parse(), Ok(MyStruct { a:10, b:20 }));

§Field regex

Set #[display("...")] to struct and set #[from_str(regex = "...")] to field, regex is used in the position where field name is specified in #[display("...")].

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[display("{a}__{b}")]
struct MyStruct {
  #[from_str(regex = "[0-9]+")]
  a: u8,

  #[from_str(regex = "[0-9]+")]
  b: u8,
}
assert_eq!("10__20".parse(), Ok(MyStruct { a:10, b:20 }));

If #[from_str(regex = "...")] is not set to field , it operates in the same way as when #[from_str(regex = "(?s:.*?)")] is set.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[display("{a}{b}")]
struct MyStruct {
  a: String,
  b: String,
}
assert_eq!("abcdef".parse(), Ok(MyStruct { a:"".into(), b:"abcdef".into() }));

§Variant name

In the regex specified for enum or variant, empty name capture means variant name.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[from_str(regex = "___(?<>)___")]
enum MyEnum {
  VarA,

  #[from_str(regex = "xxx(?<>)xxx")]
  VarB,
}
assert_eq!("___VarA___".parse(), Ok(MyEnum::VarA));
assert_eq!("xxxVarBxxx".parse(), Ok(MyEnum::VarB));

§Regex nested field

You can use nested field in regex.

use parse_display::FromStr;

#[derive(PartialEq, Debug, Default)]
struct X {
    a: u32,
}

#[derive(FromStr, PartialEq, Debug)]
#[from_str(regex = "___(?<x.a>[0-9]+)")]
struct Y {
    #[from_str(default)]
    x: X,
}
assert_eq!("___10".parse(), Ok(Y { x: X { a: 10 } }));

When using nested field, you need to use #[from_str(default)].

§#[from_str(new = ...)]

If #[from_str(new = ...)] is specified, the value will be initialized with the specified expression instead of the constructor.

The expression must return a value that implement IntoResult (e.g. Self, Option<Self>, Result<Self, E>).

In the expression, you can use a variable with the same name as the field name.

use parse_display::FromStr;
#[derive(FromStr, Debug, PartialEq)]
#[from_str(new = Self::new(value))]
struct MyNonZeroUSize {
    value: usize,
}

impl MyNonZeroUSize {
    fn new(value: usize) -> Option<Self> {
        if value == 0 {
            None
        } else {
            Some(Self { value })
        }
    }
}

assert_eq!("1".parse(), Ok(MyNonZeroUSize { value: 1 }));
assert_eq!("0".parse::<MyNonZeroUSize>().is_err(), true);

In tuple struct, variables are named with a leading underscore and their index. (e.g. _0, _1).

use parse_display::FromStr;
#[derive(FromStr, Debug, PartialEq)]
#[from_str(new = Self::new(_0))]
struct MyNonZeroUSize(usize);

impl MyNonZeroUSize {
    fn new(value: usize) -> Option<Self> {
        if value == 0 {
            None
        } else {
            Some(Self(value))
        }
    }
}

assert_eq!("1".parse(), Ok(MyNonZeroUSize(1)));
assert_eq!("0".parse::<MyNonZeroUSize>().is_err(), true);

§#[from_str(ignore)]

Specifying this attribute for a variant will not generate FromStr implementation for that variant.

use parse_display::FromStr;

#[derive(Debug, Eq, PartialEq)]
struct CanNotFromStr;

#[derive(FromStr, Debug, Eq, PartialEq)]
#[allow(dead_code)]
enum HasIgnore {
    #[from_str(ignore)]
    A(CanNotFromStr),
    #[display("{0}")]
    B(u32),
}

assert_eq!("1".parse(), Ok(HasIgnore::B(1)));

§#[from_str(default)]

If this attribute is specified, the default value is used for fields not included in the input.

If an attribute is specified for struct, the struct’s default value is used.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[display("{b}")]
#[from_str(default)]
struct MyStruct {
  a: u32,
  b: u32,
}

impl Default for MyStruct {
  fn default() -> Self {
    Self { a:99, b:99 }
  }
}
assert_eq!("10".parse(), Ok(MyStruct { a:99, b:10 }));

If an attribute is specified for field, the field type’s default value is used.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[display("{b}")]
struct MyStruct {
  #[from_str(default)]
  a: u32,
  b: u32,
}

impl Default for MyStruct {
  fn default() -> Self {
    Self { a:99, b:99 }
  }
}
assert_eq!("10".parse(), Ok(MyStruct { a:0, b:10 }));

§#[from_str(default_fields(...))]

You can use #[from_str(default_fields(...))] if you want to set default values for the same-named fields of multiple variants.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
#[display("{}-{a}")]
#[from_str(default_fields("b", "c"))]
enum MyEnum {
  VarA { a:u8, b:u8, c:u8 },
  VarB { a:u8, b:u8, c:u8 },
}

assert_eq!("VarA-10".parse(), Ok(MyEnum::VarA { a:10, b:0, c:0 }));
assert_eq!("VarB-10".parse(), Ok(MyEnum::VarB { a:10, b:0, c:0 }));