facet_core/impls_core/
fn_ptr.rs

1use core::{alloc::Layout, fmt, hash::Hash, ptr::fn_addr_eq};
2
3use crate::{
4    ConstTypeId, Def, Facet, FunctionAbi, FunctionPointerDef, HasherProxy, MarkerTraits, Shape,
5    TypeNameOpts, TypeParam, ValueVTable,
6};
7
8#[inline(always)]
9pub fn write_type_name_list(
10    f: &mut fmt::Formatter<'_>,
11    opts: TypeNameOpts,
12    abi: FunctionAbi,
13    params: &'static [&'static Shape],
14    ret_type: &'static Shape,
15) -> fmt::Result {
16    if abi != FunctionAbi::Rust {
17        f.pad("extern \"")?;
18        if let Some(abi) = abi.as_abi_str() {
19            f.pad(abi)?;
20        }
21        f.pad("\" ")?;
22    }
23    f.pad("fn")?;
24    f.pad("(")?;
25    if let Some(opts) = opts.for_children() {
26        for (index, shape) in params.iter().enumerate() {
27            if index > 0 {
28                f.pad(", ")?;
29            }
30            shape.write_type_name(f, opts)?;
31        }
32    } else {
33        write!(f, "⋯")?;
34    }
35    f.pad(") -> ")?;
36    ret_type.write_type_name(f, opts)?;
37    Ok(())
38}
39
40macro_rules! impl_facet_for_fn_ptr {
41    // Used to implement the next bigger `fn` type, by taking the next typename out of `remaining`,
42    // if it exists.
43    {
44        continue from $(extern $extern:literal)? fn($($args:ident),*) -> R with $abi:expr,
45        remaining ()
46    } => {};
47    {
48        continue from $(extern $extern:literal)? fn($($args:ident),*) -> R with $abi:expr,
49        remaining ($next:ident $(, $remaining:ident)*)
50    } => {
51        impl_facet_for_fn_ptr! {
52            impl $(extern $extern)? fn($($args,)* $next) -> R with $abi,
53            remaining ($($remaining),*)
54        }
55    };
56    // Actually generate the trait implementation, and keep the remaining possible arguments around
57    {
58        impl $(extern $extern:literal)? fn($($args:ident),*) -> R with $abi:expr,
59        remaining ($($remaining:ident),*)
60    } => {
61        unsafe impl<'a, $($args,)* R> Facet<'a> for $(extern $extern)? fn($($args),*) -> R
62        where
63            $($args: Facet<'a>,)*
64            R: Facet<'a>,
65        {
66            const SHAPE: &'static Shape = &const {
67                Shape::builder()
68                    .id(ConstTypeId::of::<Self>())
69                    .layout(Layout::new::<Self>())
70                    .vtable(const {
71                        &ValueVTable::builder::<Self>()
72                            .type_name(|f, opts| {
73                                write_type_name_list(f, opts, $abi, &[$($args::SHAPE),*], R::SHAPE)
74                            })
75                            .debug(|data, f| fmt::Debug::fmt(data, f))
76                            .clone_into(|src, dst| unsafe { dst.put(src.clone()) })
77                            .marker_traits(
78                                MarkerTraits::EQ
79                                    .union(MarkerTraits::SEND)
80                                    .union(MarkerTraits::SYNC)
81                                    .union(MarkerTraits::COPY)
82                                    .union(MarkerTraits::UNPIN)
83                            )
84                            .eq(|&left, &right| {
85                                fn_addr_eq(left, right)
86                            })
87                            .partial_ord(|left, right| {
88                                #[allow(unpredictable_function_pointer_comparisons)]
89                                left.partial_cmp(right)
90                            })
91                            .ord(|left, right| {
92                                #[allow(unpredictable_function_pointer_comparisons)]
93                                left.cmp(right)
94                            })
95                            .hash(|value, hasher_this, hasher_write_fn| {
96                                value.hash(&mut unsafe {
97                                        HasherProxy::new(hasher_this, hasher_write_fn)
98                                    })
99                            })
100                            .build()
101                    })
102                    .type_params(&[
103                        $(TypeParam { name: stringify!($args), shape: || $args::SHAPE },)*
104                    ])
105                    .def(Def::FunctionPointer({
106                        FunctionPointerDef::builder()
107                            .parameter_types(&const { [$(|| $args::SHAPE),*] })
108                            .return_type(|| R::SHAPE)
109                            .abi($abi)
110                            .build()
111                    }))
112                    .build()
113            };
114        }
115        impl_facet_for_fn_ptr! {
116            continue from $(extern $extern)? fn($($args),*) -> R with $abi,
117            remaining ($($remaining),*)
118        }
119    };
120    // The entry point into this macro, all smaller `fn` types get implemented as well.
121    {$(extern $extern:literal)? fn($($args:ident),*) -> R with $abi:expr} => {
122        impl_facet_for_fn_ptr! {
123            impl $(extern $extern)? fn() -> R with $abi,
124            remaining ($($args),*)
125        }
126    };
127}
128
129impl_facet_for_fn_ptr! { fn(T0, T1, T2, T3, T4, T5) -> R with FunctionAbi::Rust }
130impl_facet_for_fn_ptr! { extern "C" fn(T0, T1, T2, T3, T4, T5) -> R with FunctionAbi::C }