2
2
// SPDX-License-Identifier: Apache-2.0
3
3
#![ deny( missing_docs) ]
4
4
5
- //! Exports the Versionize derive proc macro that generates the Versionize implementation
6
- //! for structs, and enums by using annotations.
7
-
5
+ //! Exports the `Versionize` derive proc macro that generates the Versionize
6
+ //! trait implementation.
7
+ //!
8
+ //! Versionize generates serialization and deserialization code only for
9
+ //! structures and enums.
10
+ //!
11
+ //! Supported primitives: u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,
12
+ //! char, f32, f64, String, Vec<T>, Arrays up to 32 elements, Box<T>,
13
+ //! Wrapping<T>, Option<T>, FamStructWrapper<T>, and (T, U).
14
+ //!
15
+ //! Known issues and limitations:
16
+ //! - Union serialization is not supported via the `Versionize` proc macro.
17
+ //! - Implementing Versionize for non-repr(C) unions can result in undefined
18
+ //! behaviour and MUST be avoided.
19
+ //! - Versionize trait implementations for repr(C) unions must be backed by
20
+ //! extensive testing.
21
+ //! - Semantic serialization and deserialization is available only for structures.
22
+ //!
8
23
extern crate proc_macro;
9
24
extern crate proc_macro2;
10
25
extern crate quote;
@@ -30,7 +45,170 @@ pub(crate) const SEMANTIC_DE_FN: &str = "de_fn";
30
45
pub ( crate ) const START_VERSION : & str = "start" ;
31
46
pub ( crate ) const END_VERSION : & str = "end" ;
32
47
33
- /// Implements the derive proc macro.
48
+ /// Generates serialization and deserialization code as an implementation of
49
+ /// the `Versionize` trait.
50
+ ///
51
+ /// Different code paths are generated for each version of the structure or
52
+ /// enum. There is no limit enforced on the maximum number of structure
53
+ /// versions.
54
+ ///
55
+ /// ### Struct and enum requirements
56
+ /// - all members or enum variants need to implement the `Versionize` trait
57
+ /// - no generics are being used (this is currenly a limitation)
58
+ ///
59
+ /// ## Annotations
60
+ ///
61
+ /// To facilitate version tolerant serialization "history metadata" is attached
62
+ /// to the structure or enum. This is done by using the `version` attribute in
63
+ /// their definition. In the below example a new field is added to the
64
+ /// structure starting with version 2: `#[version(start = 2)]`.
65
+ ///
66
+ /// ```ignore
67
+ /// extern crate versionize;
68
+ /// extern crate versionize_derive;
69
+ /// use versionize::{Versionize, VersionizeError, VersionizeResult};
70
+ /// use versionize_derive::Versionize;
71
+ ///
72
+ /// #[derive(Versionize)]
73
+ /// struct Test {
74
+ /// a: u32,
75
+ /// #[version(start = 2)]
76
+ /// b: u8,
77
+ /// }
78
+ /// ```
79
+ ///
80
+ /// Multiple version annotations can be defined for a field, like for example:
81
+ /// `#[version(start = 2, end = 3)]`. Field was added in structure version 2
82
+ /// and removed in version 3. The generated code will attempt to (de)serialize
83
+ /// this field only for version 2 of the structure.
84
+ ///
85
+ /// ### Supported field attributes and usage
86
+ ///
87
+ /// The `version` attribute accepts multiple key/value pairs to be specified in
88
+ /// order to support versioning, semantic serialization and default values for
89
+ /// fields. All of these are optional and a default behaviour is provided in
90
+ /// their absence.
91
+ ///
92
+ /// #### default_fn
93
+ ///
94
+ /// Provides an initialization value for a field when deserializing from an
95
+ /// older structure version which does not contain this field. If not specified
96
+ /// the `Default` trait isused to initialize the field.
97
+ ///
98
+ /// ```ignore
99
+ /// extern crate versionize;
100
+ /// extern crate versionize_derive;
101
+ /// use versionize::{Versionize, VersionizeError, VersionizeResult};
102
+ /// use versionize_derive::Versionize;
103
+ ///
104
+ /// #[derive(Versionize)]
105
+ /// struct TestStruct {
106
+ /// a: u32,
107
+ /// #[version(start = 2, default_fn = "default_b")]
108
+ /// b: u8,
109
+ /// }
110
+ ///
111
+ /// impl TestStruct {
112
+ /// fn default_b(_source_version: u16) -> u8 {
113
+ /// 12u8
114
+ /// }
115
+ /// }
116
+ /// ```
117
+ ///
118
+ /// The function name needs to be specified as a string and its prototype must
119
+ /// take an u16 source version parameter and return a value of the same type as
120
+ /// as the field.
121
+ ///
122
+ /// #### start/end
123
+ ///
124
+ /// Defines the field version lifetime. Fields can be added by specifing the
125
+ /// start version of the structure when first defining them and can be later
126
+ /// on removed from serialization logic by adding and end version.
127
+ ///
128
+ /// For example: `#[version(start = 2, end = 4)]`. The field would be present
129
+ /// in the structure v2 and v3, but starting with v4 it would no longer be
130
+ /// serialized or deserialized.
131
+ ///
132
+ /// Once a field is removed, it can never be added again in a future version.
133
+ ///
134
+ /// #### ser_fn
135
+ /// * Not supported for enums. *
136
+ ///
137
+ /// Defines a semantic serialization function for a field. The function needs
138
+ /// to be specified as a string and implemented as a method attached to
139
+ /// the structure. The prototype of the function is
140
+ /// `fn(&mut self, u16) -> VersionizeResult<()>`.
141
+ ///
142
+ /// If defined, the method is called when the field is skipped from
143
+ /// serialization because it does not exist in the target version of the
144
+ /// structure. Its implementation can perform any mutation of `self` or return
145
+ /// an error to stop serialization. Intended usage is to implement semantic
146
+ /// translation or semantic validations.
147
+ ///
148
+ /// ```ignore
149
+ /// extern crate versionize;
150
+ /// extern crate versionize_derive;
151
+ /// use versionize::{Versionize, VersionizeError, VersionizeResult};
152
+ /// use versionize_derive::Versionize;
153
+ ///
154
+ /// #[derive(Versionize)]
155
+ /// struct SomeStruct {
156
+ /// some_u32: u32,
157
+ /// #[version(start = 2, ser_fn = "ser_u16")]
158
+ /// some_u16: u16,
159
+ /// }
160
+ ///
161
+ /// impl SomeStruct {
162
+ /// fn ser_u16(&mut self, target_version: u16) -> VersionizeResult<()> {
163
+ /// self.some_u32 = self.some_u32 & self.some_u16 as u32;
164
+ /// Ok(())
165
+ /// }
166
+ /// }
167
+ /// ```
168
+ ///
169
+ /// #### de_fn
170
+ /// * Not supported for enums. *
171
+ ///
172
+ /// Defines a semantic deserialization function for a field. The function needs
173
+ /// to be specified as a string and implemented as a method attached to
174
+ /// the structure. The prototype of the function is
175
+ /// `fn(&mut self, u16) -> VersionizeResult<()>`.
176
+ ///
177
+ /// If defined, the method is called if the field is skipped from
178
+ /// deserialization because it does not exist in the source version of the
179
+ /// serialized structure. Its implementation can perform any mutation of `self`
180
+ /// or return an error to stop deserialization. Intended usage is to implement
181
+ /// semantic translation or semantic validations.
182
+ ///
183
+ /// Both `default_fn` and `de_fn` can be specified for a field. `default_fn` is
184
+ /// always called first and `de_fn` last.
185
+ ///
186
+ /// ```ignore
187
+ /// extern crate versionize;
188
+ /// extern crate versionize_derive;
189
+ /// use versionize::{Versionize, VersionizeError, VersionizeResult};
190
+ /// use versionize_derive::Versionize;
191
+ ///
192
+ /// #[derive(Clone, Versionize)]
193
+ /// struct SomeStruct {
194
+ /// some_u32: u32,
195
+ /// #[version(start = 2, ser_fn = "ser_u16", de_fn = "de_u16")]
196
+ /// some_u16: u16,
197
+ /// }
198
+ ///
199
+ /// impl SomeStruct {
200
+ /// fn ser_u16(&mut self, target_version: u16) -> VersionizeResult<()> {
201
+ /// self.some_u32 = self.some_u32 & self.some_u16 as u32;
202
+ /// Ok(())
203
+ /// }
204
+ /// fn de_u16(&mut self, source_version: u16) -> VersionizeResult<()> {
205
+ /// if source_version < 2 {
206
+ /// self.some_u16 = (self.some_u32 & 0xFF) as u16;
207
+ /// }
208
+ /// Ok(())
209
+ /// }
210
+ /// }
211
+ /// ```
34
212
#[ proc_macro_derive( Versionize , attributes( version) ) ]
35
213
pub fn impl_versionize ( input : TokenStream ) -> proc_macro:: TokenStream {
36
214
let input = parse_macro_input ! ( input as DeriveInput ) ;
0 commit comments