1 // Take a look at the license at the top of the repository in the LICENSE file.
2
3 use proc_macro2::{Ident, TokenStream};
4 use proc_macro_error::abort_call_site;
5 use quote::quote;
6
7 use crate::utils::{crate_ident_new, find_attribute_meta, find_nested_meta, parse_type_name};
8
gen_option_to_ptr() -> TokenStream9 fn gen_option_to_ptr() -> TokenStream {
10 quote! {
11 match s {
12 Some(s) => Box::into_raw(Box::new(s.clone())),
13 None => std::ptr::null_mut(),
14 };
15 }
16 }
17
gen_impl_from_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenStream18 fn gen_impl_from_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenStream {
19 quote! {
20 unsafe impl<'a> #crate_ident::value::FromValue<'a> for #name {
21 type Checker = #crate_ident::value::GenericValueTypeOrNoneChecker<Self>;
22
23 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
24 let ptr = #crate_ident::gobject_ffi::g_value_dup_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
25 assert!(!ptr.is_null());
26 *Box::from_raw(ptr as *mut #name)
27 }
28 }
29
30 unsafe impl<'a> #crate_ident::value::FromValue<'a> for &'a #name {
31 type Checker = #crate_ident::value::GenericValueTypeOrNoneChecker<Self>;
32
33 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
34 let ptr = #crate_ident::gobject_ffi::g_value_get_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
35 assert!(!ptr.is_null());
36 &*(ptr as *mut #name)
37 }
38 }
39 }
40 }
41
gen_impl_from_value(name: &Ident, crate_ident: &TokenStream) -> TokenStream42 fn gen_impl_from_value(name: &Ident, crate_ident: &TokenStream) -> TokenStream {
43 quote! {
44 unsafe impl<'a> #crate_ident::value::FromValue<'a> for #name {
45 type Checker = #crate_ident::value::GenericValueTypeChecker<Self>;
46
47 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
48 let ptr = #crate_ident::gobject_ffi::g_value_dup_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
49 assert!(!ptr.is_null());
50 *Box::from_raw(ptr as *mut #name)
51 }
52 }
53
54 unsafe impl<'a> #crate_ident::value::FromValue<'a> for &'a #name {
55 type Checker = #crate_ident::value::GenericValueTypeChecker<Self>;
56
57 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
58 let ptr = #crate_ident::gobject_ffi::g_value_get_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
59 assert!(!ptr.is_null());
60 &*(ptr as *mut #name)
61 }
62 }
63 }
64 }
65
gen_impl_to_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenStream66 fn gen_impl_to_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenStream {
67 let option_to_ptr = gen_option_to_ptr();
68
69 quote! {
70 impl #crate_ident::value::ToValueOptional for #name {
71 fn to_value_optional(s: Option<&Self>) -> #crate_ident::Value {
72 let mut value = #crate_ident::Value::for_value_type::<Self>();
73 unsafe {
74 let ptr: *mut #name = #option_to_ptr;
75 #crate_ident::gobject_ffi::g_value_take_boxed(
76 #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0,
77 ptr as *mut _
78 );
79 }
80
81 value
82 }
83 }
84 }
85 }
86
impl_gboxed(input: &syn::DeriveInput) -> TokenStream87 pub fn impl_gboxed(input: &syn::DeriveInput) -> TokenStream {
88 let name = &input.ident;
89
90 let gtype_name = match parse_type_name(input, "gboxed") {
91 Ok(v) => v,
92 Err(e) => abort_call_site!(
93 "{}: derive(GBoxed) requires #[gboxed(type_name = \"BoxedTypeName\")]",
94 e
95 ),
96 };
97
98 let crate_ident = crate_ident_new();
99
100 let meta = find_attribute_meta(&input.attrs, "gboxed")
101 .unwrap()
102 .unwrap();
103 let nullable = find_nested_meta(&meta, "nullable").is_some();
104
105 let impl_from_value = if !nullable {
106 gen_impl_from_value(name, &crate_ident)
107 } else {
108 gen_impl_from_value_optional(name, &crate_ident)
109 };
110 let impl_to_value_optional = if nullable {
111 gen_impl_to_value_optional(name, &crate_ident)
112 } else {
113 quote! {}
114 };
115
116 quote! {
117 impl #crate_ident::subclass::boxed::BoxedType for #name {
118 const NAME: &'static str = #gtype_name;
119 }
120
121 impl #crate_ident::StaticType for #name {
122 fn static_type() -> #crate_ident::Type {
123 static ONCE: ::std::sync::Once = ::std::sync::Once::new();
124 static mut TYPE_: #crate_ident::Type = #crate_ident::Type::INVALID;
125
126 ONCE.call_once(|| {
127 let type_ = #crate_ident::subclass::register_boxed_type::<#name>();
128 unsafe {
129 TYPE_ = type_;
130 }
131 });
132
133 unsafe {
134 assert!(TYPE_.is_valid());
135 TYPE_
136 }
137 }
138 }
139
140 impl #crate_ident::value::ValueType for #name {
141 type Type = #name;
142 }
143
144 impl #crate_ident::value::ToValue for #name {
145 fn to_value(&self) -> #crate_ident::Value {
146 unsafe {
147 let ptr: *mut #name = Box::into_raw(Box::new(self.clone()));
148 let mut value = #crate_ident::Value::from_type(<#name as #crate_ident::StaticType>::static_type());
149 #crate_ident::gobject_ffi::g_value_take_boxed(
150 #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0,
151 ptr as *mut _
152 );
153 value
154 }
155 }
156
157 fn value_type(&self) -> #crate_ident::Type {
158 <#name as #crate_ident::StaticType>::static_type()
159 }
160 }
161
162 #impl_to_value_optional
163
164 #impl_from_value
165 }
166 }
167