version_track/
versioned.rs

1use std::ops::{Deref, DerefMut};
2
3use crate::Version;
4
5/// A wrapper around data, that tracks mutable changes using mutable dereference counting.
6#[derive(Debug)]
7pub struct Versioned<T> {
8	value: T,
9	version: Version,
10}
11
12impl<T> Versioned<T> {
13	/// Create a new instance of [Self] with an internal version.
14	#[inline]
15	pub fn new(value: T) -> Self {
16		Self::with_version(value, Version::new())
17	}
18
19	/// Creates a new instance of [Self] with a provided version.
20	#[inline]
21	pub fn with_version(value: T, version: Version) -> Self {
22		Self { value, version }
23	}
24
25	/// Returns current version.
26	#[inline]
27	pub fn version(&self) -> Version {
28		self.version
29	}
30}
31
32impl<T> Default for Versioned<T>
33where T: Default
34{
35	/// Proxy default call, that creates a version tracker `T` with a default value.
36	#[inline]
37	fn default() -> Self {
38		Self::new(T::default())
39	}
40}
41
42#[allow(clippy::expl_impl_clone_on_copy)]
43impl<T> Clone for Versioned<T>
44where T: Clone
45{
46	/// Proxy clone call, that creates a new tracked version of `T` by cloning `T`. The version is not cloned, and a
47	/// new version is created.
48	#[inline]
49	fn clone(&self) -> Self {
50		Self::new(self.value.clone())
51	}
52}
53
54impl<T> Copy for Versioned<T> where T: Copy {}
55
56impl<T> Deref for Versioned<T> {
57	type Target = T;
58
59	/// Dereferences the value. Does not increment version.
60	#[must_use]
61	#[inline]
62	fn deref(&self) -> &Self::Target {
63		&self.value
64	}
65}
66
67impl<T> AsRef<T> for Versioned<T> {
68	/// Returns reference to the value. Does not increment version.
69	#[must_use]
70	#[inline]
71	fn as_ref(&self) -> &T {
72		self
73	}
74}
75
76impl<T> DerefMut for Versioned<T> {
77	/// Mutably dereferences the value. Increments version.
78	#[must_use]
79	#[inline]
80	fn deref_mut(&mut self) -> &mut Self::Target {
81		self.version.increment();
82		&mut self.value
83	}
84}
85
86impl<T> AsMut<T> for Versioned<T> {
87	/// Returns mutable reference to the value. Increments version.
88	#[must_use]
89	#[inline]
90	fn as_mut(&mut self) -> &mut T {
91		self
92	}
93}
94
95#[cfg(test)]
96mod tests {
97	use super::*;
98	use crate::SENTINEL_VERSION;
99
100	#[derive(Debug, PartialEq, Copy, Clone)]
101	struct TestType {
102		value: usize,
103	}
104
105	impl Default for TestType {
106		fn default() -> Self {
107			Self { value: 42 }
108		}
109	}
110
111	#[test]
112	fn new() {
113		let versioned_value = Versioned::new(42);
114		assert_eq!(*versioned_value, 42);
115	}
116
117	#[test]
118	fn with_version() {
119		let versioned_value = Versioned::with_version(42, SENTINEL_VERSION);
120		assert_eq!(*versioned_value, 42);
121		assert_eq!(versioned_value.version(), SENTINEL_VERSION);
122	}
123
124	#[test]
125	fn version() {
126		let versioned_value = Versioned::with_version(42, SENTINEL_VERSION);
127		assert_eq!(versioned_value.version(), SENTINEL_VERSION);
128	}
129
130	#[test]
131	fn default_impl() {
132		let versioned_value = Versioned::<TestType>::default();
133		assert_eq!(*versioned_value, TestType::default());
134	}
135
136	#[test]
137	#[allow(clippy::clone_on_copy)]
138	fn clone_impl() {
139		let versioned_value = Versioned::new(TestType::default());
140		let initial_version = versioned_value.version();
141		let cloned = versioned_value.clone();
142		assert_eq!(*cloned, *versioned_value);
143		assert_ne!(initial_version, cloned.version());
144	}
145
146	#[test]
147	fn deref() {
148		let versioned_value = Versioned::new(TestType::default());
149		let initial_version = versioned_value.version();
150		assert_eq!(&*versioned_value, &TestType::default());
151		assert_eq!(initial_version, versioned_value.version());
152	}
153
154	#[test]
155	fn as_ref() {
156		let versioned_value = Versioned::new(TestType::default());
157		let initial_version = versioned_value.version();
158		assert_eq!(versioned_value.as_ref(), &TestType::default());
159		assert_eq!(initial_version, versioned_value.version());
160	}
161
162	#[test]
163	fn deref_mut() {
164		let mut versioned_value = Versioned::new(TestType::default());
165		let initial_version = versioned_value.version();
166		let value = &mut *versioned_value;
167		value.value = 99;
168		assert_eq!(*versioned_value, TestType { value: 99 });
169		assert_ne!(initial_version, versioned_value.version());
170	}
171
172	#[test]
173	fn as_mut() {
174		let mut versioned_value = Versioned::new(TestType::default());
175		let initial_version = versioned_value.version();
176		let value = versioned_value.as_mut();
177		value.value = 99;
178		assert_eq!(*versioned_value, TestType { value: 99 });
179		assert_ne!(initial_version, versioned_value.version());
180	}
181}