use std::fmt;
use ref_view::RefView;
#[derive(Debug, PartialEq, Eq)]
enum Role {
Admin,
Member,
}
#[derive(Debug, PartialEq, Eq, RefView)]
#[ref_view(derive(Debug, PartialEq, Eq))]
#[ref_view(name = PublicUserRef, omit(email, api_token))]
struct User {
id: u64,
name: String,
role: Role,
email: Option<String>,
api_token: String,
}
fn role_label(user: &impl UserView) -> String {
format!("{:?}", user.role())
}
#[ref_view::impl_fn(UserView)]
fn compact_label(user: &User) -> String {
format!("{}#{} ({:?})", user.name(), user.id(), user.role())
}
#[ref_view::impl_fn(UserView)]
fn optional_contact(user: &User) -> &'static str {
if user.email().is_some() {
"contactable"
} else {
"private"
}
}
trait AuditSummary {
fn audit_summary(&self) -> String;
}
impl<T: UserView> AuditSummary for T {
fn audit_summary(&self) -> String {
let token_state = if self.api_token().is_some() {
"token=present"
} else {
"token=hidden"
};
format!("{} {}", compact_label(self), token_state)
}
}
#[ref_view::impl_trait(UserView => UserRef<'_>, PublicUserRef<'_>)]
impl fmt::Display for User {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} [{}]", compact_label(self), optional_contact(self))
}
}
fn main() {
let user = User {
id: 7,
name: "Ada".to_string(),
role: Role::Admin,
email: Some("ada@example.com".to_string()),
api_token: "secret-token".to_string(),
};
let full = UserRef::from(&user);
let public = PublicUserRef::from(&user);
assert_eq!(full, UserRef::from(&user));
assert_eq!(public, PublicUserRef::from(&user));
println!("{:?}", full);
println!("{:?}", public);
println!("{}", full.audit_summary());
println!("{}", public.audit_summary());
println!("{}", role_label(&public));
println!("{}", user);
println!("{}", full);
println!("{}", public);
let member = User {
id: 8,
name: "Grace".to_string(),
role: Role::Member,
email: None,
api_token: "member-token".to_string(),
};
println!("{}", compact_label(&member));
}