ffi_enum_macros/lib.rs
1use proc_macro::TokenStream;
2use syn::{parse_macro_input, Error};
3
4mod delegate;
5mod ffi_enum;
6mod utils;
7
8macro_rules! export_attribute {
9 ($($(#[$attr:meta])* $i:ident),*$(,)?) => {$(
10 $(#[$attr])*
11 #[proc_macro_attribute]
12 pub fn $i(args: TokenStream, item: TokenStream) -> TokenStream {
13 $i::handle(parse_macro_input!(args), parse_macro_input!(item))
14 .unwrap_or_else(Error::into_compile_error)
15 .into()
16 }
17 )*};
18}
19
20export_attribute!(
21 /// Converts the enum into ffi-safe `enum`s that could be safely sent through ffi Metadata, separated with
22 /// `,`, passed as arguments of this attribute call would be transformed into raw attributes attached on
23 /// the generated `ffi_enum`.
24 ///
25 /// The generated `ffi_enum` type implements `::ffi_enum::FfiEnum` that provides with essential type and constant
26 /// informations of the generated details.
27 ///
28 /// The generated `ffi_enum` type by default implements `Copy`, `Clone`, `PartialEq`, `Eq`, based on which
29 /// essential implementations could be derived.
30 ///
31 /// ## For Derive Macros
32 ///
33 /// There are 3 positions to place derive macros:
34 ///
35 /// 1. **(Preferred)** `#[derive(...)]` attached above `ffi_enum` would **see the original `enum` definition**
36 /// and **`impl`s for the generated `ffi_enum` type**. Note that helper attributes attached below this
37 /// `ffi_enum` attribute would also be seen by such derive macros.
38 ///
39 /// 2. `#[ffi_enum(derive(...))]` passed within this attribute would **both** see the definition of and takes
40 /// all effects on **the generated `ffi_enum` type**. All helper attributes passed within this attribute
41 /// would **only** be been by the derive macros passed in this way.
42 ///
43 /// 3. `#[derive(...)]` attached below `ffi_enum` would **both** see the definition of and takes
44 /// all effects on the **the original `enum` definition**.
45 ///
46 /// Derive macros that works on regular `enum`s may simply works fine at Position `1` described above,
47 /// unless the expanded code `match`es the value of the generated `ffi_enum` type **without a
48 /// `_` wildcard pattern** that covers other unknown values that would potentially come from ffi.
49 ///
50 /// As for the derive macros that does not care the variant details, or normally logically works fine for a
51 /// struct that contaions a single field, attach the derive macros along with
52 /// their helper attributes at Position `2`. Derive macros passed in this way would see a `ffi_enum_origin`
53 /// helper attribute with the original enum definition passed as the arguments. If you are authoring a derive
54 /// macro that may need to see both the original and generated definitions, this way is preferred.
55 ///
56 /// As for the derive macros that generate `match`ing code without wildcards, or the implemention of which is
57 /// logically insufficient for the generated `ffi_enum` type that covers all binary patterns. The only
58 /// way of automatic deriving is to `derive` at Position `3` described above, which implements for the original
59 /// `enum` definition, and then delegate the implementations from the original `enum` definition which could
60 /// accessed as `<TypeName as ffi_enum::FfiEnum>::Enum`.
61 ///
62 /// This attribute macro would automatically delegate implementations for the generated `ffi_enum` type
63 /// for supported traits. The currently supported derives are:
64 ///
65 /// + `core::fmt::Debug`
66 /// + `core::fmt::Display` (The derive macro for the original `enum` is not hereby specified, user may use any
67 /// one that implements it for the original type)
68 /// + `core::hash::Hash`
69 /// + `core::str::FromStr` (The derive macro for the original `enum` is not hereby specified, user may use any
70 /// one that implements it for the original type)
71 /// + `thiserror::Error` implementing `core::error::Error` and `core::fmt::Display`
72 /// + `serde::Serialize`
73 /// + `serde::Deserialize`
74 ///
75 /// For more automatically delegatings, contributions are welcomed.
76 ffi_enum
77);
78
79#[doc(hidden)]
80#[proc_macro_derive(NoDerive, attributes(ffi_enum_origin))]
81pub fn no_derive(_: TokenStream) -> TokenStream {
82 TokenStream::new()
83}