Crates.io | fieldname-access |
lib.rs | fieldname-access |
version | 0.1.11 |
source | src |
created_at | 2024-07-08 16:30:10.827246 |
updated_at | 2024-08-22 23:05:19.480698 |
description | Derive macro for safe struct field access by their names in runtime |
homepage | |
repository | https://github.com/Huterenok/fieldname-access |
max_upload_size | |
id | 1296138 |
size | 29,154 |
It is used to safely get values from the structure by field name when we do not know exactly which field we will need at the moment but can match it and do some actions based on other data.
Also it generates const FIELDS: [&'static str; FIELDS_COUNT]
constant with struct fields and field_iter
method on struct for creating Iterator
over struct using generated field enum.
#fieldname_enum(name = "NewName")
- Name of generated enum of possible valuesuse fieldname_access::FieldnameAccess;
#[derive(FieldnameAccess, Default)]
#[fieldname_enum(name = "NewName")]
struct NamedFieldname {
name: String,
age: i64,
}
let mut instance = NamedFieldname::default();
match instance.field("name").unwrap() {
NewName::String(val) => {}
NewName::I64(val) => {},
}
match instance.field_mut("name").unwrap() {
NewNameMut::String(val) => {}
NewNameMut::I64(val) => {},
}
#fieldname_enum(derive = [Debug, Clone], derive_mut = [Debug])
- Derive macroses for generated enums.
derive
only for enum with immutable references, derive_mut
only for enum with mutable references.
It can be helpful when you want to derive Clone
but only for immutable references as mutable are not clonableuse fieldname_access::FieldnameAccess;
#[derive(FieldnameAccess)]
#[fieldname_enum(derive = [Debug, Clone], derive_mut = [Debug])]
struct NamedFieldname {
name: String,
age: i64,
}
#fieldname_enum(derive_all = [Debug])
- Derive macroses for immutable and mutable generated enumsuse fieldname_access::FieldnameAccess;
#[derive(FieldnameAccess)]
#[fieldname_enum(derive_all = [Debug])]
struct NamedFieldname {
name: String,
age: i64,
}
#fieldname = "AmazingAge"
- Name of variant for field in generated enum.
It can be helpfull when you want to 'mark' field with specific variant nameuse fieldname_access::FieldnameAccess;
#[derive(FieldnameAccess, Default)]
struct NamedFieldname {
name: String,
#[fieldname = "MyAge"]
age: i64,
dog_age: i64
}
let mut instance = NamedFieldname::default();
match instance.field("name").unwrap() {
NamedFieldnameField::String(val) => {}
NamedFieldnameField::MyAge(val) => {}
NamedFieldnameField::I64(val) => {}
}
match instance.field_mut("name").unwrap() {
NamedFieldnameFieldMut::String(val) => {}
NamedFieldnameFieldMut::MyAge(val) => {}
NamedFieldnameFieldMut::I64(val) => {}
}
Let's say we have a User structure and Crit criteria for it.
use fieldname_access::FieldnameAccess;
#[derive(FieldnameAccess)]
#[fieldname_enum(derive_all = [Debug])]
struct User {
name: String,
age: u64,
does_love_ranni: bool, // important
}
struct Crit {
value: String,
field: String,
kind: CritKind,
}
enum CritKind {
Contains,
Equals,
BiggerThan,
}
Based on this information FieldnameAccess
will generate all possible types
of field and methods for User
struct to access them by name:
enum UserField<'a> {
String(&'a String),
U64(&'a u64),
Bool(&'a bool)
}
enum UserFieldMut<'a> {
String(&'a mut String),
U64(&'a mut u64),
Bool(&'a mut bool)
}
Having information on these two elements, we can determine our next steps.
let user = User {
age: 2022,
name: String::from("Radahn"),
does_love_ranni: true,
};
let crits = vec![
Crit {
value: String::from("Ra"),
field: String::from("name"),
kind: CritKind::Contains,
},
Crit {
value: String::from("true"),
field: String::from("does_love_ranni"), // important
kind: CritKind::Equals,
},
Crit {
value: String::from("18"),
field: String::from("age"),
kind: CritKind::BiggerThan,
},
];
let its_ok = crits.into_iter().all(|crit| {
let user_field =
user.field(&crit.field).expect("Criteria has wrong fieldname");
match crit.kind {
CritKind::Contains => match user_field {
UserField::String(str) => str.contains(&crit.value),
_ => panic!("Criteria has wrong value"),
},
CritKind::Equals => match user_field {
UserField::String(str) => str.eq(&crit.value),
UserField::U64(int) => int.eq(&crit.value.parse::<u64>().unwrap()),
UserField::Bool(boolean) => {
boolean.eq(&crit.value.parse::<bool>().unwrap())
}
},
CritKind::BiggerThan => match user_field {
UserField::U64(int) => int > &crit.value.parse::<u64>().unwrap(),
_ => panic!("Criteria has wrong value"),
},
}
});
assert!(its_ok);
Also you can modify fields
if let Some(UserFieldMut::Bool(does_love_ranni)) =
user.field_mut("does_love_ranni") // important
{
*does_love_ranni = false; // HARAM
}
assert!(!user.does_love_ranni); //important
And iterate over struct fields
let not_so_pretty_output = user
.field_iter()
.map(|(field_name, enum_var)| format!("{}={:?}", field_name, enum_var))
.join("\n");
println!("Here it is {}", not_so_pretty_output);