use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Guarded<T> {
inner: T,
}
impl<T> Guarded<T> {
pub fn new(value: T) -> Self {
Self { inner: value }
}
pub fn read(&self) -> &T {
&self.inner
}
pub fn write(&mut self, _token: &WriteToken) -> &mut T {
&mut self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: Default> Default for Guarded<T> {
fn default() -> Self {
Self {
inner: T::default(),
}
}
}
pub struct WriteToken {
_private: (),
}
impl WriteToken {
pub(crate) fn new() -> Self {
Self { _private: () }
}
}
unsafe impl Send for WriteToken {}
unsafe impl Sync for WriteToken {}
impl std::fmt::Debug for WriteToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("WriteToken")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_guarded_read_without_token() {
let guarded = Guarded::new(42);
assert_eq!(*guarded.read(), 42);
}
#[test]
fn test_guarded_write_with_token() {
let mut guarded = Guarded::new(42);
let token = WriteToken::new();
*guarded.write(&token) = 100;
assert_eq!(*guarded.read(), 100);
}
#[test]
fn test_guarded_serde_transparent() {
let guarded = Guarded::new("hello".to_string());
let json = serde_json::to_string(&guarded).unwrap();
assert_eq!(json, "\"hello\"");
let deserialized: Guarded<String> = serde_json::from_str(&json).unwrap();
assert_eq!(*deserialized.read(), "hello");
}
#[test]
fn test_guarded_with_struct() {
use std::collections::HashMap;
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct Headers {
map: HashMap<String, String>,
}
let mut guarded = Guarded::new(Headers::default());
let token = WriteToken::new();
assert!(guarded.read().map.is_empty());
guarded
.write(&token)
.map
.insert("X-Auth".into(), "Bearer tok".into());
assert_eq!(guarded.read().map.get("X-Auth").unwrap(), "Bearer tok");
}
}