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: GstObjectImpl + ObjectSubclass<Type: IsA<Allocator>> {
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
43pub trait AllocatorImplExt: AllocatorImpl {
44    fn parent_alloc(
45        &self,
46        size: usize,
47        params: Option<&AllocationParams>,
48    ) -> Result<Memory, BoolError> {
49        unsafe {
50            let data = Self::type_data();
51            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAllocatorClass;
52
53            if let Some(f) = (*parent_class).alloc {
54                from_glib_full::<*mut ffi::GstMemory, Option<_>>(f(
55                    self.obj().unsafe_cast_ref::<Allocator>().to_glib_none().0,
56                    size,
57                    mut_override(params.to_glib_none().0),
58                ))
59                .ok_or_else(|| bool_error!("Allocation failed"))
60            } else {
61                Err(bool_error!("No allocation method on parent class"))
62            }
63        }
64    }
65
66    fn parent_free(&self, memory: Memory) {
67        unsafe {
68            let data = Self::type_data();
69            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAllocatorClass;
70
71            if let Some(f) = (*parent_class).free {
72                f(
73                    self.obj().unsafe_cast_ref::<Allocator>().to_glib_none().0,
74                    memory.into_glib_ptr(),
75                )
76            }
77        }
78    }
79}
80
81impl<T: AllocatorImpl> AllocatorImplExt for T {}
82
83unsafe impl<T: AllocatorImpl> IsSubclassable<T> for Allocator {
84    fn class_init(klass: &mut glib::Class<Self>) {
85        Self::parent_class_init::<T>(klass);
86        let klass = klass.as_mut();
87        klass.alloc = Some(alloc::<T>);
88        klass.free = Some(free::<T>);
89    }
90}
91
92unsafe extern "C" fn alloc<T: AllocatorImpl>(
93    ptr: *mut ffi::GstAllocator,
94    size: usize,
95    params: *mut ffi::GstAllocationParams,
96) -> *mut ffi::GstMemory {
97    let instance = &*(ptr as *mut T::Instance);
98    let imp = instance.imp();
99    let instance = imp.obj();
100
101    let params = if params.is_null() {
102        None
103    } else {
104        Some(&*(params as *mut AllocationParams))
105    };
106
107    imp.alloc(size, params)
108        .map(|memory| memory.into_glib_ptr())
109        .unwrap_or_else(|error| {
110            error!(crate::CAT_RUST, obj = instance, "{:?}", error);
111
112            ptr::null_mut()
113        })
114}
115
116unsafe extern "C" fn free<T: AllocatorImpl>(
117    ptr: *mut ffi::GstAllocator,
118    memory: *mut ffi::GstMemory,
119) {
120    let instance = &*(ptr as *mut T::Instance);
121    let imp = instance.imp();
122    let memory = from_glib_full(memory);
123
124    imp.free(memory);
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    use crate::prelude::*;
131
132    pub mod imp {
133        use super::*;
134
135        #[derive(Default)]
136        pub struct TestAllocator;
137
138        impl ObjectImpl for TestAllocator {}
139        impl GstObjectImpl for TestAllocator {}
140        impl AllocatorImpl for TestAllocator {
141            fn alloc(
142                &self,
143                size: usize,
144                _params: Option<&AllocationParams>,
145            ) -> Result<Memory, BoolError> {
146                Ok(Memory::from_slice(vec![0; size]))
147            }
148
149            fn free(&self, memory: Memory) {
150                self.parent_free(memory)
151            }
152        }
153
154        #[glib::object_subclass]
155        impl ObjectSubclass for TestAllocator {
156            const NAME: &'static str = "TestAllocator";
157            type Type = super::TestAllocator;
158            type ParentType = Allocator;
159        }
160    }
161
162    glib::wrapper! {
163        pub struct TestAllocator(ObjectSubclass<imp::TestAllocator>) @extends Allocator, crate::Object;
164    }
165
166    impl Default for TestAllocator {
167        fn default() -> Self {
168            glib::Object::new()
169        }
170    }
171
172    #[test]
173    fn test_allocator_registration() {
174        crate::init().unwrap();
175
176        const TEST_ALLOCATOR_NAME: &str = "TestAllocator";
177
178        let allocator = TestAllocator::default();
179        Allocator::register(TEST_ALLOCATOR_NAME, allocator);
180
181        let allocator = Allocator::find(Some(TEST_ALLOCATOR_NAME));
182
183        assert!(allocator.is_some());
184    }
185
186    #[test]
187    fn test_allocator_alloc() {
188        crate::init().unwrap();
189
190        const SIZE: usize = 1024;
191
192        let allocator = TestAllocator::default();
193
194        let memory = allocator.alloc(SIZE, None).unwrap();
195
196        assert_eq!(memory.size(), SIZE);
197    }
198}