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