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