Crate descriptor[−][src]
Expand description
Easy pretty print your Rust struct into single element or list.
Simple Example
use descriptor::{object_describe_to_string, table_describe_to_string, Descriptor};
#[derive(Descriptor)]
struct User {
name: String,
age: i32,
address: Address,
}
#[derive(Descriptor)]
struct Address {
street: String,
town: String,
}
let user1 = User{
name: "Adrien".to_string(),
age: 32,
address: Address{
street: "Main street".to_string(),
town: "NY".to_string()
}
};
let user2 = User{
name: "Corentin".to_string(),
age: 40,
address: Address{
street: "10 rue de la paix".to_string(),
town: "Paris".to_string()
}
};
let description = object_describe_to_string(&user1).unwrap();
assert_eq!(r#"
Name: Adrien
Age: 32
Address:
Street: Main street
Town: NY
"#, description);
let table = table_describe_to_string(&vec![user1, user2]).unwrap();
assert_eq!(r#"
NAME AGE ADDRESS.STREET ADDRESS.TOWN
Adrien 32 Main street NY
Corentin 40 10 rue de la paix Paris
"#, format!("\n{}", table));
Macro attributes
Struct attributes
#[descriptor(into = AnotherStruct)]
The into
parameter convert the struct into another before describe.
The From
or Into
Trait should be implemented and AnotherStruct
should implement the Describe
trait.
use descriptor::{Descriptor, object_describe_to_string};
#[derive(Descriptor)]
pub struct ProgressDescribe {
pub transfer: String,
}
impl From<&Progress> for ProgressDescribe {
fn from(progress: &Progress) -> Self {
let bar_length = 20;
let pad_l = ((progress.processed * bar_length) / progress.total.max(1)) as usize;
let bar = format!(
"[{:=>pad_l$}>{:>pad_r$}] {}/{}",
"",
"",
progress.processed,
progress.total,
pad_l = pad_l,
pad_r = bar_length as usize - pad_l
);
Self {
transfer: bar,
}
}
}
#[derive(Descriptor)]
#[descriptor(into = ProgressDescribe)]
struct Progress {
pub processed: u64,
pub total: u64,
}
let progress = Progress{
processed: 20,
total: 40,
};
let description = object_describe_to_string(&progress).unwrap();
assert_eq!(r#"
Transfer: [==========> ] 20/40
"#, description);
#[descriptor(extra_fields = ExtraStruct)]
Add fields from another struct into the description, useful for computed values without overriding real values.
use descriptor::{Descriptor, object_describe_to_string};
#[derive(Descriptor)]
#[descriptor(extra_fields = AgeEntity)]
struct User {
name: String,
created_at: i32,
}
#[derive(Descriptor)]
pub struct AgeEntity {
pub age: String,
}
impl From<&User> for AgeEntity {
fn from(u: &User) -> Self {
Self {
age: format!("{} days ago", u.created_at),
}
}
}
let progress = User{
name: "Adrien".to_string(),
created_at: 40,
};
let description = object_describe_to_string(&progress).unwrap();
assert_eq!(r#"
Name: Adrien
Created At: 40
Age: 40 days ago
"#, description);
#[descriptor(default_headers = [""])]
Overrides default headers when using the table output.
use descriptor::{Descriptor, table_describe_to_string};
#[derive(Descriptor, Clone)]
#[descriptor(default_headers = ["brand", "seat"])]
struct Car {
brand: String,
seat: i16,
model: String,
}
let cars = vec![
Car{brand: "Audi".to_string(), seat:4, model: "A3".to_string()},
Car{brand: "Mercedes".to_string(), seat: 2, model: "GLC".to_string()}
];
let description = table_describe_to_string(&cars).unwrap();
assert_eq!(r#"
BRAND SEAT
Audi 4
Mercedes 2
"#, format!("\n{}", description));
Field attributes
#[descriptor(flatten)]
Flatten a struct into another.
use descriptor::{Descriptor, object_describe_to_string};
#[derive(Descriptor)]
struct User {
name: String,
age: i32,
#[descriptor(flatten)]
address: Address
}
#[derive(Descriptor)]
struct Address {
street: String,
town: String,
}
let foo = User{
name: "Adrien".to_string(),
age: 32,
address: Address{
street: "Main street".to_string(),
town: "NY".to_string()
}
};
let description = object_describe_to_string(&foo).unwrap();
assert_eq!(r#"
Name: Adrien
Age: 32
Street: Main street
Town: NY
"#, description);
#[descriptor(map = func)]
Takes a transformation function as parameter, called before generating the field.
Return value of the functions should not be a struct, use into
parameter for this use case.
use descriptor::{Descriptor, object_describe_to_string};
fn age_to_string(val: &i32) -> String {
format!("{} years", val)
}
#[derive(Descriptor)]
struct User {
name: String,
#[descriptor(map = age_to_string)]
age: i32,
}
let foo = User{
name: "Adrien".to_string(),
age: 32,
};
let description = object_describe_to_string(&foo).unwrap();
assert_eq!(r#"
Name: Adrien
Age: 32 years
"#, description);
map
parameter can be used with resolve_option
parameter.
If the field is an Option, it extract it before calling the transformation function.
use descriptor::{Descriptor, object_describe_to_string};
fn age_to_string(val: &i32) -> String {
format!("{} years", val)
}
#[derive(Descriptor)]
struct User {
name: String,
#[descriptor(map = age_to_string, resolve_option)]
age: Option<i32>,
}
let foo = User{
name: "Adrien".to_string(),
age: Option::Some(32),
};
let description = object_describe_to_string(&foo).unwrap();
assert_eq!(r#"
Name: Adrien
Age: 32 years
"#, description);
#[descriptor(into)]
Act like into
parameter in struct level,
into
parameter can be used with map
parameter in field level.
Sometimes, it’s impossible to implement Into
and From
for some struct,
you can use a public method from the struct
use descriptor::{Descriptor, object_describe_to_string};
#[derive(Descriptor)]
struct Download {
pub filename: String,
#[descriptor(into = String, map = Progress::to_string)]
pub progress: Progress,
}
#[derive(Descriptor)]
struct Progress {
pub processed: u64,
pub total: u64,
}
impl Progress {
fn to_string(&self) -> String {
format!("{}/{}", self.processed, self.total)
}
}
let download = Download{
filename: "debian-11.iso".to_string(),
progress: Progress{ processed: 2, total: 4},
};
let description = object_describe_to_string(&download).unwrap();
assert_eq!(r#"
Filename: debian-11.iso
Progress: 2/4
"#, description);
#[descriptor(output_table)]
Output a table-like output inside the description.
use descriptor::{Descriptor, object_describe_to_string};
#[derive(Descriptor, Clone)]
struct Car {
name: String,
seat: i16,
}
#[derive(Descriptor)]
struct User {
name: String,
cars: Vec<Car>,
#[descriptor(output_table)]
cars_list: Vec<Car>,
}
let cars = vec![Car{name: "Audi".to_string(), seat:4}, Car{name: "Mercedes".to_string(), seat: 2}];
let user = User{
name: "Adrien".to_string(),
cars: cars.clone(),
cars_list: cars.clone(),
};
let description = object_describe_to_string(&user).unwrap();
assert_eq!(r#"
Name: Adrien
Cars:
- Name: Audi
Seat: 4
- Name: Mercedes
Seat: 2
Cars List:
NAME SEAT
Audi 4
Mercedes 2
"#, description);
#[descriptor(skip)]
#[descriptor(skip)]
: Skip this field from description and default headers in table#[descriptor(skip_description)]
: Skip this field only from description#[descriptor(skip_header)]
: Skip this field from default headers
use descriptor::{Descriptor, object_describe_to_string, table_describe_to_string, table_describe_with_header_to_string, object_describe};
#[derive(Descriptor, Clone)]
struct Car {
brand: String,
#[descriptor(skip_header)]
seat: i16,
#[descriptor(skip_description)]
model: String,
#[descriptor(skip)]
serial: String,
}
let car = Car{brand: "Audi".to_string(), seat:4, model: "A3".to_string(), serial: "SN".to_string()};
let cars = vec![
car.clone(),
Car{brand: "Mercedes".to_string(), seat: 2, model: "GLC".to_string(), serial: "WD".to_string()}
];
let description = object_describe_to_string(&car).unwrap();
assert_eq!(r#"
Brand: Audi
Seat: 4
"#, format!("{}", description));
let table = table_describe_to_string(&cars).unwrap();
assert_eq!(r#"
BRAND MODEL
Audi A3
Mercedes GLC
"#, format!("\n{}", table));
let table = table_describe_with_header_to_string(&cars,&vec!["seat".to_string()] ).unwrap();
assert_eq!(r#"
SEAT
4
2
"#, format!("\n{}", table));
#[descriptor(rename_header)]
Rename the auto-generated name for table header
use descriptor::{Descriptor, object_describe_to_string, table_describe_to_string, table_describe_with_header_to_string, object_describe};
#[derive(Descriptor)]
struct Car {
#[descriptor(rename_header="Marque")]
brand: String,
#[descriptor(rename_header="Siege")]
seat: i16,
}
let cars = vec![
Car{brand: "Audi".to_string(), seat:4},
Car{brand: "Mercedes".to_string(), seat: 2}
];
let table = table_describe_to_string(&cars).unwrap();
assert_eq!(r#"
Marque Siege
Audi 4
Mercedes 2
"#, format!("\n{}", table));
Enum parameters
#[descriptor(rename_description = "Renamed")]
Rename the value for enums.
use descriptor::{object_describe_to_string, Descriptor};
#[derive(Descriptor)]
struct User {
name: String,
role: Role,
}
#[derive(Descriptor)]
enum Role {
Admin,
#[descriptor(rename_description = "User role")]
User,
}
let description = object_describe_to_string(&User {
name: "Adrien".to_string(),
role: Role::User,
}).unwrap();
assert_eq!(r#"
Name: Adrien
Role: User role
"#, description);