feattle_core/
macros.rs

1/// Define an `enum` that can be used as a type for a feattle
2///
3/// The generated `enum` will have these standard traits: `Debug`, `Clone`, `Copy`, `Eq`,
4/// `PartialEq`, `PartialOrd`, `Ord`, `FromStr`, `Display`. And mainly, it will implement
5/// [`crate::FeattleStringValue`] so that it can be used a feattle type.
6///
7/// Only `enum`s whose variants do not carry any extra information are supported.
8///
9/// # Examples
10/// In the simplest form:
11/// ```
12/// use feattle_core::feattle_enum;
13///
14/// feattle_enum! {
15///     enum Colors { Red, Green, Blue }
16/// }
17/// ```
18///
19/// However, it also works with other visibility keywords and additional attributes on the enum
20/// itself or its variants. Those attributes will not be modified by this lib, allowing composition
21/// with other libs. For example, you can also make the enum `Serialize`:
22/// ```
23/// use feattle_core::feattle_enum;
24/// use serde::Serialize;
25///
26/// feattle_enum! {
27///     #[derive(Serialize)]
28///     pub(crate) enum Colors {
29///         #[serde(rename = "R")]
30///         Red,
31///         #[serde(rename = "G")]
32///         Green,
33///         #[serde(rename = "B")]
34///         Blue,
35///     }
36/// }
37/// ```
38#[macro_export]
39macro_rules! feattle_enum {
40    (
41        $(#[$enum_meta:meta])*
42        $visibility:vis enum $name:ident {
43            $(
44                $(#[$variant_meta:meta])*
45                $variant:ident
46            ),+ $(,)?
47        }
48    ) => {
49        #[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
50        $(#[$enum_meta])*
51        $visibility enum $name {
52            $(
53                $(#[$variant_meta])*
54                $variant
55            ),+
56        }
57
58        impl ::std::str::FromStr for $name {
59            type Err = $crate::__internal::ParseError;
60            fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
61                match s {
62                    $(
63                        stringify!($variant) => ::std::result::Result::Ok(Self::$variant)
64                    ),+,
65                    _ => ::std::result::Result::Err($crate::__internal::ParseError)
66                }
67            }
68        }
69
70        impl ::std::fmt::Display for $name {
71            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
72                let as_str = match self {
73                    $(
74                        Self::$variant => stringify!($variant)
75                    ),+
76                };
77                ::std::write!(f, "{}", as_str)
78            }
79        }
80
81        impl $name {
82            const VARIANTS: &'static [&'static str] = &[
83                $(
84                    stringify!($variant)
85                ),+
86            ];
87        }
88
89        impl $crate::FeattleStringValue for $name {
90            fn serialized_string_format() -> $crate::StringFormat {
91                let variants = Self::VARIANTS.join(", ");
92                $crate::StringFormat {
93                    kind: $crate::StringFormatKind::Choices(&Self::VARIANTS),
94                    tag: format!("enum {{{}}}", variants),
95                }
96            }
97        }
98    }
99}
100
101#[macro_export]
102#[doc(hidden)]
103macro_rules! __init_field {
104    ($default:expr) => {
105        $default
106    };
107    () => {
108        Default::default()
109    };
110}
111
112/// The main macro of this crate, used to generate a struct that will provide the Feattles
113/// functionalities.
114///
115/// See more at the [crate level](crate).
116#[macro_export]
117macro_rules! feattles {
118    (
119    $(#[$meta:meta])*
120    $visibility:vis struct $name:ident {
121        $(
122            $(#[doc=$description:tt])*
123            $key:ident: $type:ty $(= $default:expr)?
124        ),*
125        $(,)?
126    }
127) => {
128        use $crate::__internal;
129
130        $(#[$meta])*
131        #[derive(Debug)]
132        $visibility struct $name(__internal::FeattlesImpl<__Feattles>);
133
134        impl __internal::FeattlesPrivate for $name {
135            type FeattleStruct = __Feattles;
136
137            fn _read(
138                &self,
139            ) -> __internal::RwLockReadGuard<'_, __internal::InnerFeattles<Self::FeattleStruct>>
140            {
141                self.0.inner_feattles.read()
142            }
143
144            fn _write(
145                &self,
146            ) -> __internal::RwLockWriteGuard<'_, __internal::InnerFeattles<Self::FeattleStruct>>
147            {
148                self.0.inner_feattles.write()
149            }
150        }
151
152        impl __internal::Feattles for $name {
153            fn new(persistence: __internal::Arc<dyn __internal::Persist>) -> Self {
154                $name(__internal::FeattlesImpl::new(
155                    persistence,
156                    __Feattles {
157                        $(
158                            $key: __internal::Feattle::new(
159                                stringify!($key),
160                                concat!($($description),*).trim(),
161                                $crate::__init_field!($($default)?),
162                            )
163                        ),*
164                    },
165                ))
166            }
167
168            fn persistence(&self) -> &__internal::Arc<dyn __internal::Persist> {
169                &self.0.persistence
170            }
171
172            fn keys(&self) -> &'static [&'static str] {
173                &[$(stringify!($key)),*]
174            }
175
176            fn definition(&self, key: &str) -> Option<__internal::FeattleDefinition> {
177                use __internal::FeattlesPrivate;
178                let inner = self._read();
179                match key {
180                    $(stringify!($key) => Some(inner.feattles_struct.$key.definition()),)*
181                    _ => None,
182                }
183            }
184        }
185
186        impl $name {
187            $(
188                pub fn $key(&self) -> __internal::MappedRwLockReadGuard<$type> {
189                    __internal::RwLockReadGuard::map(self.0.inner_feattles.read(), |inner| {
190                        inner.feattles_struct.$key.value()
191                    })
192                }
193            )*
194        }
195
196        #[derive(Debug)]
197        pub struct __Feattles {
198            $($key: __internal::Feattle<$type>),*
199        }
200
201        impl __internal::FeattlesStruct for __Feattles {
202            fn try_update(
203                &mut self,
204                key: &str,
205                value: Option<__internal::CurrentValue>,
206            ) -> Result<Option<__internal::CurrentValue>, __internal::FromJsonError> {
207                match key {
208                    $(stringify!($key) => self.$key.try_update(value),)*
209                    _ => unreachable!(),
210                }
211            }
212        }
213    }
214}