gstreamer/subclass/
allocator.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{bool_error, prelude::*, subclass::prelude::*, translate::*, BoolError};
6
7use super::prelude::*;
8use crate::{ffi, AllocationParams, Allocator, Memory};
9
10pub trait AllocatorImpl: AllocatorImplExt + GstObjectImpl + Send + Sync {
11    /// Use `self` to allocate a new memory block with memory that is at least
12    /// `size` big.
13    ///
14    /// The optional `params` can specify the prefix and padding for the memory. If
15    /// [`None`] is passed, no flags, no extra prefix/padding and a default alignment is
16    /// used.
17    ///
18    /// The prefix/padding will be filled with 0 if flags contains
19    /// [`MemoryFlags::ZERO_PREFIXED`][crate::MemoryFlags::ZERO_PREFIXED] and [`MemoryFlags::ZERO_PADDED`][crate::MemoryFlags::ZERO_PADDED] respectively.
20    ///
21    /// When `self` is [`None`], the default allocator will be used.
22    ///
23    /// The alignment in `params` is given as a bitmask so that `align` + 1 equals
24    /// the amount of bytes to align to. For example, to align to 8 bytes,
25    /// use an alignment of 7.
26    /// ## `size`
27    /// size of the visible memory area
28    /// ## `params`
29    /// optional parameters
30    ///
31    /// # Returns
32    ///
33    /// a new [`Memory`][crate::Memory].
34    fn alloc(&self, size: usize, params: Option<&AllocationParams>) -> Result<Memory, BoolError> {
35        self.parent_alloc(size, params)
36    }
37
38    fn free(&self, memory: Memory) {
39        self.parent_free(memory)
40    }
41}
42
43mod sealed {
44    pub trait Sealed {}
45    impl<T: super::AllocatorImplExt> Sealed for T {}
46}
47
48pub trait AllocatorImplExt: sealed::Sealed + ObjectSubclass {
49    fn parent_alloc(
50        &self,
51        size: usize,
52        params: Option<&AllocationParams>,
53    ) -> Result<Memory, BoolError> {
54        unsafe {
55            let data = Self::type_data();
56            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAllocatorClass;
57
58            if let Some(f) = (*parent_class).alloc {
59                from_glib_full::<*mut ffi::GstMemory, Option<_>>(f(
60                    self.obj().unsafe_cast_ref::<Allocator>().to_glib_none().0,
61                    size,
62                    mut_override(params.to_glib_none().0),
63                ))
64                .ok_or_else(|| bool_error!("Allocation failed"))
65            } else {
66                Err(bool_error!("No allocation method on parent class"))
67            }
68        }
69    }
70
71    fn parent_free(&self, memory: Memory) {
72        unsafe {
73            let data = Self::type_data();
74            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAllocatorClass;
75
76            if let Some(f) = (*parent_class).free {
77                f(
78                    self.obj().unsafe_cast_ref::<Allocator>().to_glib_none().0,
79                    memory.into_glib_ptr(),
80                )
81            }
82        }
83    }
84}
85
86impl<T: AllocatorImpl> AllocatorImplExt for T {}
87
88unsafe impl<T: AllocatorImpl> IsSubclassable<T> for Allocator {
89    fn class_init(klass: &mut glib::Class<Self>) {
90        Self::parent_class_init::<T>(klass);
91        let klass = klass.as_mut();
92        klass.alloc = Some(alloc::<T>);
93        klass.free = Some(free::<T>);
94    }
95}
96
97unsafe extern "C" fn alloc<T: AllocatorImpl>(
98    ptr: *mut ffi::GstAllocator,
99    size: usize,
100    params: *mut ffi::GstAllocationParams,
101) -> *mut ffi::GstMemory {
102    let instance = &*(ptr as *mut T::Instance);
103    let imp = instance.imp();
104    let instance = imp.obj();
105
106    let params = if params.is_null() {
107        None
108    } else {
109        Some(&*(params as *mut AllocationParams))
110    };
111
112    imp.alloc(size, params)
113        .map(|memory| memory.into_glib_ptr())
114        .unwrap_or_else(|error| {
115            error!(crate::CAT_RUST, obj = instance, "{:?}", error);
116
117            ptr::null_mut()
118        })
119}
120
121unsafe extern "C" fn free<T: AllocatorImpl>(
122    ptr: *mut ffi::GstAllocator,
123    memory: *mut ffi::GstMemory,
124) {
125    let instance = &*(ptr as *mut T::Instance);
126    let imp = instance.imp();
127    let memory = from_glib_full(memory);
128
129    imp.free(memory);
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135    use crate::prelude::*;
136
137    pub mod imp {
138        use super::*;
139
140        #[derive(Default)]
141        pub struct TestAllocator;
142
143        impl ObjectImpl for TestAllocator {}
144        impl GstObjectImpl for TestAllocator {}
145        impl AllocatorImpl for TestAllocator {
146            fn alloc(
147                &self,
148                size: usize,
149                _params: Option<&AllocationParams>,
150            ) -> Result<Memory, BoolError> {
151                Ok(Memory::from_slice(vec![0; size]))
152            }
153
154            fn free(&self, memory: Memory) {
155                self.parent_free(memory)
156            }
157        }
158
159        #[glib::object_subclass]
160        impl ObjectSubclass for TestAllocator {
161            const NAME: &'static str = "TestAllocator";
162            type Type = super::TestAllocator;
163            type ParentType = Allocator;
164        }
165    }
166
167    glib::wrapper! {
168        pub struct TestAllocator(ObjectSubclass<imp::TestAllocator>) @extends Allocator, crate::Object;
169    }
170
171    impl Default for TestAllocator {
172        fn default() -> Self {
173            glib::Object::new()
174        }
175    }
176
177    #[test]
178    fn test_allocator_registration() {
179        crate::init().unwrap();
180
181        const TEST_ALLOCATOR_NAME: &str = "TestAllocator";
182
183        let allocator = TestAllocator::default();
184        Allocator::register(TEST_ALLOCATOR_NAME, allocator);
185
186        let allocator = Allocator::find(Some(TEST_ALLOCATOR_NAME));
187
188        assert!(allocator.is_some());
189    }
190
191    #[test]
192    fn test_allocator_alloc() {
193        crate::init().unwrap();
194
195        const SIZE: usize = 1024;
196
197        let allocator = TestAllocator::default();
198
199        let memory = allocator.alloc(SIZE, None).unwrap();
200
201        assert_eq!(memory.size(), SIZE);
202    }
203}