pub trait HasField<F: FieldName> {
type Value;
fn get_field(&self) -> &Self::Value;
}
pub trait FieldName {
fn field_name() -> &'static str;
}
pub trait NonEmptyStruct {}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct TestUser {
name: String,
age: i32,
email: String,
}
#[allow(non_camel_case_types)]
pub struct test_name;
impl FieldName for test_name {
fn field_name() -> &'static str {
"name"
}
}
#[allow(non_camel_case_types)]
pub struct test_age;
impl FieldName for test_age {
fn field_name() -> &'static str {
"age"
}
}
#[allow(non_camel_case_types)]
pub struct test_email;
impl FieldName for test_email {
fn field_name() -> &'static str {
"email"
}
}
impl HasField<test_name> for TestUser {
type Value = String;
fn get_field(&self) -> &Self::Value {
&self.name
}
}
impl HasField<test_age> for TestUser {
type Value = i32;
fn get_field(&self) -> &Self::Value {
&self.age
}
}
impl HasField<test_email> for TestUser {
type Value = String;
fn get_field(&self) -> &Self::Value {
&self.email
}
}
#[test]
fn test_field_name_trait() {
assert_eq!(test_name::field_name(), "name");
assert_eq!(test_age::field_name(), "age");
assert_eq!(test_email::field_name(), "email");
}
#[test]
fn test_has_field_trait_manually_implemented() {
let user = TestUser {
name: "John Doe".to_string(),
age: 30,
email: "john.doe@example.com".to_string(),
};
let name_ref: &String = HasField::<test_name>::get_field(&user);
let age_ref: &i32 = HasField::<test_age>::get_field(&user);
let email_ref: &String = HasField::<test_email>::get_field(&user);
assert_eq!(name_ref, &"John Doe".to_string());
assert_eq!(age_ref, &30);
assert_eq!(email_ref, &"john.doe@example.com".to_string());
}
#[test]
fn test_type_safety() {
let user = TestUser {
name: "Test".to_string(),
age: 42,
email: "test@example.com".to_string(),
};
let name_ref: &String = <TestUser as HasField<test_name>>::get_field(&user);
assert_eq!(name_ref, "Test");
let age_ref: &i32 = <TestUser as HasField<test_age>>::get_field(&user);
assert_eq!(*age_ref, 42);
let email_ref: &String = <TestUser as HasField<test_email>>::get_field(&user);
assert_eq!(email_ref, "test@example.com");
}
}