use std::cell::RefCell; use crate::config::Player; // this global stuff is so that we can load up the config and check stuff without // being part of the Game struct thread_local! { /// Minimum length for name static NAME_MIN: RefCell = RefCell::new(0); /// Maximum length for name static NAME_MAX: RefCell = RefCell::new(0); /// Characters allowed to be in name static NAME_CHARS: RefCell<&'static str> = RefCell::new(""); /// Password minimum length static PASS_MIN: RefCell = RefCell::new(0); /// Password maximum length static PASS_MAX: RefCell = RefCell::new(0); /// Password allowed characters static PASS_CHARS: RefCell<&'static str> = RefCell::new(""); } /// Return value for check functions #[derive(Debug)] pub enum PlayerCheck { /// The value checks out Ok(String), /// There is one or more issues Err(Vec), } /// Initialize the check module from the Player part of the Config. /// /// # Arguments /// /// * config: the Player struct of Config /// /// # Example /// ``` /// use rude::config::Config; /// use rude::check; /// /// let config = Config::load("config.toml").unwrap(); /// check::init(&config.player); /// ``` pub fn init(config: &Player) { NAME_MIN.with(|n| *n.borrow_mut() = config.name_min); NAME_MAX.with(|n| *n.borrow_mut() = config.name_max); NAME_CHARS.with(|n| *n.borrow_mut() = Box::leak(config.name_chars.clone().into_boxed_str())); PASS_MIN.with(|p| *p.borrow_mut() = config.pass_min); PASS_MAX.with(|p| *p.borrow_mut() = config.pass_max); PASS_CHARS.with(|p| *p.borrow_mut() = Box::leak(config.pass_chars.clone().into_boxed_str())); } /// Check the player name to ensure it meets guidelines pub fn player_name>(name: S) -> PlayerCheck { let name = name.into(); let name = name.trim(); let mut err_vec = Vec::::new(); if name.len() < NAME_MIN.with(|n| *n.borrow()) { err_vec.push(format!("{} character minimum", NAME_MIN.with(|n| *n.borrow()))); } else if name.len() > NAME_MAX.with(|n| *n.borrow()) { err_vec.push(format!("{} character maximum", NAME_MAX.with(|n| *n.borrow()))); } for c in name.chars() { if !NAME_CHARS.with(|n| *n.borrow()).contains(&c.to_string()) { err_vec.push(format!( "Allowed characters are: {}", NAME_CHARS.with(|n| *n.borrow()) )); break; } } if err_vec.is_empty() { PlayerCheck::Ok(name.into()) } else { PlayerCheck::Err(err_vec) } } /// Check the password to ensure it meets password requirements pub fn player_password>(password: S) -> PlayerCheck { let password = password.into(); let mut err_vec = Vec::::new(); if password.len() < PASS_MIN.with(|p| *p.borrow()) { err_vec.push(format!("{} character minimum", PASS_MIN.with(|p| *p.borrow()))); } else if password.len() > PASS_MAX.with(|p| *p.borrow()) { err_vec.push(format!("{} character maximum", PASS_MAX.with(|p| *p.borrow()))); } for c in password.chars() { if !PASS_CHARS.with(|p| *p.borrow()).contains(&c.to_string()) { err_vec.push(format!( "Allowed characters are: {}", PASS_CHARS.with(|p| *p.borrow()) )); break; } } if err_vec.is_empty() { PlayerCheck::Ok(password.into()) } else { PlayerCheck::Err(err_vec) } }