safer_ffi/headers/
definer.rs

1#![cfg_attr(rustfmt, rustfmt::skip)]
2use super::*;
3
4/// Helper for the generation of C headers.
5///
6/// Defining C headers requires _two_ abstractions:
7///
8///   - set-like lookup by name, to ensure each type is defined at most once;
9///
10///   - a [`Write`][`::std::io::Write`]able "out stream", where the headers
11///     should be written to.
12///
13/// This trait minimally combines both abstractions, and in exchange offers an
14/// auto-implemented non-overridable
15/// [`Definer::define_once`]`()`.
16pub
17trait Definer : define_once_seal::__ {
18    /// Must return `true` iff an actual `insert` happened.
19    fn insert (self: &'_ mut Self, name: &'_ str)
20      -> bool
21    ;
22
23    /// Yields a handle to the underlying [`Write`][`io::Write`]r
24    fn out (self: &'_ mut Self)
25      -> &'_ mut dyn io::Write
26    ;
27
28    #[cfg(docs)]
29    /// Convenience method to perform an [`.insert()`][`Definer::insert`] so
30    /// that if it succeeds (thus guaranteeing the call happens for the first
31    /// time), it calls `write_typedef` on itself.
32    ///
33    /// **This method cannot be overriden**.
34    fn define_once (
35        self: &'_ mut Self,
36        name: &'_ str,
37        write_typedef: &'_ mut dyn
38            FnMut (&'_ mut dyn Definer) -> io::Result<()>
39        ,
40    ) -> io::Result<()>
41    { unreachable!("See `define_once_seal::__::define_once` for the impl") }
42}
43
44mod define_once_seal {
45    use super::*;
46
47    pub
48    trait __ {
49        fn define_once (
50            self: &'_ mut Self,
51            name: &'_ str,
52            write_typedef: &'_ mut dyn
53                FnMut(&'_ mut dyn Definer) -> io::Result<()>
54            ,
55        ) -> io::Result<()>
56        ;
57    }
58
59    impl<T : Definer> __
60        for T
61    {
62        fn define_once (
63            self: &'_ mut Self,
64            name: &'_ str,
65            write_typedef: &'_ mut dyn
66                FnMut(&'_ mut dyn Definer) -> io::Result<()>
67            ,
68        ) -> io::Result<()>
69        {
70            if self.insert(name) {
71                write_typedef(self)?;
72            }
73            Ok(())
74        }
75    }
76}
77
78/// Simplest implementation of a [`Definer`]:
79/// a `HashSet<String>, &'_ mut dyn Write` pair.
80pub
81struct HashSetDefiner<'out> {
82    pub
83    defines_set: HashSet<String>,
84
85    pub
86    out: &'out mut dyn io::Write,
87}
88
89impl Definer
90    for HashSetDefiner<'_>
91{
92    fn insert (self: &'_ mut Self, name: &'_ str)
93      -> bool
94    {
95        self.defines_set
96            .insert(name.to_owned())
97    }
98
99    fn out (self: &'_ mut Self)
100      -> &'_ mut dyn io::Write
101    {
102        &mut *self.out
103    }
104}