facet_core/impls_core/
fn_ptr.rs1use 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 {
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 {
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 {$(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 }