1#![cfg_attr(rustfmt, rustfmt::skip)]
2
3export_cfgs! {$
4 "headers" => __cfg_headers__!,
5 "headers" => __cfg_csharp__!,
6 "js" => __cfg_js__!,
7 "python-headers" => __cfg_python__!,
8}
9macro_rules! export_cfgs {(
13 $_:tt
14 $(
15 $feature:tt => $macro_name:ident !
16 ),* $(,)?
17) => (
18 $(
19 match_cfg! {
20 feature = $feature => {
21 #[doc(hidden)] #[macro_export]
22 macro_rules! $macro_name {(
23 $_($item:item)*
24 ) => (
25 $_($item)*
26 )}
27 },
28 _ => {
29 #[doc(hidden)] #[macro_export]
30 macro_rules! $macro_name {(
31 $_($item:item)*
32 ) => (
33 )}
35 },
36 }
37 #[allow(unused)]
38 pub(in crate) use $macro_name;
39 )*
40)} use export_cfgs;
41
42match_cfg! {
56 feature = "python-headers" => {
57 #[doc(hidden)] #[macro_export]
58 macro_rules! __with_cfg_python__ {(
59 |$_:tt $if_python:ident $(, $__:tt $dol:ident)?| $body:tt
60 ) => ({
61 macro_rules! __emit__ {
62 (
63 [$( $__ $dol : tt )? $_($__rest:tt)*]
64 $_(true $_($_ $if_python:tt)?)?
65 $_(false)?
66 ) => $body
67 }
68 __emit__! { [$] true }
69 })}
70 },
71 _ => {
72 #[doc(hidden)] #[macro_export]
73 macro_rules! __with_cfg_python__ {(
74 |$_:tt $if_python:ident $(, $__:tt $dol:ident)?| $body:tt
75 ) => ({
76 macro_rules! __emit__ {
77 (
78 [$( $__ $dol : tt )? $_($__rest:tt)*]
79 $_(true $_($_ $if_python:tt)?)?
80 $_(false)?
81 ) => $body
82 }
83 __emit__! { [$] false }
84 })}
85 },
86}
87
88#[macro_export]
96macro_rules! CType {(
97 $(
98 @doc_meta( $($doc_meta:tt)* )
99 )?
100 #[repr(C $(, js $(@$js:tt)?)? $(,)?)]
101 $(#[$($meta:tt)*])*
102 $pub:vis
103 struct $StructName:ident $(
104 [
105 $($lt:lifetime ,)*
106 $($($generics:ident $(= $Default:ty)?),+ $(,)?)?
107 ]
108 $(where { $($bounds:tt)* })?
109 )?
110 {
111 $(
112 $(#[$($field_meta:tt)*])*
113 $field_pub:vis
114 $field_name:ident : $field_ty:ty
115 ),+ $(,)?
116 }
117) => (
118 impl $(<$($lt ,)* $($($generics),+)?>)?
119 $crate::js::ReprNapi
120 for
121 $StructName $(<$($lt ,)* $($($generics),+)?>)?
122 where
123 Self : 'static,
124 $(
125 $field_ty : $crate::layout::ReprC,
126 <$field_ty as $crate::layout::ReprC>::CLayout : $crate::js::ReprNapi,
127 )*
128 $(
129 $($(
130 $generics : $crate::layout::ReprC,
131 <$generics as $crate::layout::ReprC>::CLayout : $crate::js::ReprNapi,
132 )+)?
133 $($($bounds)*)?
134 )?
135 {
136 type NapiValue = $crate::js::JsUnknown;
137
138 fn to_napi_value (
139 self: Self,
140 env: &'_ $crate::js::Env,
141 ) -> $crate::js::Result<$crate::js::JsUnknown>
142 {
143 let mut _obj = env.create_object()?;
144 $(
145 _obj.set_named_property(
146 $crate::ඞ::stringify!($field_name),
147 <
148 <$field_ty as $crate::layout::ReprC>::CLayout
149 as
150 $crate::js::ReprNapi
151 >::to_napi_value(
152 unsafe { $crate::layout::into_raw(self.$field_name) },
153 env,
154 )?,
155 )?;
156 )*
157 $crate::js::Result::Ok(_obj.into_unknown())
158 }
159
160 fn from_napi_value (
161 env: &'_ $crate::js::Env,
162 obj: $crate::js::JsUnknown,
163 ) -> $crate::js::Result<Self>
164 {
165 use $crate::ඞ::convert::TryFrom as _;
166 let mut is_buffer = false;
167 if $crate::ඞ::any::TypeId::of::<Self>()
169 ==
170 $crate::ඞ::any::TypeId::of::<$crate::slice::slice_ref_Layout<'_, u8>>()
171 && (
172 { is_buffer = obj.is_buffer()?; is_buffer }
173 ||
174 $crate::ඞ::matches!(
175 obj.get_type(),
176 $crate::js::Result::Ok($crate::js::ValueType::Null)
177 )
178 )
179 {
180 return if is_buffer {
181 let js_buffer = $crate::js::JsBuffer::try_from(obj)?;
182 let (buf, _storage): (&[u8], _);
183 #[cfg(target_arch = "wasm32")] {
184 _storage = ();
185 let bytes = js_buffer.into_value()?.into_boxed_slice();
186 let raw = $crate::ඞ::boxed::Box::into_raw(bytes);
187 env.__push_drop_glue($crate::ඞ::scopeguard::guard(raw, |raw| unsafe {
188 $crate::ඞ::mem::drop($crate::ඞ::boxed::Box::from_raw(raw))
189 }));
190 buf = unsafe { &*raw };
191 } #[cfg(not(target_arch = "wasm32"))] {
193 _storage = js_buffer.into_value()?;
194 buf = &_storage;
195 }
196 let xs = buf;
197 $crate::js::Result::Ok(unsafe { $crate::ඞ::mem::transmute_copy(&{
198 $crate::slice::slice_raw_Layout::<u8> {
199 ptr: xs.as_ptr() as _,
200 len: xs.len(),
201 }
202 })})
203 } else { $crate::js::Result::Ok(unsafe { $crate::ඞ::mem::transmute_copy::<_, Self>(&{
205 $crate::slice::slice_raw_Layout::<u8> {
206 ptr: $crate::NULL!(),
207 len: 0xbad000,
208 }
209 })})
210 };
211 }
212 let obj = $crate::js::JsObject::try_from(obj)?;
213 $crate::js::Result::Ok(Self {
214 $(
215 $field_name: unsafe { $crate::layout::from_raw_unchecked(
216 <
217 <$field_ty as $crate::layout::ReprC>::CLayout
218 as
219 $crate::js::ReprNapi
220 >::from_napi_value(
221 env,
222 obj.get_named_property($crate::ඞ::stringify!($field_name))?,
223 )?
224 )},
225 )*
226 })
227 }
228 }
229); (
230 @js_enum
231 $Enum_Layout:ident {
232 $(
233 $Variant:ident = $Discriminant:expr
234 ),* $(,)?
235 }
236) => (
237 #[allow(nonstandard_style)]
238 const _: () = {
239 impl $Enum_Layout {
240 $(
241 pub const $Variant: $Enum_Layout = $Discriminant;
242 )*
243 }
244
245 impl $crate::js::ReprNapi for $Enum_Layout {
246 type NapiValue = $crate::js::JsString;
247
248 fn to_napi_value (
249 self: Self,
250 env: &'_ $crate::js::Env,
251 ) -> $crate::js::Result< $crate::js::JsString >
252 {
253 env.create_string(match self {
254 $(
255 | $Enum_Layout::$Variant => $crate::ඞ::stringify!($Variant),
256 )*
257 | _ => $crate::ඞ::panic!(
258 "ill-formed enum variant ({:?}) for type `{}`",
259 &self.discriminant,
260 <$Enum_Layout as $crate::layout::CType>::short_name(),
261 ),
262 })
263 }
264
265 fn from_napi_value (
266 env: &'_ $crate::js::Env,
267 js_string: $crate::js::JsString,
268 ) -> $crate::js::Result<Self>
269 {
270 match js_string.into_utf8()?.as_str()? {
271 $(
272 | $crate::ඞ::stringify!($Variant) => $crate::js::Result::Ok($Enum_Layout::$Variant),
273 )*
274 | _ => $crate::js::Result::Err($crate::js::Error::new(
275 $crate::js::Status::InvalidArg,
277 $crate::ඞ::concat!(
279 "Expected one of: "
280 $(
281 , "`", $crate::ඞ::stringify!($Variant), "`",
282 )", "*
283 ).into(),
284 ).into()),
285 }
286 }
287 }
288 };
289)}
290
291#[macro_export]
294macro_rules! ReprC {(
295 $(
296 @[doc = $doc:expr]
297 )?
298 $(
299 #[doc = $doc2:expr]
300 )*
301 #[repr(
302 $C_or_transparent:ident $(,
303 $($(@$if_js:tt)?
304 js $(,)?
305 )?
306 )?
307 )]
308 $(
309 #[$attr:meta]
310 )*
311 $pub:vis
312 struct $StructName:ident $([$($generics:tt)*])?
313 $(
314 where { $($wc:tt)* }
315 )?
316 $({
317 $($body:tt)*
318 })?
319 $((
320 $($body2:tt)*
321 );)?
322) => (
323 #[$crate::prelude::derive_ReprC2($($($($if_js)? js)?)?)]
324 $(
325 #[doc = $doc]
326 )?
327 $(
328 #[doc = $doc2]
329 )*
330 #[cfg_attr(feature = "stabby", stabby::stabby)]
331 #[repr($C_or_transparent)]
332 $(
333 #[$attr]
334 )*
335 $pub
336 struct $StructName $(<$($generics)*>)?
337 $(
338 where $($wc)*
339 )?
340 $({
341 $($body)*
342 })?
343 $((
344 $($body2)*
345 );)?
346)}
347
348#[cfg(test)]
349#[crate::derive_ReprC]
350#[repr(u8)]
351#[derive(Debug)]
352pub
354enum MyBool {
355 False = 42,
357 True, }
359
360#[cfg(any(test, docs))]
361mod test {
362 use crate::layout::ReprC;
363
364 #[crate::derive_ReprC]
365 #[repr(u8)]
367 #[derive(Debug)]
368 pub
370 enum MyBool {
371 False = 42,
372 True, }
374
375 ReprC! {
376 #[repr(opaque)]
377 struct Opaque
378 {}
379 }
380
381 ReprC! {
382 #[repr(C)]
383 struct GenericStruct['lifetime, T]
384 where {
385 T : 'lifetime,
386 }
387 {
388 inner: &'lifetime T,
389 }
390 }
391
392 doc_test! { derive_ReprC_supports_generics:
393 fn main () {}
394
395 use ::safer_ffi::prelude::*;
396
397 #[derive_ReprC]
399 #[repr(u8)]
400 #[derive(Debug)]
401 pub
403 enum MyBool {
404 False = 42,
405 True, }
407
408 #[derive_ReprC]
409 #[repr(C)]
410 struct GenericStruct<'lifetime, T : 'lifetime>
411 where
412 T : ReprC,
413 {
414 inner: &'lifetime T,
415 }
416 }
417
418 mod opaque {
419 doc_test! { unused:
420 fn main () {}
421
422 use ::safer_ffi::prelude::*;
423
424 ReprC! {
425 #[repr(opaque)]
426 struct Foo {}
427 }
428 }
429
430 doc_test! { with_indirection:
431 fn main () {}
432
433 use ::safer_ffi::prelude::*;
434
435 ReprC! {
436 #[repr(opaque)]
437 pub
438 struct Foo {}
439 }
440
441 #[ffi_export]
442 fn foo (_it: &'_ Foo)
443 {}
444 }
445
446 doc_test! { without_indirection:
447 #![compile_fail]
448 fn main () {}
449
450 use ::safer_ffi::prelude::*;
451
452 ReprC! {
453 #[repr(opaque)]
454 pub
455 struct Foo {}
456 }
457
458 #[ffi_export]
459 fn foo (it: Foo)
460 {}
461 }
462 }
463}