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::{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>(class:klass);
68 let klass: &mut GstAllocatorClass = 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: &::Instance = &*(ptr as *mut T::Instance);
80 let imp: &T = instance.imp();
81 let instance: BorrowedObject<'_, ::Type> = imp.obj();
82
83 let params: Option<&AllocationParams> = 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: BoolError| {
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: &::Instance = &*(ptr as *mut T::Instance);
103 let imp: &T = instance.imp();
104 let memory: Memory = from_glib_full(ptr: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}
181