1#[rustfmt::skip]
2pub use
3::safer_ffi::{
4 dyn_traits::DynDrop,
5 layout::ReprC,
6 prelude::{char_p, Out},
7}
8;
9
10#[diagnostic::on_unimplemented(
13 note = "\
14 This is a marker trait used to distinguish normal, well-defined, non-FFI-opaque types, from \
15 the latter, the `extern \"C\" {{ type`s.\n\nIf you are sure this is the case for this \
16 pointee type, then you can simply silence this error by manually writing the \
17 appropriate:\n\n impl NonOpaque for Foo {{}}\n",
18 label = "Missing `impl NonOpaque for … {{}}`"
19)]
20pub trait NonOpaque: Sized {}
21
22pub mod c_slice {
24 use super::*;
25
26 guarded_type_alias! {
27 pub
28 type Box<T> where { T : NonOpaque } = ::safer_ffi::prelude::c_slice::Box<T>;
29 }
30
31 guarded_type_alias! {
32 pub
33 type Ref<'lt, T> where { T : 'lt + NonOpaque } = ::safer_ffi::prelude::c_slice::Ref<'lt, T>;
34 }
35}
36
37impl NonOpaque for char_p::Box {}
38impl NonOpaque for char_p::Ref<'_> {}
39impl<T: NonOpaque> NonOpaque for ::safer_ffi::prelude::c_slice::Box<T> {}
40impl<T: NonOpaque> NonOpaque for ::safer_ffi::prelude::c_slice::Ref<'_, T> {}
41impl NonOpaque for i64 {}
42impl NonOpaque for u64 {}
43impl NonOpaque for usize {}
44impl NonOpaque for u8 {}
45impl NonOpaque for bool {}
46impl<T> NonOpaque for repr_c::Box<T> where T: FfiDropBox {}
48impl<T> NonOpaque for repr_c::Arc<T> where T: FfiDropArc {}
49
50pub trait HasNiche {}
53impl<T: HasNiche> NonOpaque for Option<T> {}
54
55impl HasNiche for char_p::Box {}
56impl HasNiche for char_p::Ref<'_> {}
57impl<T: NonOpaque> HasNiche for ::safer_ffi::prelude::c_slice::Box<T> {}
58impl<T: NonOpaque> HasNiche for ::safer_ffi::prelude::c_slice::Ref<'_, T> {}
59
60#[diagnostic::on_unimplemented(
61 message = "Pointee type may be opaque",
62 note = "\
63 If the pointee is some concrete type, rather than one defined by the FFI and opaque, then \
64 consider `impl`ementing `NonOpaque` for it.\n\nOtherwise, you will need to involve a \
65 companion `#[drop(…)] fn` declaration in the `unsafe extern \"C\" {{}}` block."
66)]
67pub trait FfiDropBox: Sized + ReprC {
68 unsafe fn drop_boxed(it: &mut repr_c::Box<Self>);
72}
73
74impl<T: NonOpaque + ReprC> FfiDropBox for T {
76 unsafe fn drop_boxed(it: &mut repr_c::Box<T>) {
77 unsafe {
78 drop(::std::boxed::Box::from_raw(it.0.ptr.as_mut_ptr()));
79 }
80 }
81}
82
83#[diagnostic::on_unimplemented(
84 message = "Pointee type may be opaque",
85 note = "\
86 If the pointee is some concrete type, rather than one defined by the FFI and opaque, then \
87 consider `impl`ementing `NonOpaque` for it.\n\nOtherwise, you will need to involve a \
88 companion `#[drop(…)] fn` declaration in the `unsafe extern \"C\" {{}}` block."
89)]
90pub trait FfiDropArc: Sized + ReprC {
91 unsafe fn drop_arced(it: &mut repr_c::Arc<Self>);
95}
96
97impl<T: NonOpaque + ReprC> FfiDropArc for T {
99 unsafe fn drop_arced(it: &mut repr_c::Arc<T>) {
100 unsafe {
101 drop(::std::sync::Arc::from_raw(it.0.ptr.as_mut_ptr()));
102 }
103 }
104}
105
106pub mod repr_c {
171 use ::safer_ffi::layout::ReprC;
172 pub use ::safer_ffi::prelude::repr_c::*;
173
174 use super::*;
175
176 guarded_type_alias! {
177 pub
179 type Vec<T> where { T : NonOpaque } = ::safer_ffi::prelude::repr_c::Vec<T>;
180 }
181
182 #[::safer_ffi::derive_ReprC]
185 #[repr(transparent)]
186 pub struct ThinBox<T>
187 where
188 T: FfiDropBox,
189 {
190 pub(super) ptr: ::safer_ffi::ptr::NonNullOwned<T>,
191 }
192
193 impl<T> Drop for ThinBox<T>
194 where
195 T: FfiDropBox,
196 {
197 fn drop(&mut self) {
198 unsafe {
199 T::drop_boxed(::core::mem::transmute(self));
200 }
201 }
202 }
203
204 unsafe impl<T> Send for ThinBox<T>
205 where
206 T: FfiDropBox,
207 ::std::boxed::Box<T>: Send,
208 {
209 }
210
211 unsafe impl<T> Sync for ThinBox<T>
212 where
213 T: FfiDropBox,
214 ::std::boxed::Box<T>: Sync,
215 {
216 }
217
218 pub use self::Box as Box_;
220
221 #[::safer_ffi::derive_ReprC]
234 #[repr(transparent)]
235 pub struct Box<T: ?Sized + PointeeFitForCBox>(pub(super) <T as PointeeFitForCBox>::CBoxed);
236
237 #[diagnostic::on_unimplemented(
238 message = "`repr_c::Box<dyn …>` requires `FnMut` rather than `Fn`, alongside `Send` only \
239 (no `Sync`)",
240 label = "double-check that this be using `FnMut` rather than `Fn`, alongside `Send` only \
241 (no `Sync`)"
242 )]
243 pub trait PointeeFitForCBox<Diagnostics = ()> {
245 type CBoxed: ReprC;
246 }
247
248 impl<T: Sized + NonOpaque + ReprC> PointeeFitForCBox for [T] {
250 type CBoxed = c_slice::Box<T>;
252 }
253
254 impl<T: Sized + FfiDropBox> PointeeFitForCBox for T {
256 type CBoxed = ThinBox<T>;
257 }
258
259 closure_impls! {
260 dyn Send + FnMut() -> R,
261 dyn Send + FnMut(A) -> R,
262 dyn Send + FnMut(A, B) -> R,
263 dyn Send + FnMut(A, B, C) -> R,
264 dyn Send + FnMut(A, B, C, D) -> R,
265 }
266 #[rustfmt::skip]
268 macro_rules! closure_impls {(
269 $(
270 dyn Send + FnMut($($Arg:ident),*) -> $R:ident,
271 )*
272 ) => (
273 $(
274 impl<
275 $R : ReprC $(, $Arg : ReprC)*
276 >
277 PointeeFitForCBox
278 for
279 dyn 'static + Send + FnMut($($Arg),*) -> $R
280 {
281 type CBoxed = ::safer_ffi::prelude::repr_c::Box<
282 dyn 'static + Send + FnMut($($Arg),*) -> $R,
283 >;
284 }
285
286 impl<
287 T,
288 $R : ReprC $(, $Arg : ReprC)*
289 >
290 From<::std::boxed::Box<T>>
291 for
292 Box<dyn 'static + Send + FnMut($($Arg),*) -> $R>
293 where
294 T : 'static + Send + FnMut($($Arg),*) -> $R,
295 {
296 fn from(f: ::std::boxed::Box<T>) -> Self {
297 Self(f.into())
298 }
299 }
300
301 impl<$R : ReprC $(, $Arg : ReprC)*>
302 Box<dyn 'static + Send + FnMut($($Arg),*) -> $R>
303 {
304 #[allow(nonstandard_style)]
305 pub fn call(&mut self $(, $Arg: $Arg)*) -> $R {
306 self.0.call($($Arg),*)
307 }
308 }
309
310 repr_c_ptr_dyn_diagnostics::improve_lack_of_PointeeFitForCBox_impl_diagnostics! {
311 dyn Send? + Sync? + Fn?($($Arg),*) -> $R,
312 }
313 )*
314 )}
315 use closure_impls;
316
317 impl<T> ::core::ops::Deref for Box<T>
318 where
319 T: FfiDropBox,
320 {
321 type Target = T;
322
323 fn deref(self: &'_ Self) -> &'_ T {
324 unsafe { self.0.ptr.as_ref() }
325 }
326 }
327
328 impl<T> ::core::ops::DerefMut for Box<T>
329 where
330 T: FfiDropBox,
331 {
332 fn deref_mut(self: &'_ mut Self) -> &'_ mut T {
333 unsafe { self.0.ptr.as_mut() }
334 }
335 }
336
337 impl<T> ::core::ops::Deref for Box<[T]>
338 where
339 T: NonOpaque + ReprC,
340 {
341 type Target = [T];
342
343 fn deref(self: &'_ Self) -> &'_ [T] {
344 &self.0[..]
345 }
346 }
347
348 impl<T> ::core::ops::DerefMut for Box<[T]>
349 where
350 T: NonOpaque + ReprC,
351 {
352 fn deref_mut(self: &'_ mut Self) -> &'_ mut [T] {
353 &mut self.0[..]
354 }
355 }
356
357 impl<T: ::std::fmt::Debug> ::std::fmt::Debug for Box<T>
358 where
359 T: FfiDropBox,
360 {
361 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
362 T::fmt(self, f)
363 }
364 }
365
366 #[::safer_ffi::derive_ReprC]
371 #[repr(transparent)]
372 pub struct ThinArc<T>
373 where
374 T: FfiDropArc,
375 {
376 pub(super) ptr: ::safer_ffi::ptr::NonNullOwned<T>,
377 }
378
379 impl<T> Drop for ThinArc<T>
380 where
381 T: FfiDropArc,
382 {
383 fn drop(&mut self) {
384 unsafe {
385 T::drop_arced(::core::mem::transmute(self));
386 }
387 }
388 }
389
390 impl<T> Clone for ThinArc<T>
391 where
392 T: FfiDropArc,
393 {
394 fn clone(&self) -> Self {
395 unsafe {
396 ::std::sync::Arc::increment_strong_count(self.ptr.as_ptr());
397 }
398 Self {
399 ptr: ::safer_ffi::ptr::NonNullOwned::from(self.ptr.0),
400 }
401 }
402 }
403
404 unsafe impl<T> Send for ThinArc<T>
405 where
406 T: FfiDropArc,
407 ::std::sync::Arc<T>: Send,
408 {
409 }
410
411 unsafe impl<T> Sync for ThinArc<T>
412 where
413 T: FfiDropArc,
414 ::std::sync::Arc<T>: Sync,
415 {
416 }
417
418 pub use self::Arc as Arc_;
420
421 #[::safer_ffi::derive_ReprC]
432 #[repr(transparent)]
433 pub struct Arc<T: ?Sized + PointeeFitForCArc>(pub(super) <T as PointeeFitForCArc>::CArced);
434
435 #[diagnostic::on_unimplemented(
436 message = "`repr_c::Arc<dyn …>` requires `Fn` rather than `FnMut`, alongside `Send + Sync`",
437 label = "double-check that this be using `Fn` rather than `FnMut`, alongside `Send + Sync`"
438 )]
439 pub trait PointeeFitForCArc<Diagnostics = ()> {
441 type CArced: ReprC;
442 }
443
444 impl<T: Sized + FfiDropArc> PointeeFitForCArc for T {
446 type CArced = ThinArc<T>;
447 }
448
449 arc_closure_impls! {
450 dyn Send + Sync + Fn() -> R,
451 dyn Send + Sync + Fn(A) -> R,
452 dyn Send + Sync + Fn(A, B) -> R,
453 dyn Send + Sync + Fn(A, B, C) -> R,
454 dyn Send + Sync + Fn(A, B, C, D) -> R,
455 }
456 #[rustfmt::skip]
458 macro_rules! arc_closure_impls {(
459 $(
460 dyn Send + Sync + Fn($($Arg:ident),*) -> $R:ident,
461 )*
462 ) => (
463 $(
464 impl<
465 $R : ReprC $(, $Arg : ReprC)*
466 >
467 PointeeFitForCArc
468 for
469 dyn 'static + Send + Sync + Fn($($Arg),*) -> $R
470 {
471 type CArced = ::safer_ffi::prelude::repr_c::Arc<
472 dyn 'static + Send + Sync + Fn($($Arg),*) -> $R,
473 >;
474 }
475
476 impl<
477 T,
478 $R : ReprC $(, $Arg : ReprC)*
479 >
480 From<::std::sync::Arc<T>>
481 for
482 Arc<dyn 'static + Send + Sync + Fn($($Arg),*) -> $R>
483 where
484 T : 'static + Send + Sync + Fn($($Arg),*) -> $R,
485 {
486 fn from(f: ::std::sync::Arc<T>) -> Self {
487 Self(f.into())
488 }
489 }
490
491 impl<$R : ReprC $(, $Arg : ReprC)*>
492 Arc<dyn 'static + Send + Sync + Fn($($Arg),*) -> $R>
493 {
494 #[allow(nonstandard_style)]
495 pub fn call(&self $(, $Arg: $Arg)*) -> $R {
496 self.0.call($($Arg),*)
497 }
498 }
499
500 repr_c_ptr_dyn_diagnostics::improve_lack_of_PointeeFitForCArc_impl_diagnostics! {
501 dyn Send? + Sync? + FnMut?($($Arg),*) -> $R,
502 }
503 )*
504 )}
505 use arc_closure_impls;
506
507 mod repr_c_ptr_dyn_diagnostics {
510 include!("repr_c_ptr_dyn_diagnostics.rs");
511 }
512
513 impl<T> ::core::ops::Deref for Arc<T>
514 where
515 T: FfiDropArc,
516 {
517 type Target = T;
518
519 fn deref(self: &'_ Self) -> &'_ T {
520 unsafe { self.0.ptr.as_ref() }
521 }
522 }
523
524 impl<T> ::core::ops::DerefMut for Arc<T>
525 where
526 T: FfiDropArc,
527 {
528 fn deref_mut(self: &'_ mut Self) -> &'_ mut T {
529 unsafe { self.0.ptr.as_mut() }
530 }
531 }
532
533 impl<T: ::std::fmt::Debug> ::std::fmt::Debug for Arc<T>
534 where
535 T: FfiDropArc,
536 {
537 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
538 T::fmt(self, f)
539 }
540 }
541
542 impl<T> Clone for repr_c::Arc<T>
543 where
544 T: FfiDropArc,
545 {
546 fn clone(&self) -> Self {
547 Self { 0: self.0.clone() }
548 }
549 }
550
551 pub use result::*;
552 mod result {
553 include!(concat!(env!("CARGO_MANIFEST_DIR"), "/", "result.rs"));
554 }
555}
556
557#[cfg_attr(all(rustfmt), rustfmt::skip)]
558macro_rules! extern_type_polyfill {
559 (
560 $( #[$attrs:meta] )*
561 unsafe extern $($abi:literal)? {
562 $($contents:tt)*
563 }
564 ) => (
565 $crate::ffi_utils::extern_type_polyfill! {
566 @internal
567 [$($attrs)*]
568 [$($abi)?]
569 $($contents)*
570 }
571 );
572
573 (
575 @internal $attrs:tt $abi:tt
576
577 $( #[$ty_attrs:meta] )*
578 $pub:vis type $TypeName:ident
579 $(:
580 $SendOrSync:ident
581 $(+ $SendOrSync2:ident)*
582 $(+)?
583 )?
584 ;
585
586 $($rest:tt)*
587 ) => (
588 $( #[$ty_attrs] )*
589 #[::safer_ffi::derive_ReprC]
590 #[repr(opaque)]
591 $pub
592 struct $TypeName {
593 _private: [u8; 0],
594 __not_send_nor_sync: ::core::marker::PhantomData<*const ()>,
595 }
596
597 ::paste::paste! {
598 $pub type [<Boxed $TypeName>] =
599 $crate::ffi_utils::repr_c::Box<$TypeName>
600 ;
601 }
602
603 $(
604 unsafe impl $SendOrSync for $TypeName {}
605 $(
606 unsafe impl $SendOrSync2 for $TypeName {}
607 )*
608 )?
609
610 impl $crate::ffi_utils::NonOpaque for $TypeName
613 where
614 for<'_never_true> $TypeName : $crate::ffi_utils::diagnostic_hack::ExternDropFnAnnotation
627 ,
628 {}
629
630 $crate::ffi_utils::extern_type_polyfill! {
631 @internal $attrs $abi
632 $($rest)*
633 }
634 );
635
636 (
638 @internal $attrs:tt $abi:tt
639
640 #[drop(to impl FfiDropBox for $T:ty)]
641 $pub:vis fn $fname:ident (
642 $arg_name:tt : $BoxedTy:ty $(,)?
643 );
644
645 $($rest:tt)*
646 ) => (
647 $crate::ffi_utils::extern_type_polyfill! {
648 @internal $attrs $abi
649
650 $pub fn $fname (
652 $arg_name : $BoxedTy,
653 );
654
655 $($rest)*
656 }
657
658 impl $crate::ffi_utils::FfiDropBox for $T {
659 unsafe
660 fn drop_boxed (it: &'_ mut $BoxedTy)
661 {
662 unsafe {
663 $fname(<*const $BoxedTy>::read(it))
664 }
665 }
666 }
667 );
668
669 (
671 @internal $attrs:tt $abi:tt
672
673 #[drop(to impl FfiDropArc for $T:ty)]
674 $pub:vis fn $fname:ident (
675 $arg_name:tt : $ArcedTy:ty $(,)?
676 );
677
678 $($rest:tt)*
679 ) => (
680 $crate::ffi_utils::extern_type_polyfill! {
681 @internal $attrs $abi
682
683 $pub fn $fname (
685 $arg_name : $ArcedTy,
686 );
687
688 $($rest)*
689 }
690
691 impl $crate::ffi_utils::FfiDropArc for $T {
692 unsafe
693 fn drop_arced (it: &'_ mut $ArcedTy)
694 {
695 unsafe {
696 $fname(<*const $ArcedTy>::read(it))
697 }
698 }
699 }
700 );
701
702 (
704 @internal [$($attrs:tt)*] [$($abi:literal)?]
705
706 $(#[$fn_attrs:meta])*
707 $pub:vis
708 $(unsafe $(@$if_unsafe:tt)?)?
709 fn $fname:ident $(< $($a:lifetime $(: $b:lifetime)?),* >)? (
710 $($arg_name:ident : $ArgTy:ty),* $(,)?
711 ) $(-> $Ret:ty)?;
712
713 $($rest:tt)*
714 ) => (
715 $(#[$fn_attrs])*
716 #[inline]
717 $pub
718 $($($if_unsafe)?
719 unsafe
720 )?
721 fn $fname $(< $($a $(: $b)?),* >)? (
722 $($arg_name : $ArgTy),*
723 ) $(-> $Ret)?
724 {
725 $( #[$attrs] )*
726 #[allow(improper_ctypes)]
727 extern $($abi)? {
728 $(#[$fn_attrs])*
729 $pub
730 fn $fname $(< $($a $(: $b)?),* >)? (
731 $($arg_name : $ArgTy),*
732 ) $(-> $Ret)?
733 ;
734 }
735 unsafe {
736 $fname($($arg_name),*)
737 }
738 }
739
740 $crate::ffi_utils::extern_type_polyfill! {
741 @internal [$($attrs)*] [$($abi)?]
742 $($rest)*
743 }
744 );
745
746 (
747 @internal $attrs:tt $abi:tt
748 ) => (
750 );
752}
753pub(crate) use extern_type_polyfill;
754
755#[cfg_attr(all(rustfmt), rustfmt::skip)]
756macro_rules! guarded_type_alias {
757 (
758 $( #[doc = $doc:tt] )*
759 $pub:vis
760 type $TypeName:ident [$($generics:tt)*]
761 where {
762 $($where_clauses:tt)*
763 } = $T:ty;
764 ) => (::paste::paste! {
765 #[cfg(not(doc))]
766 #[allow(nonstandard_style)]
767 $pub
768 trait [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
769 where
770 $($where_clauses)*
771 {
772 type T : ?Sized;
773 }
774
775 #[cfg(not(doc))]
776 impl<$($generics)*>
777 [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
778 for
779 ()
780 where
781 $($where_clauses)*
782 {
783 type T = $T;
784 }
785
786 #[cfg(not(doc))]
787 $pub type $TypeName<$($generics)*> =
788 <
789 ()
790 as
791 [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
792 >::T
793 ;
794
795 $( #[doc = $doc] )*
796 #[cfg(doc)]
797 $pub type $TypeName<$($generics)*> where $($where_clauses)* = $T;
798
799 });
800
801 (
802 $( #[doc = $doc:expr] )*
803 $pub:vis type $TypeName:ident
804 <
805 $($lt:lifetime),*
806 $(,)?
807 $($T:ident),*
808 > $($rest:tt)*
809 ) => (
810 $crate::ffi_utils::guarded_type_alias! {
811 $(#[doc = $doc])*
812 $pub type $TypeName [$($lt ,)* $($T),*] $($rest)*
813 }
814 );
815}
816pub(crate) use guarded_type_alias;
817
818#[cfg_attr(all(rustfmt), rustfmt::skip)]
825macro_rules! non_exhaustive_ffi_enum {(
826 #[repr($int:tt)]
827 $( #$attr:tt )*
828 $pub:vis
829 enum $EnumName:ident {
830 $(
831 $( #[doc $($doc:tt)*] )*
832 $Variant:ident $(= $value:expr)?
833 ),* $(,)?
834 }
835) => (
836 #[repr(transparent)]
837 $( #$attr )*
838 $pub
839 struct $EnumName {
840 discriminant: $int,
841 }
842
843 #[allow(warnings, clippy::all)]
844 const _: () = {
845 #[derive(Debug)]
846 #[repr($int)]
847 enum Discriminants {
848 $(
849 $Variant $(= $value)?
850 ),*
851 }
852
853 impl $EnumName {
854 $(
855 $( #[doc $($doc)*] )*
856 $pub const $Variant: Self = Self {
857 discriminant: Discriminants::$Variant as _,
858 };
859 )*
860 }
861
862 impl ::core::fmt::Debug for $EnumName {
863 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
864 -> ::core::fmt::Result
865 {
866 match *self {
867 $(
868 | Self::$Variant => Discriminants::$Variant.fmt(f),
869 )*
870 | Self { discriminant: unknown_discriminant } => {
871 #[::core::prelude::v1::derive(::core::fmt::Debug)]
872 struct $EnumName {
873 unknown_discriminant: $int,
874 }
875
876 $EnumName { unknown_discriminant }.fmt(f)
877 }
878 }
879 }
880 }
881 };
882)}
883pub(crate) use non_exhaustive_ffi_enum;
884
885pub mod diagnostic_hack {
886 mod seal {
887 pub trait NeverImplemented {}
888 }
889
890 #[rustfmt::skip]
891 #[diagnostic::on_unimplemented(
892 message = "\
893 The pointee type is missing its companion `#[drop(…)] fn …;` declaration.",
894 note = "\
895`extern type`s have no known size or statically-dispatchable `drop_in_place()` logic, \
896which is otherwise ordinarily the case, and the reason `drop::<Box<T>>()` is \
897well-defined.
898
899Since it is not the case here, we need to manually tell Rust how \"an owned pointed to \
900a `T`\" (a `c::Box<T>`) is to be dropped.
901
902This is done through the `FfiDropBox` trait, which is automagically defined and \
903implemented for `extern type`s which have the following kind of companion annotation:
904
905 #[apply(extern_type_polyfill!)]
906 extern \"C\" {{
907 …
908
909 type Foo : …;
910
911 #[drop(to impl FfiDropBox for Foo)]
912 fn dittoffi_current_type_free(_: c::Box<Foo>);
913
914 …
915 }}
916\
917 ",
918 )]
919 pub trait ExternDropFnAnnotation: Sized + seal::NeverImplemented {}
920}