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