This crate provides derive macro Display
and FromStr
.
These macros use common helper attributes to specify the format.
Add this to your Cargo.toml:
toml
[dependencies]
parse-display = "0.8.0"
```rust use parse_display::{Display, FromStr};
struct MyStruct { a: u32, b: u32, } asserteq!(MyStruct { a:10, b:20 }.tostring(), "10-20"); assert_eq!("10-20".parse(), Ok(MyStruct { a:10, b:20 }));
enum MyEnum { VarA, VarB, } asserteq!(MyEnum::VarA.tostring(), "vara"); asserteq!("var_a".parse(), Ok(MyEnum::VarA)); ```
Helper attributes can be written in the following positions.
| attribute | struct | enum | variant | field |
| ------------------------------------------------------------- | ------ | ---- | ------- | ----- |
| #[display("...")]
| ✔ | ✔ | ✔ | ✔ |
| #[display(style = "...")]
| | ✔ | ✔ | |
| #[display(bound(...))]
| ✔ | ✔ | ✔ | ✔ |
| #[from_str(bound(...))]
| ✔ | ✔ | ✔ | ✔ |
| #[from_str(regex = "...")]
| ✔ | ✔ | ✔ | ✔ |
| #[from_str(new = ...)]
| ✔ | | ✔ | |
| #[from_str(ignore)]
| | | ✔ | |
| #[from_str(default)]
| ✔ | | | ✔ |
| #[from_str(default_fields(...))]
| ✔ | ✔ | ✔ | |
#[derive(Display)]
use #[display]
.
#[derive(FromStr)]
use both #[display]
and #[from_str]
.
key = value
style parameter can be specified only once for each key.
key(value1, value2, ...)
style parameter can be specified multiple times.
#[display("...")]
Specifies the format using a syntax similar to std::format!()
.
However, unlike std::format!()
, field name is specified in {}
.
By writing #[display("..")]
, you can specify the format used by Display
and FromStr
.
```rust use parse_display::{Display, FromStr};
struct MyStruct { a: u32, b: u32, } asserteq!(MyStruct { a:10, b:20 }.tostring(), "10-20"); assert_eq!("10-20".parse(), Ok(MyStruct { a:10, b:20 }));
struct MyTuple(u32, u32); asserteq!(MyTuple(10, 20).tostring(), "10+20"); assert_eq!("10+20".parse(), Ok(MyTuple(10, 20))); ```
If the struct has only one field, the format can be omitted. In this case, the only field is used.
```rust use parse_display::{Display, FromStr};
struct NewType(u32); asserteq!(NewType(10).tostring(), "10"); assert_eq!("10".parse(), Ok(NewType(10))); ```
In enum, you can specify the format for each variant.
```rust use parse_display::{Display, FromStr};
enum MyEnum { #[display("aaa")] VarA, #[display("bbb")] VarB, } asserteq!(MyEnum::VarA.tostring(), "aaa"); asserteq!(MyEnum::VarB.tostring(), "bbb"); asserteq!("aaa".parse(), Ok(MyEnum::VarA)); asserteq!("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 = "...")]
.
```rust use parse_display::{Display, FromStr};
enum MyEnum { #[display("aaa-{}")] VarA, #[display("bbb-{}")] VarB, } asserteq!(MyEnum::VarA.tostring(), "aaa-VarA"); asserteq!(MyEnum::VarB.tostring(), "bbb-VarB"); asserteq!("aaa-VarA".parse(), Ok(MyEnum::VarA)); asserteq!("bbb-VarB".parse(), Ok(MyEnum::VarB));
enum MyEnumSnake { #[display("{}")] VarA, } asserteq!(MyEnumSnake::VarA.tostring(), "vara"); asserteq!("var_a".parse(), Ok(MyEnumSnake::VarA)); ```
By writing a format on enum instead of variant, you can specify the format common to multiple variants.
```rust use parse_display::{Display, FromStr};
enum MyEnum { VarA, VarB, } asserteq!(MyEnum::VarA.tostring(), "xxx-VarA"); asserteq!(MyEnum::VarB.tostring(), "xxx-VarB"); asserteq!("xxx-VarA".parse(), Ok(MyEnum::VarA)); asserteq!("xxx-VarB".parse(), Ok(MyEnum::VarB)); ```
If all variants has no field, format can be omitted. In this case, variant name is used.
```rust use parse_display::{Display, FromStr};
enum MyEnum { VarA, VarB, } asserteq!(MyEnum::VarA.tostring(), "VarA"); asserteq!(MyEnum::VarB.tostring(), "VarB"); asserteq!("VarA".parse(), Ok(MyEnum::VarA)); asserteq!("VarB".parse(), Ok(MyEnum::VarB)); ```
You can specify the format of the field.
In field format, {}
means the field itself.
```rust use parse_display::{Display, FromStr};
struct MyStruct { #[display("a is {}")] a: u32, #[display("b is {}")] b: u32, } asserteq!(MyStruct { a:10, b:20 }.tostring(), "a is 10, b is 20"); assert_eq!("a is 10, b is 20".parse(), Ok(MyStruct { a:10, b:20 }));
struct MyTuple(#[display("first is {}")] u32, #[display("next is {}")] u32); asserteq!(MyTuple(10, 20).tostring(), "first is 10, next is 20"); assert_eq!("first is 10, next is 20".parse(), Ok(MyTuple(10, 20)));
enum MyEnum { #[display("this is A {0}")] VarA(#[display("{}")] u32), } asserteq!(MyEnum::VarA(10).tostring(), "this is A 10"); asserteq!("this is A 10_".parse(), Ok(MyEnum::VarA(10))); ```
You can use "field chain", e.g. {x.a}
.
```rust use parse_display::{Display, FromStr};
struct MyStruct { a: u32, b: u32, }
struct FieldChain { #[fromstr(default)] x: MyStruct, } asserteq!(FieldChain { x:MyStruct { a:10, b:20 } }.tostring(), "10"); asserteq!("10".parse(), Ok(FieldChain { x:MyStruct { a:10, b:0 } })); ```
When using "field chain", you need to use #[from_str(default)]
to implement FromStr
.
Like std::format!()
, format parameter can be specified.
```rust use parse_display::{Display, FromStr};
struct WithFormatParameter { a: u32, } asserteq!(WithFormatParameter { a:5 }.tostring(), "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
```rust use parse_display::{Display, FromStr};
enum MyEnum { VarA, VarB, } asserteq!(MyEnum::VarA.tostring(), "vara"); asserteq!("var_a".parse(), Ok(MyEnum::VarA));
enum StyleExample { #[display(style = "none")] VarA1, #[display(style = "none")] varA2, #[display(style = "lowercase")] VarB, #[display(style = "UPPERCASE")] VarC, #[display(style = "snakecase")] VarD, #[display(style = "SNAKECASE")] 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, } asserteq!(StyleExample::VarA1.tostring(), "VarA1"); asserteq!(StyleExample::varA2.tostring(), "varA2"); asserteq!(StyleExample::VarB.tostring(), "varb"); asserteq!(StyleExample::VarC.tostring(), "VARC"); asserteq!(StyleExample::VarD.tostring(), "vard"); asserteq!(StyleExample::VarE.tostring(), "VARE"); asserteq!(StyleExample::VarF.tostring(), "varF"); asserteq!(StyleExample::VarG1.tostring(), "VarG1"); asserteq!(StyleExample::varG2.tostring(), "VarG2"); asserteq!(StyleExample::VarH.tostring(), "var-h"); asserteq!(StyleExample::VarI.tostring(), "VAR-I"); asserteq!(StyleExample::VarJ.tostring(), "Var J"); asserteq!(StyleExample::VarK.tostring(), "Var k"); asserteq!(StyleExample::VarL.tostring(), "var l"); asserteq!(StyleExample::VarM.tostring(), "VAR M"); ```
#[display(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.
```rust
use parse_display::Display;
// private type Inner<T>
in public interface (error E0446)
pub struct Outer
struct Inner
By writing #[display(bound(...))]
, you can override the default behavior.
By specifying the type, you can specify the type that need to implement Display
and FromStr
.
```rust use parse_display::{Display, FromStr};
pub struct Outer
struct Inner
asserteq!(Outer(Inner(10)).tostring(), "10"); assert_eq!("10".parse(), Ok(Outer(Inner(10)))); ```
You can also specify the where predicate.
```rust use parse_display::Display;
pub struct Outer
struct Inner
asserteq!(Outer(Inner(10)).tostring(), "10"); ```
You can also remove all trait bounds.
```rust use parse_display::Display;
pub struct Outer
struct Inner
asserteq!(Outer(Inner(10)).tostring(), "ABC"); ```
..
means default (automatically generated) trait bounds.
The following example specifies T1
as a trait bound in addition to the default trait bound T2
.
```rust use parse_display::Display;
pub struct Inner
pub struct Outer
asserteq!(Outer(Inner(10), 20).tostring(), "10, 20"); ```
#[from_str(bound(...))]
You can use a different trait bound for Display
and FromStr
by specifying both #[display(bound(...))]
and #[from_str(bound(...))]
.
```rust use parse_display::*; use std::{fmt::Display, str::FromStr};
pub struct Outer
struct Inner
asserteq!(Outer(Inner(10)).tostring(), "10"); assert_eq!("10".parse(), Ok(Outer(Inner(10)))); ```
#[from_str(regex = "...")]
Specify the format of the string to be input with FromStr
.
#[display("...")]
is ignored, when this attribute is specified.
The capture name corresponds to the field name.
```rust use parse_display::FromStr;
struct MyStruct { a: u8, b: u8, }
asserteq!("10_20".parse(), Ok(MyStruct { a:10, b:20 })); ```
Set #[display("...")]
to struct and set #[from_str(regex = "...")]
to field, regex is used in the position where field name is specified in #[display("...")]
.
```rust use parse_display::FromStr;
struct MyStruct { #[from_str(regex = "[0-9]+")] a: u8,
#[fromstr(regex = "[0-9]+")] b: u8, } asserteq!("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.
```rust use parse_display::FromStr;
struct MyStruct { a: String, b: String, } assert_eq!("abcdef".parse(), Ok(MyStruct { a:"".into(), b:"abcdef".into() })); ```
In the regex specified for enum or variant, empty name capture means variant name.
```rust use parse_display::FromStr;
enum MyEnum { VarA,
#[fromstr(regex = "xxx(?P<>)xxx")] VarB, } asserteq!("VarA".parse(), Ok(MyEnum::VarA)); assert_eq!("xxxVarBxxx".parse(), Ok(MyEnum::VarB)); ```
You can use "field chain" in regex.
```rust use parse_display::FromStr;
struct MyStruct { a: u32, }
struct FieldChain { #[fromstr(default)] x: MyStruct, } asserteq!("_10".parse(), Ok(FieldChain { x:MyStruct { a:10 } })); ```
When using "field chain", 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.
```rust use parse_display::FromStr;
struct MyNonZeroUSize { value: usize, }
impl MyNonZeroUSize {
fn new(value: usize) -> Option
asserteq!("1".parse(), Ok(MyNonZeroUSize { value: 1 }));
asserteq!("0".parse::
In tuple struct, variables are named with a leading underscore and their index. (e.g. _0
, _1
).
```rust use parse_display::FromStr;
struct MyNonZeroUSize(usize);
impl MyNonZeroUSize {
fn new(value: usize) -> Option
asserteq!("1".parse(), Ok(MyNonZeroUSize(1)));
asserteq!("0".parse::
#[from_str(ignore)]
Specifying this attribute for a variant will not generate FromStr
implementation for that variant.
```rust use parse_display::FromStr;
struct CanNotFromStr;
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.
```rust use parse_display::FromStr;
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.
```rust use parse_display::FromStr;
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.
```rust use parse_display::FromStr;
enum MyEnum { VarA { a:u8, b:u8, c:u8 }, VarB { a:u8, b:u8, c:u8 }, }
asserteq!("VarA-10".parse(), Ok(MyEnum::VarA { a:10, b:0, c:0 })); asserteq!("VarB-10".parse(), Ok(MyEnum::VarB { a:10, b:0, c:0 })); ```
This project is dual licensed under Apache-2.0/MIT. See the two LICENSE-* files for details.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.