glib/subclass/
shared.rs
1use crate::{ffi, gobject_ffi, prelude::*, translate::*};
7
8pub unsafe trait RefCounted: Clone + Sized + 'static {
9 type InnerType;
12
13 unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType;
16
17 fn as_ptr(&self) -> *const Self::InnerType;
20
21 unsafe fn into_raw(self) -> *const Self::InnerType;
24
25 unsafe fn from_raw(this: *const Self::InnerType) -> Self;
28}
29
30unsafe impl<T> RefCounted for std::sync::Arc<T>
31where
32 T: 'static,
33{
34 type InnerType = T;
35
36 #[inline]
37 unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType {
38 std::sync::Arc::increment_strong_count(this);
39 this
40 }
41
42 #[inline]
43 fn as_ptr(&self) -> *const Self::InnerType {
44 std::sync::Arc::as_ptr(self)
45 }
46
47 #[inline]
48 unsafe fn into_raw(self) -> *const Self::InnerType {
49 std::sync::Arc::into_raw(self)
50 }
51
52 #[inline]
53 unsafe fn from_raw(this: *const Self::InnerType) -> Self {
54 std::sync::Arc::from_raw(this)
55 }
56}
57
58unsafe impl<T> RefCounted for std::rc::Rc<T>
59where
60 T: 'static,
61{
62 type InnerType = T;
63
64 #[inline]
65 unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType {
66 use std::mem::ManuallyDrop;
67 let this_rc = ManuallyDrop::new(std::rc::Rc::from_raw(this));
68 std::rc::Rc::into_raw(ManuallyDrop::take(&mut this_rc.clone()))
69 }
70
71 #[inline]
72 fn as_ptr(&self) -> *const Self::InnerType {
73 std::rc::Rc::as_ptr(self)
74 }
75
76 #[inline]
77 unsafe fn into_raw(self) -> *const Self::InnerType {
78 std::rc::Rc::into_raw(self)
79 }
80
81 #[inline]
82 unsafe fn from_raw(this: *const Self::InnerType) -> Self {
83 std::rc::Rc::from_raw(this)
84 }
85}
86
87pub trait SharedType: StaticType + Clone + Sized + 'static {
97 const NAME: &'static str;
102
103 const ALLOW_NAME_CONFLICT: bool = false;
117
118 type RefCountedType: RefCounted;
121
122 fn into_refcounted(self) -> Self::RefCountedType;
125
126 fn from_refcounted(this: Self::RefCountedType) -> Self;
129}
130
131pub fn register_shared_type<T: SharedType>() -> crate::Type {
141 unsafe {
142 use std::ffi::CString;
143 unsafe extern "C" fn shared_ref<T: SharedType>(v: ffi::gpointer) -> ffi::gpointer {
144 T::RefCountedType::ref_(v as *const <T::RefCountedType as RefCounted>::InnerType)
145 as ffi::gpointer
146 }
147 unsafe extern "C" fn shared_unref<T: SharedType>(v: ffi::gpointer) {
148 let _ = T::RefCountedType::from_raw(
149 v as *const <T::RefCountedType as RefCounted>::InnerType,
150 );
151 }
152
153 let type_name = if T::ALLOW_NAME_CONFLICT {
154 let mut i = 0;
155 loop {
156 let type_name = CString::new(if i == 0 {
157 T::NAME.to_string()
158 } else {
159 format!("{}-{}", T::NAME, i)
160 })
161 .unwrap();
162 if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID
163 {
164 break type_name;
165 }
166 i += 1;
167 }
168 } else {
169 let type_name = CString::new(T::NAME).unwrap();
170 assert_eq!(
171 gobject_ffi::g_type_from_name(type_name.as_ptr()),
172 gobject_ffi::G_TYPE_INVALID,
173 "Type {} has already been registered",
174 type_name.to_str().unwrap()
175 );
176
177 type_name
178 };
179
180 let type_ = crate::Type::from_glib(gobject_ffi::g_boxed_type_register_static(
181 type_name.as_ptr(),
182 Some(shared_ref::<T>),
183 Some(shared_unref::<T>),
184 ));
185 assert!(type_.is_valid());
186
187 type_
188 }
189}
190
191#[cfg(test)]
192mod test {
193 use super::*;
194 use crate as glib;
198
199 #[derive(Clone, Debug, PartialEq, Eq)]
200 struct MySharedInner {
201 foo: String,
202 }
203
204 #[derive(Clone, Debug, PartialEq, Eq, glib::SharedBoxed)]
205 #[shared_boxed_type(name = "MySharedArc")]
206 struct MySharedArc(std::sync::Arc<MySharedInner>);
207
208 #[derive(Clone, Debug, PartialEq, Eq, glib::SharedBoxed)]
209 #[shared_boxed_type(name = "MySharedRc")]
210 struct MySharedRc(std::rc::Rc<MySharedInner>);
211
212 #[test]
213 fn test_register() {
214 assert_ne!(crate::Type::INVALID, MySharedArc::static_type());
215 assert_ne!(crate::Type::INVALID, MySharedRc::static_type());
216 }
217
218 #[test]
219 fn test_value_arc() {
220 assert_ne!(crate::Type::INVALID, MySharedArc::static_type());
221
222 let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner {
223 foo: String::from("abc"),
224 }));
225 let v = b.to_value();
226 let b2 = v.get::<MySharedArc>().unwrap();
227 assert!(std::sync::Arc::ptr_eq(&b.0, &b2.0));
228 }
229
230 #[test]
231 fn test_value_rc() {
232 assert_ne!(crate::Type::INVALID, MySharedRc::static_type());
233
234 let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner {
235 foo: String::from("abc"),
236 }));
237 let v = b.to_value();
238 let b2 = v.get::<MySharedRc>().unwrap();
239 assert!(std::rc::Rc::ptr_eq(&b.0, &b2.0));
240 }
241
242 #[test]
243 fn same_ffi_pointer_arc() {
244 assert_ne!(crate::Type::INVALID, MySharedArc::static_type());
245
246 let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner {
247 foo: String::from("abc"),
248 }));
249
250 let inner_raw_ptr = std::sync::Arc::into_raw(b.clone().0);
251
252 assert_eq!(std::sync::Arc::strong_count(&b.0), 2);
253
254 let inner_raw_ptr_clone =
255 unsafe { <MySharedArc as SharedType>::RefCountedType::ref_(inner_raw_ptr) };
256
257 assert_eq!(std::sync::Arc::strong_count(&b.0), 3);
258 assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone));
259
260 let _ = unsafe { <MySharedArc as SharedType>::RefCountedType::from_raw(inner_raw_ptr) };
261 let _ =
262 unsafe { <MySharedArc as SharedType>::RefCountedType::from_raw(inner_raw_ptr_clone) };
263 assert_eq!(std::sync::Arc::strong_count(&b.0), 1);
264 }
265
266 #[test]
267 fn same_ffi_pointer_rc() {
268 assert_ne!(crate::Type::INVALID, MySharedRc::static_type());
269
270 let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner {
271 foo: String::from("abc"),
272 }));
273
274 let inner_raw_ptr = std::rc::Rc::into_raw(b.clone().0);
275
276 assert_eq!(std::rc::Rc::strong_count(&b.0), 2);
277
278 let inner_raw_ptr_clone =
279 unsafe { <MySharedRc as SharedType>::RefCountedType::ref_(inner_raw_ptr) };
280
281 assert_eq!(std::rc::Rc::strong_count(&b.0), 3);
282 assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone));
283
284 let _ = unsafe { <MySharedRc as SharedType>::RefCountedType::from_raw(inner_raw_ptr) };
285 let _ =
286 unsafe { <MySharedRc as SharedType>::RefCountedType::from_raw(inner_raw_ptr_clone) };
287 assert_eq!(std::rc::Rc::strong_count(&b.0), 1);
288 }
289
290 #[test]
291 fn from_glib_borrow_arc() {
292 assert_ne!(crate::Type::INVALID, MySharedRc::static_type());
293
294 let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner {
295 foo: String::from("abc"),
296 }));
297
298 let inner_raw_ptr = std::sync::Arc::into_raw(b.clone().0);
299
300 assert_eq!(std::sync::Arc::strong_count(&b.0), 2);
301
302 unsafe {
303 let _ = MySharedArc::from_glib_borrow(inner_raw_ptr);
304 assert_eq!(std::sync::Arc::strong_count(&b.0), 2);
305 }
306
307 assert_eq!(std::sync::Arc::strong_count(&b.0), 2);
308 unsafe {
309 let _ = std::sync::Arc::from_raw(inner_raw_ptr);
310 }
311 assert_eq!(std::sync::Arc::strong_count(&b.0), 1);
312 }
313
314 #[test]
315 fn from_glib_borrow_rc() {
316 assert_ne!(crate::Type::INVALID, MySharedRc::static_type());
317
318 let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner {
319 foo: String::from("abc"),
320 }));
321
322 let inner_raw_ptr = std::rc::Rc::into_raw(b.clone().0);
323
324 assert_eq!(std::rc::Rc::strong_count(&b.0), 2);
325
326 unsafe {
327 let _ = MySharedRc::from_glib_borrow(inner_raw_ptr);
328 assert_eq!(std::rc::Rc::strong_count(&b.0), 2);
329 }
330
331 assert_eq!(std::rc::Rc::strong_count(&b.0), 2);
332 unsafe {
333 let _ = std::rc::Rc::from_raw(inner_raw_ptr);
334 }
335 assert_eq!(std::rc::Rc::strong_count(&b.0), 1);
336 }
337}