use alloc::sync::Arc;
use core::sync::atomic::AtomicBool;
use core::sync::atomic::Ordering;
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct VaultConfig {
pub key_normalization: bool,
}
impl VaultConfig {
#[must_use]
pub fn new() -> Self {
Self {
key_normalization: true,
}
}
}
#[derive(Clone)]
pub struct KeyVault {
inner: Arc<VaultInner>,
}
struct VaultInner {
config: VaultConfig,
locked_out: AtomicBool,
}
impl KeyVault {
#[must_use]
pub fn is_locked_out(&self) -> bool {
self.inner.locked_out.load(Ordering::Acquire)
}
#[must_use]
pub fn config(&self) -> &VaultConfig {
&self.inner.config
}
}
impl core::fmt::Debug for KeyVault {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("KeyVault")
.field("locked_out", &self.is_locked_out())
.field("config", &self.inner.config)
.finish()
}
}
#[derive(Debug, Default, Clone)]
pub struct KeyVaultBuilder {
config: VaultConfig,
}
impl KeyVaultBuilder {
#[must_use]
pub fn new() -> Self {
Self {
config: VaultConfig::new(),
}
}
#[must_use]
pub fn normalize_with_blake3(mut self, enabled: bool) -> Self {
self.config.key_normalization = enabled;
self
}
#[must_use]
pub fn build(self) -> KeyVault {
KeyVault {
inner: Arc::new(VaultInner {
config: self.config,
locked_out: AtomicBool::new(false),
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
#[test]
fn builder_defaults_to_normalization_on() {
let v = KeyVaultBuilder::new().build();
assert!(v.config().key_normalization);
}
#[test]
fn builder_can_disable_normalization() {
let v = KeyVaultBuilder::new().normalize_with_blake3(false).build();
assert!(!v.config().key_normalization);
}
#[test]
fn fresh_vault_is_not_locked_out() {
let v = KeyVaultBuilder::new().build();
assert!(!v.is_locked_out());
}
#[test]
fn debug_does_not_panic() {
let v = KeyVaultBuilder::new().build();
let _ = format!("{v:?}");
}
}