gstreamer/subclass/
allocator.rs
1use 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> {
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}