ref-view 0.1.0

Derive zero-copy reference views for structs and enums
Documentation
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));
}