reactive_mutiny/ogre_std/ogre_alloc/
ogre_unique.rs

1//! Resting place for [OgreUnique<>]
2
3use crate::ogre_std::ogre_alloc::{
4    ogre_arc::OgreArc,
5    BoundedOgreAllocator,
6    };
7use std::{
8    ops::Deref,
9    fmt::{Debug, Display, Formatter},
10};
11use std::borrow::Borrow;
12
13
14/// Wrapper type for data that requires a custom Drop to be called (through an [BoundedOgreAllocator]).
15/// Similar to C++'s `unique_ptr`
16pub struct OgreUnique<DataType:          Debug + Send + Sync + 'static,
17                      OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync + 'static> {
18    allocator: &'static OgreAllocatorType,
19    data_ref:  &'static DataType,
20}
21
22
23impl<DataType:          Debug + Send + Sync + 'static,
24     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
25OgreUnique<DataType, OgreAllocatorType> {
26
27    #[inline(always)]
28    pub fn new<F: FnOnce(&mut DataType)>(setter: F, allocator: &OgreAllocatorType) -> Option<Self> {
29        allocator.alloc_ref()
30            .map(|(slot_ref, _slot_id)| {
31                setter(slot_ref);
32                Self::from_allocated_ref(slot_ref, allocator)
33            })
34    }
35
36    #[inline(always)]
37    pub fn from_allocated_id(data_id: u32, allocator: &OgreAllocatorType) -> Self {
38        let data_ref = allocator.ref_from_id(data_id);
39        Self::from_allocated_ref(data_ref, allocator)
40    }
41
42    #[inline(always)]
43    pub fn from_allocated_ref(data_ref: &DataType, allocator: &OgreAllocatorType) -> Self {
44        Self {
45            allocator: unsafe { &*(allocator as *const OgreAllocatorType) },
46            data_ref:  unsafe { &*(data_ref as *const DataType) },
47        }
48    }
49
50    #[inline(always)]
51    pub fn into_ogre_arc(self) -> OgreArc<DataType, OgreAllocatorType> {
52        let undroppable_self = std::mem::ManuallyDrop::new(self);
53        OgreArc::from_allocated(undroppable_self.allocator.id_from_ref(undroppable_self.data_ref), undroppable_self.allocator)
54    }
55
56}
57
58
59impl<DataType:          Debug + Send + Sync,
60     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
61Deref for
62OgreUnique<DataType, OgreAllocatorType> {
63
64    type Target = DataType;
65
66    #[inline(always)]
67    fn deref(&self) -> &Self::Target {
68        self.data_ref
69    }
70}
71
72
73impl<DataType:          Debug + Send + Sync,
74     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
75AsRef<DataType> for
76OgreUnique<DataType, OgreAllocatorType> {
77
78    #[inline(always)]
79    fn as_ref(&self) -> &DataType {
80        self.data_ref
81    }
82
83}
84
85impl<DataType:          Debug + Send + Sync,
86     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
87Borrow<DataType> for
88OgreUnique<DataType, OgreAllocatorType> {
89
90    #[inline(always)]
91    fn borrow(&self) -> &DataType {
92        self.data_ref
93    }
94}
95
96impl<DataType:          Debug + Send + Sync + Display,
97     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
98Display for
99OgreUnique<DataType, OgreAllocatorType> {
100
101    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102        std::fmt::Display::fmt(&self.deref(), f)
103    }
104}
105
106
107impl<DataType:          Debug + Send + Sync,
108     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
109Debug for
110OgreUnique<DataType, OgreAllocatorType> {
111
112    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
113        write!(f, "OgreUnique {{allocator: {:?}, data: #{}:{:?}}}",
114                  self.allocator, self.allocator.id_from_ref(self.data_ref), self.data_ref)
115    }
116}
117
118
119impl<DataType:          Debug + Send + Sync,
120     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
121PartialEq<DataType> for
122OgreUnique<DataType, OgreAllocatorType>
123where DataType: PartialEq {
124
125    #[inline(always)]
126    fn eq(&self, other: &DataType) -> bool {
127        self.deref().eq(other)
128    }
129}
130
131
132impl<DataType:          Debug + Send + Sync,
133     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
134From<OgreUnique<DataType, OgreAllocatorType>> for
135OgreArc<DataType, OgreAllocatorType> {
136
137    #[inline(always)]
138    fn from(ogre_unique: OgreUnique<DataType, OgreAllocatorType>) -> OgreArc<DataType, OgreAllocatorType> {
139        ogre_unique.into_ogre_arc()
140    }
141}
142
143
144impl<DataType:          Debug + Send + Sync,
145     OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
146Drop for
147OgreUnique<DataType, OgreAllocatorType> {
148
149    #[inline(always)]
150    fn drop(&mut self) {
151        self.allocator.dealloc_ref(self.data_ref);
152    }
153}
154
155
156unsafe impl<DataType:          Debug + Send + Sync,
157            OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
158Send for
159OgreUnique<DataType, OgreAllocatorType> {}
160
161unsafe impl<DataType:          Debug + Send + Sync,
162            OgreAllocatorType: BoundedOgreAllocator<DataType> + Send + Sync>
163Sync for
164OgreUnique<DataType, OgreAllocatorType> {}
165
166
167#[cfg(any(test,doc))]
168mod tests {
169    //! Unit tests for [ogre_arc](super) module
170
171    use super::*;
172    use crate::prelude::advanced::AllocatorAtomicArray;
173
174
175    #[cfg_attr(not(doc),test)]
176    pub fn happy_path_usage() {
177        let allocator = AllocatorAtomicArray::<u128, 128>::new();
178        let unique = OgreUnique::new(|slot| *slot = 128, &allocator).expect("Allocation should have been done");
179        println!("unique is {unique} -- {:?}", unique);
180        assert_eq!(*unique.deref(), 128, "Value doesn't match");
181        drop(unique);
182        // TODO assert that allocator have all elements free (change the trait) and do a similar assertion in `OgreArc`
183        println!("all is free:");
184        println!("{:?}", allocator);
185    }
186
187    #[cfg_attr(not(doc),test)]
188    pub fn into_ogrearc() {
189        let allocator = AllocatorAtomicArray::<u128, 128>::new();
190        let unique = OgreUnique::new(|slot| *slot = 128, &allocator).expect("Allocation should have been done");
191        let ogre_arc = unique.into_ogre_arc();
192        println!("arc is {ogre_arc} -- {:?}", ogre_arc);
193        assert_eq!((*ogre_arc.deref(), ogre_arc.references_count()), (128, 1), "Starting Value and Reference Counts don't match for the converted `ogre_arc`");
194        drop(ogre_arc);
195        // TODO assert that allocator have all elements free (change the trait) and do a similar assertion in `OgreArc`
196        println!("all is free:");
197        println!("{:?}", allocator);
198    }
199
200    #[cfg_attr(not(doc),test)]
201    pub fn comparisons() {
202        // &str
203        let expected: &str = "&str to compare";
204        let allocator = AllocatorAtomicArray::<&str, 128>::new();
205        let observed = OgreUnique::new(|slot| *slot = expected, &allocator).expect("Allocation should have been done");
206        assert_eq!(observed,  expected,  "Comparison of pristine types failed for `&str`");
207        assert_eq!(&observed, &expected, "Comparison of references failed for `&str`");
208        assert_eq!(*observed, expected,  "Comparison of `Deref` failed for `&str`");
209
210        // String -- notice that, although possible, there is no nice API for "movable values", like `Arc` or `String`: OgreAllocator were not designed for those, therefore, OgreArc, also isn't.
211        let expected: String = String::from("String to compare");
212        let allocator = AllocatorAtomicArray::<String, 128>::new();
213        let observed = OgreUnique::new(|slot| unsafe { std::ptr::write(slot, expected.clone()); }, &allocator).expect("Allocation should have been done");
214        assert_eq!(observed,  expected,  "Comparison of pristine types failed for `String`");
215        assert_eq!(&observed, &expected, "Comparison of references failed for `String`");
216        assert_eq!(*observed, expected,  "Comparison of `Deref` failed for `String`");
217
218        // Wrapped in an `Option<>` (not yet supported as I cannot implement PartialEq for Option<MyType>...)
219        // unwrap and compare instead
220        // let payload = String::from("Wrapped");
221        // let expected = Some(payload.clone());
222        // let allocator = AllocatorAtomicArray::<String, 128>::new();
223        // let observed = Some(OgreUnique::new(|slot| unsafe { std::ptr::write(slot, payload); }, &allocator).expect("Allocation should have been done"));
224        // assert_eq!(observed,  expected,  "Comparison of wrapped types failed for `Option<String>`");
225        // assert_eq!(&observed, &expected, "Comparison of references failed for `Option<String>`");
226        // assert_eq!(*observed, expected,  "Comparison of `Deref` failed for `Option<String>`");
227
228    }
229
230}