22// SPDX-License-Identifier: Apache-2.0
33#![ deny( missing_docs) ]
44
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+ //!
823extern crate proc_macro;
924extern crate proc_macro2;
1025extern crate quote;
@@ -30,7 +45,170 @@ pub(crate) const SEMANTIC_DE_FN: &str = "de_fn";
3045pub ( crate ) const START_VERSION : & str = "start" ;
3146pub ( crate ) const END_VERSION : & str = "end" ;
3247
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+ /// ```
34212#[ proc_macro_derive( Versionize , attributes( version) ) ]
35213pub fn impl_versionize ( input : TokenStream ) -> proc_macro:: TokenStream {
36214 let input = parse_macro_input ! ( input as DeriveInput ) ;
0 commit comments