scuffle_ffmpeg/
smart_object.rs

1#[derive(Debug)]
2pub(crate) struct SmartPtr<T>(SmartObject<*mut T>);
3
4#[derive(Debug)]
5pub(crate) struct SmartObject<T> {
6    value: Option<T>,
7    destructor: fn(&mut T),
8}
9
10impl<T> SmartObject<T> {
11    /// Creates a new `SmartObject` instance.
12    pub(crate) const fn new(value: T, destructor: fn(&mut T)) -> Self {
13        Self {
14            value: Some(value),
15            destructor,
16        }
17    }
18
19    /// Sets the destructor for the `SmartObject`.
20    pub(crate) const fn set_destructor(&mut self, destructor: fn(&mut T)) {
21        self.destructor = destructor;
22    }
23
24    /// Consumes the `SmartObject` and returns the inner value.
25    pub(crate) fn into_inner(mut self) -> T {
26        self.value.take().unwrap()
27    }
28
29    /// Returns the inner value of the `SmartObject`.
30    pub(crate) const fn inner(&self) -> T
31    where
32        T: Copy,
33    {
34        self.value.unwrap()
35    }
36
37    /// Returns a mutable reference to the inner value of the `SmartObject`.
38    pub(crate) const fn inner_mut(&mut self) -> &mut T {
39        self.value.as_mut().unwrap()
40    }
41
42    pub(crate) const fn inner_ref(&self) -> &T {
43        self.value.as_ref().unwrap()
44    }
45}
46
47impl<T> std::ops::Deref for SmartObject<T> {
48    type Target = T;
49
50    fn deref(&self) -> &Self::Target {
51        self.value.as_ref().unwrap()
52    }
53}
54
55impl<T> std::ops::DerefMut for SmartObject<T> {
56    fn deref_mut(&mut self) -> &mut Self::Target {
57        self.value.as_mut().unwrap()
58    }
59}
60
61impl<T> Drop for SmartObject<T> {
62    fn drop(&mut self) {
63        if let Some(mut value) = self.value.take() {
64            (self.destructor)(&mut value);
65        }
66    }
67}
68
69impl<T> AsRef<T> for SmartObject<T> {
70    fn as_ref(&self) -> &T {
71        self.value.as_ref().unwrap()
72    }
73}
74
75impl<T> AsMut<T> for SmartObject<T> {
76    fn as_mut(&mut self) -> &mut T {
77        self.value.as_mut().unwrap()
78    }
79}
80
81impl<T> SmartPtr<T> {
82    /// Safety: The pointer must be valid.
83    pub(crate) const unsafe fn wrap(ptr: *mut T, destructor: fn(&mut *mut T)) -> Self {
84        Self(SmartObject::new(ptr, destructor))
85    }
86
87    /// Creates a new `SmartPtr` instance with a null pointer.
88    pub(crate) const fn null(destructor: fn(&mut *mut T)) -> Self {
89        Self(SmartObject::new(std::ptr::null_mut(), destructor))
90    }
91
92    /// Safety: The pointer must be valid.
93    pub(crate) const unsafe fn wrap_non_null(ptr: *mut T, destructor: fn(&mut *mut T)) -> Option<Self> {
94        if ptr.is_null() {
95            None
96        } else {
97            // Safety: The pointer is valid.
98            Some(unsafe { Self::wrap(ptr, destructor) })
99        }
100    }
101
102    pub(crate) const fn set_destructor(&mut self, destructor: fn(&mut *mut T)) {
103        self.0.set_destructor(destructor);
104    }
105
106    pub(crate) fn into_inner(self) -> *mut T {
107        self.0.into_inner()
108    }
109
110    pub(crate) const fn as_deref(&self) -> Option<&T> {
111        // Safety: The pointer is valid.
112        unsafe { self.0.inner().as_ref() }
113    }
114
115    pub(crate) const fn as_deref_mut(&mut self) -> Option<&mut T> {
116        // Safety: The pointer is valid.
117        unsafe { self.0.inner().as_mut() }
118    }
119
120    /// Panics if the pointer is null.
121    pub(crate) const fn as_deref_except(&self) -> &T {
122        self.as_deref().expect("deref is null")
123    }
124
125    /// Panics if the pointer is null.
126    pub(crate) const fn as_deref_mut_except(&mut self) -> &mut T {
127        self.as_deref_mut().expect("deref is null")
128    }
129
130    pub(crate) const fn as_ptr(&self) -> *const T {
131        self.0.inner()
132    }
133
134    pub(crate) const fn as_mut_ptr(&mut self) -> *mut T {
135        self.0.inner()
136    }
137
138    pub(crate) const fn as_mut(&mut self) -> &mut *mut T {
139        self.0.inner_mut()
140    }
141}
142
143#[cfg(test)]
144#[cfg_attr(all(test, coverage_nightly), coverage(off))]
145mod tests {
146    use crate::smart_object::{SmartObject, SmartPtr};
147
148    #[test]
149    fn test_smart_object_as_ref() {
150        let smart_object = SmartObject::new(42, |_value: &mut i32| {});
151        let as_ref_value: &i32 = smart_object.as_ref();
152
153        assert_eq!(*as_ref_value, 42, "Expected `as_ref` to return a reference to the value");
154    }
155
156    #[test]
157    fn test_smart_object_as_mut() {
158        let mut smart_object = SmartObject::new(42, |_value: &mut i32| {});
159        let as_mut_value: &mut i32 = smart_object.as_mut();
160        *as_mut_value = 100;
161
162        assert_eq!(*smart_object, 100, "Expected `as_mut` to allow modifying the value");
163    }
164
165    #[test]
166    fn test_smart_ptr_wrap_non_null_is_null() {
167        // no-op destructor function
168        fn noop_destructor<T>(_ptr: &mut *mut T) {}
169        let ptr: *mut i32 = std::ptr::null_mut();
170
171        // Safety: `ptr` is a valid pointer
172        let result = unsafe { SmartPtr::wrap_non_null(ptr, noop_destructor) };
173
174        assert!(result.is_none(), "Expected `wrap_non_null` to return None for a null pointer");
175    }
176}