use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock};
#[derive(Debug)]
pub struct AuthState {
authenticated: AtomicBool,
username: OnceLock<Arc<str>>,
}
impl AuthState {
#[inline]
#[must_use]
pub const fn new() -> Self {
Self {
authenticated: AtomicBool::new(false),
username: OnceLock::new(),
}
}
#[inline]
#[must_use]
pub fn is_authenticated(&self) -> bool {
self.authenticated.load(Ordering::Relaxed)
}
#[inline]
pub fn mark_authenticated(&self, username: impl Into<Arc<str>>) {
let username_arc: Arc<str> = username.into();
let _ = self.username.set(username_arc);
self.authenticated.store(true, Ordering::Relaxed);
}
#[inline]
#[must_use]
pub fn username(&self) -> Option<&str> {
self.username.get().map(|arc| &**arc)
}
#[inline]
#[must_use]
pub fn is_authenticated_or_skipped(&self, skip_check: bool) -> bool {
skip_check || self.is_authenticated()
}
}
impl Default for AuthState {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_unauthenticated() {
let state = AuthState::new();
assert!(!state.is_authenticated());
assert!(state.username().is_none());
}
#[test]
fn test_mark_authenticated() {
let state = AuthState::new();
state.mark_authenticated("testuser");
assert!(state.is_authenticated());
assert_eq!(state.username().unwrap(), "testuser");
}
#[test]
fn test_mark_authenticated_with_arc() {
let state = AuthState::new();
let username: Arc<str> = Arc::from("arcuser");
state.mark_authenticated(username);
assert!(state.is_authenticated());
assert_eq!(state.username().unwrap(), "arcuser");
}
#[test]
fn test_is_authenticated_or_skipped() {
let state = AuthState::new();
assert!(!state.is_authenticated_or_skipped(false));
assert!(state.is_authenticated_or_skipped(true));
state.mark_authenticated("skiptest");
assert!(state.is_authenticated_or_skipped(false));
assert!(state.is_authenticated_or_skipped(true));
}
#[test]
fn test_default() {
let state = AuthState::default();
assert!(!state.is_authenticated());
assert!(state.username().is_none());
}
#[test]
fn test_multiple_mark_same_username() {
let state = AuthState::new();
state.mark_authenticated("same");
state.mark_authenticated("same");
assert!(state.is_authenticated());
assert_eq!(state.username().unwrap(), "same");
}
}