2 releases
0.1.2 | Sep 6, 2023 |
---|---|
0.1.1 |
|
0.1.0 | Jul 15, 2023 |
#1285 in Encoding
75 downloads per month
18KB
334 lines
Logos Display
A set of derive macros that automatically implement Display
and Debug
for an enum, based on the Logos token
and regex
attributes.
How To Use
Simply use logos_display::Display
and/or use logos_display::Debug
and add it to your derives, like so:
use logos_display::{Display, Debug}
#[derive(Display, Debug, Logos)]
enum A {
#[token("{")]
LCur,
#[regex("[a-z]")]
Lower
}
|
V
impl std::fmt::Display for A {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ret = match &self {
A::LCur => "{",
A::Lower => "[a-z]",
};
write!(f, "{}", ret)
}
}
Difference between Display
and Debug
If the enum variant is a unit type, there is no difference. But in the case where the variant is a tuple or struct variant, the Debug
version will also show the inner value held by the instance, whereas the Display
version will only output the name of the outer layer. Like so:
use logos_display::{Display, Debug}
#[derive(Display, Debug, Logos)]
enum A {
#[token("{")]
LCur,
#[regex("[a-z]", |lex| some_func(lex.slice()))]
Lower(TypeOne, TypeTwo)
}
|
V
impl std::fmt::Debug for A {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ret = match &self {
A::LCur => "{",
A::Lower(_arg1, _arg2) => format!("{}{:?}", "[a-z]", vec![_arg1, _arg2]),
};
write!(f, "{}", ret)
}
}
This does of course require the inner types to implement Debug
in some form as well.
Dealing with non-tokens
In the case that a variant is not a token or regex, the name of the variant will be used for the Display method (so variant B
will have "B"
as it's string representation). If you want to override any of this functionality, you can add an display_override("string")
attribute to the variant as follows:
use logos_display::Display
#[derive(Display, Logos)]
enum A {
#[display_override("fancy curly thing")]
#[token("{")]
LCur,
#[regex("[a-z]")]
Lower
}
|
V
impl std::fmt::Display for A {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ret = match &self {
A::LCur => "fancy curly thing",
A::Lower => "[a-z]",
};
write!(f, "{}", ret)
}
}
Multiple tokens
When a variant accepts multiple tokens, by default, they will be concatenated using /
in the string representation, like so:
use logos_display::Display
#[derive(Display, Logos)]
enum A {
#[token("{")]
#[token("}")]
Cur
}
|
V
impl std::fmt::Display for A {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ret = match &self {
A::LCur => "{/}",
};
write!(f, "{}", ret)
}
}
This functionality can be overwritten using the display_concat("string")
attribute on the original enum:
use logos_display::Display
#[derive(Display, Logos)]
#[display_concat(" or ")]
enum A {
#[token("{")]
#[token("}")]
Cur
}
|
V
impl std::fmt::Display for A {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ret = match &self {
A::LCur => "{ or }",
};
write!(f, "{}", ret)
}
}
Additionally, you can pass None
to this attribute in order to disable concatonation. In this case, the token that is encountered last will be used:
use logos_display::Display
#[derive(Display, Logos)]
#[display_concat(None)]
enum A {
#[token("{")]
#[token("}")]
Cur
}
|
V
impl std::fmt::Display for A {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ret = match &self {
A::LCur => "}",
};
write!(f, "{}", ret)
}
}
Dependencies
~300–750KB
~18K SLoC