Pattern Type State
Published: 2023-10-12
Updated: 2023-11-03
Resource List 🔗
Annotated example 🔗
use std::collections::HashMap;
use std::marker::PhantomData;
struct Locked;
struct Unlocked;
// Note that PasswordManager<Locked> != PasswordManager<Unlocked> because of the state field with doesn't use space at runtime only a compile time check
// Locked is the default state here
struct PasswordManager<State = Locked> {
master_pass: String,
passwords: HashMap<String, String>,
state: PhantomData<State>, // This doesn't take up space at runtime
}
// impl only available while "Locked"
impl PasswordManager<Locked> {
pub fn unlock(self, master_pass: String) -> PasswordManager<Unlocked> {
PasswordManager {
master_pass: self.master_pass,
passwords: self.passwords,
state: PhantomData,
}
}
}
// impl only available while "Unlocked"
impl PasswordManager<Unlocked> {
pub fn lock(self) -> PasswordManager<Locked> {
PasswordManager {
master_pass: self.master_pass,
passwords: self.passwords,
state: PhantomData,
}
}
pub fn list_passwords(&self) -> &HashMap<String, String> {
&self.passwords
}
pub fn add_password(&mut self, username: String, password: String) {
self.passwords.insert(username, password);
}
}
// impl available in any State (Use T to guard against typos)
impl<T> PasswordManager<T> {
pub fn encryption(&self) -> String {
todo!()
}
pub fn version(&self) -> String {
todo!()
}
}
// impl available before a state is set (Only true static function)
impl PasswordManager {
pub fn new(master_pass: String) -> Self {
PasswordManager {
master_pass,
passwords: Default::default(),
state: PhantomData,
}
}
}
fn main() {
let mut manager = PasswordManager::new("password123".to_owned());
let manager = manager.unlock("password123".to_owned());
manager.list_passwords();
manager.lock();
}