glib_macros/
boxed_derive.rs
1use proc_macro2::{Ident, TokenStream};
4use quote::quote;
5
6use crate::utils::{crate_ident_new, parse_nested_meta_items, NestedMetaItem};
7
8fn gen_option_to_ptr() -> TokenStream {
9 quote! {
10 match s {
11 ::core::option::Option::Some(s) => ::std::boxed::Box::into_raw(::std::boxed::Box::new(s.clone())),
12 ::core::option::Option::None => ::std::ptr::null_mut(),
13 };
14 }
15}
16
17fn gen_impl_from_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenStream {
18 quote! {
19 unsafe impl<'a> #crate_ident::value::FromValue<'a> for #name {
20 type Checker = #crate_ident::value::GenericValueTypeOrNoneChecker<Self>;
21
22 #[inline]
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 debug_assert!(!ptr.is_null());
26 *::std::boxed::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 #[inline]
34 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
35 let ptr = #crate_ident::gobject_ffi::g_value_get_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
36 debug_assert!(!ptr.is_null());
37 &*(ptr as *mut #name)
38 }
39 }
40 }
41}
42
43fn gen_impl_from_value(name: &Ident, crate_ident: &TokenStream) -> TokenStream {
44 quote! {
45 unsafe impl<'a> #crate_ident::value::FromValue<'a> for #name {
46 type Checker = #crate_ident::value::GenericValueTypeChecker<Self>;
47
48 #[inline]
49 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
50 let ptr = #crate_ident::gobject_ffi::g_value_dup_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
51 debug_assert!(!ptr.is_null());
52 *::std::boxed::Box::from_raw(ptr as *mut #name)
53 }
54 }
55
56 unsafe impl<'a> #crate_ident::value::FromValue<'a> for &'a #name {
57 type Checker = #crate_ident::value::GenericValueTypeChecker<Self>;
58
59 #[inline]
60 unsafe fn from_value(value: &'a #crate_ident::Value) -> Self {
61 let ptr = #crate_ident::gobject_ffi::g_value_get_boxed(#crate_ident::translate::ToGlibPtr::to_glib_none(value).0);
62 debug_assert!(!ptr.is_null());
63 &*(ptr as *mut #name)
64 }
65 }
66 }
67}
68
69fn gen_impl_to_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenStream {
70 let option_to_ptr = gen_option_to_ptr();
71
72 quote! {
73 impl #crate_ident::value::ToValueOptional for #name {
74 #[inline]
75 fn to_value_optional(s: ::core::option::Option<&Self>) -> #crate_ident::Value {
76 let mut value = #crate_ident::Value::for_value_type::<Self>();
77 unsafe {
78 let ptr: *mut #name = #option_to_ptr;
79 #crate_ident::gobject_ffi::g_value_take_boxed(
80 #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0,
81 ptr as *mut _
82 );
83 }
84
85 value
86 }
87 }
88
89 impl #crate_ident::value::ValueTypeOptional for #name { }
90 }
91}
92
93pub fn impl_boxed(input: &syn::DeriveInput) -> syn::Result<TokenStream> {
94 let name = &input.ident;
95
96 let mut gtype_name = NestedMetaItem::<syn::LitStr>::new("name")
97 .required()
98 .value_required();
99 let mut nullable = NestedMetaItem::<syn::LitBool>::new("nullable").value_optional();
100 let mut allow_name_conflict =
101 NestedMetaItem::<syn::LitBool>::new("allow_name_conflict").value_optional();
102
103 let found = parse_nested_meta_items(
104 &input.attrs,
105 "boxed_type",
106 &mut [&mut gtype_name, &mut nullable, &mut allow_name_conflict],
107 )?;
108
109 if found.is_none() {
110 return Err(syn::Error::new_spanned(
111 input,
112 "#[derive(glib::Boxed)] requires #[boxed_type(name = \"BoxedTypeName\")]",
113 ));
114 }
115
116 let gtype_name = gtype_name.value.unwrap();
117 let nullable = nullable.found || nullable.value.map(|b| b.value()).unwrap_or(false);
118 let allow_name_conflict = allow_name_conflict.found
119 || allow_name_conflict
120 .value
121 .map(|b| b.value())
122 .unwrap_or(false);
123
124 let crate_ident = crate_ident_new();
125
126 let impl_from_value = if !nullable {
127 gen_impl_from_value(name, &crate_ident)
128 } else {
129 gen_impl_from_value_optional(name, &crate_ident)
130 };
131 let impl_to_value_optional = if nullable {
132 gen_impl_to_value_optional(name, &crate_ident)
133 } else {
134 quote! {}
135 };
136
137 Ok(quote! {
138 impl #crate_ident::subclass::boxed::BoxedType for #name {
139 const NAME: &'static ::core::primitive::str = #gtype_name;
140 const ALLOW_NAME_CONFLICT: bool = #allow_name_conflict;
141 }
142
143 impl #crate_ident::prelude::StaticType for #name {
144 #[inline]
145 fn static_type() -> #crate_ident::Type {
146 static TYPE: ::std::sync::OnceLock<#crate_ident::Type> = ::std::sync::OnceLock::new();
147 *TYPE.get_or_init(|| {
148 #crate_ident::subclass::register_boxed_type::<#name>()
149 })
150 }
151 }
152
153 impl #crate_ident::value::ValueType for #name {
154 type Type = #name;
155 }
156
157 impl #crate_ident::value::ToValue for #name {
158 #[inline]
159 fn to_value(&self) -> #crate_ident::Value {
160 unsafe {
161 let ptr: *mut #name = ::std::boxed::Box::into_raw(::std::boxed::Box::new(self.clone()));
162 let mut value = #crate_ident::Value::from_type_unchecked(<#name as #crate_ident::prelude::StaticType>::static_type());
163 #crate_ident::gobject_ffi::g_value_take_boxed(
164 #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0,
165 ptr as *mut _
166 );
167 value
168 }
169 }
170
171 #[inline]
172 fn value_type(&self) -> #crate_ident::Type {
173 <#name as #crate_ident::prelude::StaticType>::static_type()
174 }
175 }
176
177 impl ::std::convert::From<#name> for #crate_ident::Value {
178 #[inline]
179 fn from(v: #name) -> Self {
180 unsafe {
181 let mut value = #crate_ident::Value::from_type_unchecked(<#name as #crate_ident::prelude::StaticType>::static_type());
182 #crate_ident::gobject_ffi::g_value_take_boxed(
183 #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0,
184 #crate_ident::translate::IntoGlibPtr::<*mut #name>::into_glib_ptr(v) as *mut _,
185 );
186 value
187 }
188 }
189 }
190
191 #impl_to_value_optional
192
193 #impl_from_value
194
195 unsafe impl #crate_ident::translate::TransparentType for #name {
196 type GlibType = #name;
197 }
198
199 impl #crate_ident::translate::GlibPtrDefault for #name {
200 type GlibType = *mut #name;
201 }
202
203 impl #crate_ident::translate::FromGlibPtrBorrow<*const #name> for #name {
204 #[inline]
205 unsafe fn from_glib_borrow(ptr: *const #name) -> #crate_ident::translate::Borrowed<Self> {
206 #crate_ident::translate::FromGlibPtrBorrow::from_glib_borrow(ptr as *mut _)
207 }
208 }
209
210 impl #crate_ident::translate::FromGlibPtrBorrow<*mut #name> for #name {
211 #[inline]
212 unsafe fn from_glib_borrow(ptr: *mut #name) -> #crate_ident::translate::Borrowed<Self> {
213 debug_assert!(!ptr.is_null());
214
215 #crate_ident::translate::Borrowed::new(std::ptr::read(ptr))
216 }
217 }
218
219 impl #crate_ident::translate::FromGlibPtrNone<*const #name> for #name {
220 #[inline]
221 unsafe fn from_glib_none(ptr: *const #name) -> Self {
222 debug_assert!(!ptr.is_null());
223 (&*ptr).clone()
224 }
225 }
226
227 impl #crate_ident::translate::FromGlibPtrNone<*mut #name> for #name {
228 #[inline]
229 unsafe fn from_glib_none(ptr: *mut #name) -> Self {
230 #crate_ident::translate::FromGlibPtrNone::from_glib_none(ptr as *const _)
231 }
232 }
233
234 impl #crate_ident::translate::FromGlibPtrFull<*mut #name> for #name {
235 #[inline]
236 unsafe fn from_glib_full(ptr: *mut #name) -> Self {
237 debug_assert!(!ptr.is_null());
238 *::std::boxed::Box::from_raw(ptr)
239 }
240 }
241
242 impl #crate_ident::translate::IntoGlibPtr<*mut #name> for #name {
243 #[inline]
244 unsafe fn into_glib_ptr(self) -> *mut #name {
245 ::std::boxed::Box::into_raw(::std::boxed::Box::new(self)) as *mut _
246 }
247 }
248
249 impl<'a> #crate_ident::translate::ToGlibPtr<'a, *const #name> for #name {
250 type Storage = std::marker::PhantomData<&'a Self>;
251
252 #[inline]
253 fn to_glib_none(&'a self) -> #crate_ident::translate::Stash<'a, *const #name, Self> {
254 #crate_ident::translate::Stash(self as *const #name, std::marker::PhantomData)
255 }
256
257 #[inline]
258 fn to_glib_full(&self) -> *const #name {
259 ::std::boxed::Box::into_raw(::std::boxed::Box::new(self.clone()))
260 }
261 }
262
263 impl<'a> #crate_ident::translate::ToGlibPtr<'a, *mut #name> for #name {
264 type Storage = std::marker::PhantomData<&'a Self>;
265
266 #[inline]
267 fn to_glib_none(&'a self) -> #crate_ident::translate::Stash<'a, *mut #name, Self> {
268 #crate_ident::translate::Stash(self as *const #name as *mut _, std::marker::PhantomData)
269 }
270
271 #[inline]
272 fn to_glib_full(&self) -> *mut #name {
273 ::std::boxed::Box::into_raw(::std::boxed::Box::new(self.clone())) as *mut _
274 }
275 }
276
277 impl #crate_ident::prelude::HasParamSpec for #name {
278 type ParamSpec = #crate_ident::ParamSpecBoxed;
279 type SetValue = Self;
280 type BuilderFn = fn(&::core::primitive::str) -> #crate_ident::ParamSpecBoxedBuilder<Self>;
281
282 fn param_spec_builder() -> Self::BuilderFn {
283 |name| Self::ParamSpec::builder(name)
284 }
285 }
286 })
287}