scuffle_ffmpeg/
smart_object.rs1#[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 pub(crate) const fn new(value: T, destructor: fn(&mut T)) -> Self {
13 Self {
14 value: Some(value),
15 destructor,
16 }
17 }
18
19 pub(crate) const fn set_destructor(&mut self, destructor: fn(&mut T)) {
21 self.destructor = destructor;
22 }
23
24 pub(crate) fn into_inner(mut self) -> T {
26 self.value.take().unwrap()
27 }
28
29 pub(crate) const fn inner(&self) -> T
31 where
32 T: Copy,
33 {
34 self.value.unwrap()
35 }
36
37 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 pub(crate) const unsafe fn wrap(ptr: *mut T, destructor: fn(&mut *mut T)) -> Self {
84 Self(SmartObject::new(ptr, destructor))
85 }
86
87 pub(crate) const fn null(destructor: fn(&mut *mut T)) -> Self {
89 Self(SmartObject::new(std::ptr::null_mut(), destructor))
90 }
91
92 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 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 unsafe { self.0.inner().as_ref() }
113 }
114
115 pub(crate) const fn as_deref_mut(&mut self) -> Option<&mut T> {
116 unsafe { self.0.inner().as_mut() }
118 }
119
120 pub(crate) const fn as_deref_except(&self) -> &T {
122 self.as_deref().expect("deref is null")
123 }
124
125 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 fn noop_destructor<T>(_ptr: &mut *mut T) {}
169 let ptr: *mut i32 = std::ptr::null_mut();
170
171 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}