1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! # Obake
//!
//! Obake is a procedural macro for declaring and maintaining versioned data-structures. The name
//! 'obake' is taken from the Japanese 'お化け (おばけ)', a class of supernatural beings in
//! Japanese folklore that shapeshift.
//!
//! When developing an application, configuration formats and internal data-structures typically evolve
//! between versions. However, maintaining backwards compatibility between these versions requires
//! declaring a maintaining data-structures for legacy formats and code for migrating between them.
//! Obake aims to make this process effortless.
//!
//! ## Example
//!
//! ```
//! #[obake::versioned] // create a versioned data-structure
//! #[obake(version("0.1.0"))] // declare some versions
//! #[obake(version("0.2.0"))]
//! #[derive(Debug, PartialEq, Eq)] // additional attributes are applied to all versions
//! struct Foo {
//! #[obake(cfg("0.1.0"))] // enable fields for specific versions with
//! foo: String, // semantic version constraints
//!
//! #[obake(cfg(">=0.2, <=0.3.0"))] // any semantic version constraint can appear in
//! bar: u32, // a `cfg` attribute
//!
//! #[obake(cfg("0.1.0"))] // multiple `cfg` attributes are treated as a
//! #[obake(cfg(">=0.3"))] // disjunction over version constraints
//! baz: char,
//! }
//!
//! // describe migrations between versions using the `From` trait
//! // and an automatically generated type-level macro for referring to
//! // specific versions of `Foo`
//! impl From<Foo!["0.1.0"]> for Foo!["0.2.0"] {
//! fn from(foo: Foo!["0.1.0"]) -> Self {
//! Self { bar: 0 }
//! }
//! }
//!
//! // an enumeration of all versions of `Foo` is accessed using the `obake::AnyVersion` type
//! // alias
//! let versioned_example: obake::AnyVersion<Foo> = (Foo { bar: 42 }).into();
//!
//! // this enumeration implements `Into<Foo>`, where `Foo` is the latest declared
//! // version of `Foo` (in this case, `Foo!["0.2.0"]`)
//! let example: Foo = versioned_example.into();
//!
//! assert_eq!(example, Foo { bar: 42 });
//! ```
//!
//! ## Other Features
//!
//! - `#[obake(inherit)]`: allows nesting of versioned data-structures.
//! - `#[obake(derive(...))]`: allows derive attributes to be applied to generated `enum`s.
//! - `#[obake(serde(...))]`: allows [`serde`](https://serde.rs) attributes to be applied to
//! generated `enum`s.
//! - Note: requires the feature `serde`.
//!
//! ## Limitations
//!
//! - Cannot be applied to tuple `struct`s (or `enum` variants with unnamed fields).
//! - Cannot be applied to items with generic parameters.
/// The core macro of the library. Used to declare versioned data-structures.
///
/// ### Supported attributes:
///
/// - `#[obake(version("x.y.z"))]` - Declares a possible version of the data-structure.
/// - `#[obake(cfg(...))]` - Specifies a semantic version constraints for a particular field or
/// variant.
/// - `cfg` can contain any number of comma-separated semantic version constraints (e.g.,
/// `#[obake(cfg(">=0.3, <=0.1"))]`).
/// - A field or variant marked with a `cfg` attribute will only appear in a particular version
/// of the data-structure type all of the attributes constraints are satisfied by that
/// version.
/// - In the presence of multiple `cfg` attributes, any matching `cfg` will result in a match
/// (i.e., while comman-seperated constraints are treated as a conjunctively, multiple `cfg`
/// attributes are treated as a disjunctively).
/// - `#[obake(derive(...))]` - Apply a derive to the version-tagged enum generated for the
/// data-structre.
/// - `#[obake(serde(...))]` - Apply a [serde] attribute to the version-tagged enum generated
/// for the data-structre.
/// - Note: requires the feature `serde`.
/// - `#[obake(inherit)]` - Marks a field as having an inherited version (i.e., given a field of
/// type `Bar`, when marked with `inherit`, this field will be expanded to a field of type
/// `Bar![{version}]` in every version).
///
/// [serde]: https://serde.rs
// TODO(@doctorn) document generated types and trait implementations
pub use versioned;
/// Automatically implemented for the latest version of a versioned data-structure.
///
/// ## Note
///
/// Not intended to be hand-implemented, use [`versioned`] to derive it.
/// Automatically implemented by the generated version-tagged encoding of a [`versioned`]
/// data-structure.
///
/// ## Note
///
/// Not intended to be hand-implemented, use [`versioned`] to derive it.
/// Short-hand for referring to the version-tagged representation of a [`versioned`] data-structre.
pub type AnyVersion<T> = Versioned;
/// Automatically implemented for all declared versions of a versioned data-structure.
///
/// ## Note
///
/// Not intended to be hand-implemented, use [`versioned`] to derive it.
/// A struct representing a mismatch of versions.
///
/// Such a mismatch can occur when trying to convert a version-tagged representation of a piece
/// of data into a particular version.