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.
{}Use a variant name of enum.
{},{:x}, {:?}Use the field itself.
{:x}, {:?}Use format traits other than Display for self. (e.g. LowerHex, Debug)
{a.b.c}Use a nested field.

§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)));

§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");

When {} is used within #[display("...")] set for an enum, and if a format trait is added to {} such as {:?}, the meaning changes from “variant name” to “a string using a trait other than Display for self.”

use parse_display::Display;

#[derive(Display, PartialEq, Debug)]
#[display("{}")]
enum X {
  A,
}
assert_eq!(X::A.to_string(), "A");

#[derive(Display, PartialEq)]
#[display("{:?}")]
enum Y {
  A,
}
impl std::fmt::Debug for Y {
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    write!(f, "Debug Y")
  }
}
assert_eq!(Y::A.to_string(), "Debug Y");

§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.

§#[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.

use parse_display::{Display, DisplayFormat, FromStr, FromStrFormat};

#[derive(Display, FromStr, PartialEq, Debug)]
pub struct X {
    #[display(with = Plus1)]
    a: i32,
}

struct Plus1;

impl DisplayFormat<i32> for Plus1 {
    fn write(&self, f: &mut std::fmt::Formatter, value: &i32) -> std::fmt::Result {
        write!(f, "{}", value + 1)
    }
}
impl FromStrFormat<i32> for Plus1 {
    type Err = <i32 as std::str::FromStr>::Err;
    fn parse(&self, s: &str) -> std::result::Result<i32, Self::Err> {
        Ok(s.parse::<i32>()? - 1)
    }
}

assert_eq!(X { a: 1 }.to_string(), "2");
assert_eq!("2".parse(), Ok(X { a: 1 }));

The expression specified for with = ... must be lightweight because it is called each time when formatting and parsing.

§#[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() }));

§Field regex with capture

Using a named capture group with an empty name in the field’s regex will convert only the string within that group to the field’s value.

use parse_display::FromStr;

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

§Field regex with display format

If both #[display("...")] and #[from_str(regex = "...")] are specified for a field and the regex does not contain named capture groups, the pattern within the {} part of the format specified by #[display("...")] will be determined by #[from_str(regex = "...")].

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
struct X {
  #[display("a = {}")]
  #[from_str(regex = "[0-9]+")]
  a: u8,
}
assert_eq!("a = 10".parse(), Ok(X { a: 10 }));

If the regex does not contain named capture groups, #[display("...")] is ignored.

use parse_display::FromStr;

#[derive(FromStr, PartialEq, Debug)]
struct Y {
  #[display("a = {}")]
  #[from_str(regex = "a = (?<>[0-9]+)")]
  a: u8,
}
assert_eq!("a = 10".parse(), Ok(Y { a: 10 }));
assert!("a = a = 10".parse::<Y>().is_err());

§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 }));