bagel/lib.rs
1//! 🥯 `bagel`: Always baked, never fried
2//!
3//! `bagel` provides a collection of compile-time "magic" that we use frequently at
4//! [Skytable](https://github.com/skytable/skytable).
5//!
6//! ## What bagel can do
7//!
8//! - [`Constdef`](derive.Constdef.html): Derive constant, compile-time default implementations
9//! - [`Ctor`]: Derive constructors
10//! - [`Gtor`]: Derive getters
11//! - [`Stor`]: Derive setters
12//! - [`def`]: Use the [default declaration syntax](https://github.com/skytable/bagel#default-declaration-syntax)
13//!
14
15#[macro_use]
16mod internal_macros;
17mod constdef_impls;
18mod macros;
19
20/// # Constant defaults
21///
22/// The [`Constdef`] trait is the heart of constant, compile-time default values. This trait
23/// is automatically implemented for several types in the standard library.
24///
25/// ## Implementing this trait
26///
27/// Usually, for implementing this trait -- you'll simply need to use `#[derive(bagel::Constdef)]`
28/// and the macro will do the magic for you. In other cases, you'll need to implement it yourself,
29/// like this for example:
30///
31/// ```
32/// use bagel::Constdef;
33///
34/// struct MyWeirdBool(bool);
35///
36/// impl Constdef for MyWeirdBool {
37/// const DEFAULT: MyWeirdBool = MyWeirdBool(false);
38/// }
39///
40/// ```
41///
42pub trait Constdef {
43 /// The default value for Self
44 const DEFAULT: Self;
45}
46
47// re-export macros
48
49/// # The `Constdef` macro
50/// Overcome the limits of the [`Default`] trait to get constant, compile-time default implementations.
51///
52/// The [`Constdef`](derive.Constdef.html) derive macro enables you to create constant,
53/// compile-time [`Default`] implementations, in the simplest possible way. With restrictions
54/// imposed by [RFC 911 on `const` functions](https://rust-lang.github.io/rfcs/0911-const-fn.html#detailed-design),
55/// trait methods cannot currently be called in `const` contexts. To work around this, this crate
56/// provides you with the [`Constdef`](derive.Constdef.html) macro that peeks into the AST and substitutes
57/// the default value at compile-time. This enables you to call the `default` function in constant
58/// contexts.
59///
60/// ## Example
61/// ```
62/// use bagel::Constdef;
63///
64/// type MyType = u16;
65/// #[derive(Constdef)]
66/// pub struct SpookyFriend {
67/// name: String,
68/// email: String,
69/// friend_names: Vec<String>,
70/// userid: u64,
71/// my_tag: MyType,
72/// }
73///
74/// const SPOOKY: SpookyFriend = SpookyFriend::default();
75///
76/// #[test]
77/// fn test_struct_with_heap_fields() {
78/// // spooky name; it's empty!
79/// assert_eq!(SPOOKY.name, "");
80/// // spooky email; it's empty!
81/// assert_eq!(SPOOKY.email, "");
82/// // spooky friend has no friends!
83/// assert!(SPOOKY.friend_names.is_empty());
84/// // spooky userid; it's 0!
85/// assert_eq!(SPOOKY.userid, 0);
86/// // spooky tag; it's 0!
87/// assert_eq!(SPOOKY.mytag, 0);
88/// }
89/// ```
90/// Even more complex types are supported. See [crate level docs](crate) for more information.
91///
92pub use dough::Constdef;
93
94/// # Ctor: Get a constructor derived
95///
96/// The [`Ctor`] macro will take the fields in the order they are declared and generate a
97/// constructor, that is a `YourStruct::new()` function.
98///
99///
100/// ## Example
101/// ```
102/// use bagel::Ctor;
103///
104/// #[derive(Ctor)]
105/// struct MyStruct {
106/// int: u32,
107/// unsigned_int: i32,
108/// }
109///
110/// let ms = MyStruct::new(1, -1);
111/// assert_eq!(ms.int, 1);
112/// assert_eq!(ms.unsigned_int, -1);
113/// ```
114///
115/// # Attributes
116///
117/// The following attributes are available:
118/// - `#[ctor_const]`: Will make your ctors constant
119/// - `#[phantom]`: Will skip the specified [`PhantomData`](core::marker::PhantomData) field(s) in
120/// the constructor, automatically adding `PhantomData` in the requisite positions
121///
122/// ## Constant constructors
123///
124/// To make your constructors `const`, simply add the `#[ctor_const]` attribute to the top
125/// of your struct.
126///
127/// ### Example
128///
129/// ```
130/// use bagel::Ctor;
131///
132/// #[derive(Ctor)]
133/// #[ctor_const]
134/// pub struct MyConst {
135/// a: u8,
136/// b: u8,
137/// }
138/// // you can now use it in constant contexts
139/// const MC: MyConst = MyConst::new(1, 2);
140/// ```
141///
142pub use dough::Ctor;
143
144/// # Gtor: Get the getters derived
145///
146/// Gtor takes the fields in order and generates getters for each field. For example,
147/// if you have fields named `userid` and `name`, then the getters generated will be
148/// `get_userid` and `get_name`, returning references to the appropriate types. In other
149/// words, `get_*` named methods will be derived per your fields.
150///
151/// ## Example
152/// ```
153/// use bagel::Gtor;
154/// #[derive(Gtor)]
155/// struct MyStruct {
156/// name: String,
157/// userid: u64,
158/// }
159///
160/// let ms = MyStruct { name: "Sayan".to_owned(), userid: 16 };
161/// assert_eq!(ms.get_name(), "Sayan");
162/// ```
163/// # Attributes
164///
165/// The following attributes are available:
166/// - `#[gtor_const]`: Will make your gtors constant
167/// - `#[gtor_skip]`: Will skip generation of getters for specific fields
168/// - `#[gtor_copy]`: Makes the getter return a copy of the value, assuming that the type is [`Copy`]
169/// - `#[phantom]`: Marks the field as a [`PhantomData`](core::marker::PhantomData) field, hence
170/// skipping getters, setters and ctors for the field
171/// - `#[gtor(...)]`: See [this example](#the-gtor-attribute)
172///
173/// ## The `gtor` attribute
174///
175/// Simply add the gtor attribute like this: `#[gtor(get, get_mut)]` on the top of your struct to
176/// get mutable and immutable reference methods to the fields in your struct.
177///
178/// ### Example
179///
180/// ```
181/// use bagel::{Ctor, Gtor};
182/// #[derive(Ctor, Gtor)]
183/// #[gtor(get, get_mut)]
184/// pub struct Mutable {
185/// x_axis: u8,
186/// y_axis: u8,
187/// }
188///
189/// #[test]
190/// fn test_get_and_get_mut() {
191/// let mut m = Mutable::new(0, 0);
192/// // move x by 1 unit
193/// *m.get_x_axis_mut() = 1;
194/// // move y by 2 units
195/// *m.get_y_axis_mut() = 2;
196/// assert_eq!(m.get_x_axis(), 1);
197/// assert_eq!(m.get_y_axis(), 2);
198/// }
199/// ```
200///
201/// # Important notes
202///
203/// ## References
204/// If any of the fields within the struct are primitive types that do not require large copies,
205/// then the value is returned directly instead of a reference to it:
206/// ```text
207/// u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, str, bool, usize, isize, char, f32, f64
208/// ```
209///
210/// ## Doc-comments
211///
212/// The [`Gtor`] macro will automatically add a doc comment of the form:
213/// ```text
214/// Returns the value for the `<struct_field>` field in struct [`<struct_name>`]
215/// ```
216///
217pub use dough::Gtor;
218
219/// # Stor: Get the setters derived
220///
221/// Stor takes the fields in order and generates setters for each field. For example,
222/// if you have fields named `userid` and `name`, then the setters generated will be
223/// `set_userid` and `set_name`, accepting values for the appropriate types. In other
224/// words, `set_*` named methods will be derived per your fields.
225///
226/// ## Example
227/// ```
228/// use bagel::Stor;
229/// #[derive(Stor)]
230/// struct MyStruct {
231/// name: String,
232/// userid: u64,
233/// }
234///
235/// let mut ms = MyStruct { name: "Sayan".to_owned(), userid: 1 };
236/// assert_eq!(ms.name, "Sayan");
237/// assert_eq!(ms.userid, 1);
238/// ms.set_userid(0);
239/// assert_eq!(ms.userid, 0);
240/// ```
241///
242/// # Attributes
243///
244/// The following attributes are available:
245/// - `#[phantom]`: Skips the stor for the specified field(s), assuming they are
246/// [`PhantomData`](core::marker::PhantomData) fields. This has the same effect as `#[stor_skip]`
247/// but it makes it easier to use with the other macros, avoiding the need to write skips for phantom
248/// fields specifically
249/// - `#[stor_skip]`: Skips the stor for the specified field(s)
250///
251/// ## Doc-comments
252///
253/// The [`Stor`] macro will automatically add a doc comment of the form:
254/// ```text
255/// Sets the value for the `<struct_field>` field in struct [`<struct_name>`]
256/// ```
257///
258pub use dough::Stor;