use std::ops::Deref;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(bound = "T: Serialize + DeserializeOwned")]
pub struct ReducedValue<T>
where
T: Serialize + DeserializeOwned + Clone + Send + Sync,
{
items: Vec<T>,
}
impl<T> ReducedValue<T>
where
T: Serialize + DeserializeOwned + Clone + Send + Sync,
{
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(&mut self, value: T) {
self.items.push(value);
}
pub fn extend(&mut self, values: impl IntoIterator<Item = T>) {
self.items.extend(values);
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
impl<T> Deref for ReducedValue<T>
where
T: Serialize + DeserializeOwned + Clone + Send + Sync,
{
type Target = [T];
fn deref(&self) -> &[T] {
&self.items
}
}
impl<T> Default for ReducedValue<T>
where
T: Serialize + DeserializeOwned + Clone + Send + Sync,
{
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct UntrackedValue<T: Default + Send + Sync> {
value: T,
}
impl<T: Default + Send + Sync> UntrackedValue<T> {
pub fn new() -> Self {
Self { value: T::default() }
}
pub fn with_value(value: T) -> Self {
Self { value }
}
pub fn get(&self) -> &T {
&self.value
}
pub fn set(&mut self, value: T) {
self.value = value;
}
pub fn take(&mut self) -> T {
std::mem::take(&mut self.value)
}
}
impl<T: Default + Send + Sync> Default for UntrackedValue<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Default + Send + Sync> Serialize for UntrackedValue<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_none()
}
}
impl<'de, T: Default + Send + Sync> Deserialize<'de> for UntrackedValue<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let _ = serde::de::IgnoredAny::deserialize(deserializer)?;
Ok(Self::new())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reduced_value_new_is_empty() {
let rv: ReducedValue<i32> = ReducedValue::new();
assert!(rv.is_empty());
assert_eq!(rv.len(), 0);
}
#[test]
fn test_reduced_value_push_and_deref() {
let mut rv = ReducedValue::new();
rv.push(1);
rv.push(2);
rv.push(3);
assert_eq!(rv.len(), 3);
assert_eq!(&*rv, &[1, 2, 3]);
}
#[test]
fn test_reduced_value_extend() {
let mut rv = ReducedValue::new();
rv.extend(vec![10, 20, 30]);
assert_eq!(rv.len(), 3);
assert_eq!(&*rv, &[10, 20, 30]);
}
#[test]
fn test_reduced_value_serde_round_trip() {
let mut rv = ReducedValue::new();
rv.push("hello".to_string());
rv.push("world".to_string());
let json = serde_json::to_string(&rv).unwrap();
let restored: ReducedValue<String> = serde_json::from_str(&json).unwrap();
assert_eq!(&*restored, &*rv);
}
#[test]
fn test_new_creates_default_value() {
let uv: UntrackedValue<i32> = UntrackedValue::new();
assert_eq!(*uv.get(), 0);
}
#[test]
fn test_with_value_stores_value() {
let uv = UntrackedValue::with_value(42);
assert_eq!(*uv.get(), 42);
}
#[test]
fn test_set_and_get() {
let mut uv: UntrackedValue<String> = UntrackedValue::new();
assert_eq!(uv.get(), "");
uv.set("hello".to_string());
assert_eq!(uv.get(), "hello");
}
#[test]
fn test_take_returns_value_and_resets() {
let mut uv = UntrackedValue::with_value(vec![1, 2, 3]);
let taken = uv.take();
assert_eq!(taken, vec![1, 2, 3]);
assert!(uv.get().is_empty());
}
#[test]
fn test_default_trait() {
let uv: UntrackedValue<bool> = UntrackedValue::default();
assert!(!*uv.get());
}
#[test]
fn test_serialize_produces_null() {
let uv = UntrackedValue::with_value(999);
let serialized = serde_json::to_string(&uv).unwrap();
assert_eq!(serialized, "null");
}
#[test]
fn test_deserialize_always_produces_default() {
let restored: UntrackedValue<i32> = serde_json::from_str("null").unwrap();
assert_eq!(*restored.get(), 0);
let restored: UntrackedValue<i32> = serde_json::from_str("42").unwrap();
assert_eq!(*restored.get(), 0);
let restored: UntrackedValue<Vec<i32>> = serde_json::from_str("[1,2,3]").unwrap();
assert!(restored.get().is_empty());
}
#[test]
fn test_round_trip_resets_value() {
let uv = UntrackedValue::with_value("important data".to_string());
let serialized = serde_json::to_string(&uv).unwrap();
let restored: UntrackedValue<String> = serde_json::from_str(&serialized).unwrap();
assert_eq!(restored.get(), "");
}
}