Skip to content

Commit 0111a5c

Browse files
committed
docs(stackable-versioned): Update usage guide
1 parent b262bde commit 0111a5c

File tree

2 files changed

+183
-89
lines changed
  • crates
    • stackable-versioned-macros/src
    • stackable-versioned/src

2 files changed

+183
-89
lines changed

crates/stackable-versioned-macros/src/lib.rs

Lines changed: 183 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,95 @@ mod attrs;
88
mod codegen;
99
mod consts;
1010

11-
/// This macro enables generating versioned structs.
11+
/// This macro enables generating versioned structs and enums.
1212
///
13-
/// ## Usage Guide
13+
/// # Usage Guide
1414
///
15-
/// ### Quickstart
15+
/// In this guide, code blocks usually come in pairs. The first code block
16+
/// describes how the macro is used. The second expandable block displays the
17+
/// generated piece of code for explanation purposes. It should be noted, that
18+
/// the exact code can diverge from what is being depicted in this guide. For
19+
/// example, `#[automatically_derived]` and `#[allow(deprecated)]` are removed
20+
/// in most examples to reduce visual clutter.
21+
///
22+
/// ## Declaring Versions
23+
///
24+
/// It is **important** to note that this macro must be placed before any other
25+
/// (derive) macros and attributes. This ensures that the macros and attributes
26+
/// are applied to the generated versioned instances of the struct or enum.
27+
///
28+
/// Before any of the fields or variants can be versioned, versions need to be
29+
/// declared at the container level. Each version currently supports two
30+
/// parameters: `name` and the `deprecated` flag. The `name` must be a valid
31+
/// (and supported) format - currently, only Kubernetes API versions are
32+
/// supported. The macro checks each declared version and reports any error
33+
/// encountered during parsing.
1634
///
1735
/// ```
1836
/// # use stackable_versioned_macros::versioned;
19-
/// #[versioned(
20-
/// version(name = "v1alpha1"),
21-
/// version(name = "v1beta1"),
22-
/// version(name = "v1"),
23-
/// version(name = "v2"),
24-
/// version(name = "v3")
25-
/// )]
37+
/// #[versioned(version(name = "v1alpha1"))]
2638
/// struct Foo {
27-
/// /// My docs
28-
/// #[versioned(
29-
/// added(since = "v1beta1"),
30-
/// changed(since = "v1", from_name = "gau"),
31-
/// deprecated(since = "v2", note = "not empty")
32-
/// )]
33-
/// deprecated_bar: usize,
34-
/// baz: bool,
39+
/// bar: usize,
3540
/// }
3641
/// ```
3742
///
38-
/// ### Declaring Versions
43+
/// <details>
44+
/// <summary>Generated code</summary>
45+
///
46+
/// 1. The `#[automatically_derived]` attribute indicates that the following
47+
/// piece of code is automatically generated by a macro instead of being
48+
/// handwritten by a developer. This information is used by cargo and rustc.
49+
/// 2. For each declared version, a new module containing the struct or enum
50+
/// (container) is generated. This enables you to reference the container by
51+
/// versions via `v1alpha1::Foo`.
52+
/// 3. This `use` statement gives the generated containers access to the imports
53+
/// at the top of the file. This is a convenience, because otherwise you
54+
/// would need to prefix used items with `super::`. Additionally, other
55+
/// macros can have trouble using items referred to with `super::`.
56+
///
57+
/// ```ignore
58+
/// #[automatically_derived] // 1
59+
/// mod v1alpha1 { // 2
60+
/// use super::*; // 3
61+
/// pub struct Foo {
62+
/// bar: usize,
63+
/// }
64+
/// }
65+
/// ```
66+
/// </details>
67+
///
68+
/// ### Deprecation of a Version
3969
///
40-
/// Before any of the fields can be versioned, versions need to be declared at
41-
/// the container level. Each version currently supports two parameters: `name`
42-
/// and the `deprecated` flag. The `name` must be a valid (and supported)
43-
/// format. The macro checks each declared version and reports any error
44-
/// encountered during parsing.
4570
/// The `deprecated` flag marks the version as deprecated. This currently adds
4671
/// the `#[deprecated]` attribute to the appropriate piece of code.
4772
///
4873
/// ```
4974
/// # use stackable_versioned_macros::versioned;
50-
/// #[versioned(
51-
/// version(name = "v1alpha1", deprecated)
52-
/// )]
53-
/// struct Foo {}
75+
/// #[versioned(version(name = "v1alpha1", deprecated))]
76+
/// struct Foo {
77+
/// bar: usize,
78+
/// }
79+
/// ```
80+
///
81+
/// <details>
82+
/// <summary>Generated code</summary>
83+
///
84+
/// 1. The `deprecated` flag will generate a `#[deprecated]` attribute and the
85+
/// note is automatically generated.
86+
///
87+
/// ```ignore
88+
/// #[automatically_derived]
89+
/// #[deprecated = "Version v1alpha1 is deprecated"] // 1
90+
/// mod v1alpha1 {
91+
/// use super::*;
92+
/// pub struct Foo {
93+
/// pub bar: usize,
94+
/// }
95+
/// }
5496
/// ```
97+
/// </details>
98+
///
99+
/// ### Version Sorting
55100
///
56101
/// Additionally, it is ensured that each version is unique. Declaring the same
57102
/// version multiple times will result in an error. Furthermore, declaring the
@@ -65,37 +110,94 @@ mod consts;
65110
/// version(name = "v1alpha1"),
66111
/// options(allow_unsorted)
67112
/// )]
68-
/// struct Foo {}
113+
/// struct Foo {
114+
/// bar: usize,
115+
/// }
69116
/// ```
70117
///
71-
/// ### Field Actions
118+
/// ## Item Actions
72119
///
73-
/// This library currently supports three different field actions. Fields can
120+
/// This library currently supports three different item actions. Items can
74121
/// be added, renamed and deprecated. The macro ensures that these actions
75122
/// adhere to the following set of rules:
76123
///
77-
/// - Fields cannot be added and deprecated in the same version.
78-
/// - Fields cannot be added and renamed in the same version.
79-
/// - Fields cannot be renamed and deprecated in the same version.
80-
/// - Fields added in version _a_, renamed _0...n_ times in versions
81-
/// b<sub>1</sub>, b<sub>2</sub>, ..., b<sub>n</sub> and deprecated in
82-
/// version _c_ must ensure _a < b<sub>1</sub>, b<sub>2</sub>, ...,
83-
/// b<sub>n</sub> < c_.
84-
/// - All field actions must use previously declared versions. Using versions
85-
/// not present at the container level will result in an error.
124+
/// 1. Items cannot be added and deprecated in the same version.
125+
/// 2. Items cannot be added and changed in the same version.
126+
/// 3. Items cannot be changed and deprecated in the same version.
127+
/// 4. Items added in version _a_, renamed _0...n_ times in versions
128+
/// b<sub>1</sub>, ..., b<sub>n</sub> and deprecated in
129+
/// version _c_ must ensure _a < b<sub>1</sub>, ..., b<sub>n</sub> < c_.
130+
/// 5. All item actions must use previously declared versions. Using versions
131+
/// not present at the container level will result in an error.
86132
///
87-
/// For fields marked as deprecated, two additional rules apply:
133+
/// For items marked as deprecated, one additional rule applies:
88134
///
89-
/// - Fields must start with the `deprecated_` prefix.
90-
/// - The deprecation note cannot be empty.
135+
/// - Fields must start with the `deprecated_` and variants with the
136+
/// `Deprecated` prefix. This is enforced because Kubernetes doesn't allow
137+
/// removing fields in CRDs entirely. Instead, they should be marked as
138+
/// deprecated. By convention this is done with the `deprecated` prefix.
91139
///
92-
/// ### Auto-generated [`From`] Implementations
140+
/// ### Added Action
141+
///
142+
/// This action indicates that a item is added in a particular version.
143+
/// Available parameters are:
93144
///
94-
/// To enable smooth version upgrades of the same struct, the macro automatically
95-
/// generates [`From`] implementations. On a high level, code generated for two
96-
/// versions _a_ and _b_, with _a < b_ looks like this: `impl From<a> for b`.
145+
/// - `since` to indicate since which version the item is present.
146+
/// - `default_fn` to customize the default function used to populate the item
147+
/// in auto-generated [`From`] implementations.
148+
///
149+
/// ```
150+
/// # use stackable_versioned_macros::versioned;
151+
/// #[versioned(version(name = "v1alpha1"), version(name = "v1beta1"))]
152+
/// pub struct Foo {
153+
/// #[versioned(added(since = "v1beta1"))]
154+
/// bar: usize,
155+
/// baz: bool,
156+
/// }
157+
/// ```
158+
///
159+
/// <details>
160+
/// <summary>Generated code</summary>
161+
///
162+
/// 1. The field `bar` is not yet present in version `v1alpha1` and is therefore
163+
/// not generated.
164+
/// 2. Now the field `bar` is present in version `v1beta1`.
97165
///
98166
/// ```ignore
167+
/// pub mod v1alpha1 {
168+
/// use super::*;
169+
/// pub struct Foo { // 1
170+
/// pub baz: bool,
171+
/// }
172+
/// }
173+
///
174+
/// pub mod v1beta1 {
175+
/// use super::*;
176+
/// pub struct Foo {
177+
/// pub bar: usize, // 2
178+
/// pub baz: bool,
179+
/// }
180+
/// }
181+
/// ```
182+
/// </details>
183+
///
184+
/// ### Changed Action
185+
///
186+
/// TODO.
187+
///
188+
/// ### Deprecated Action
189+
///
190+
/// TODO.
191+
///
192+
/// ### Auto-generated [`From`] Implementations
193+
///
194+
/// To enable smooth version upgrades of the same container, the macro
195+
/// automatically generates [`From`] implementations. On a high level, code
196+
/// generated for two versions _a_ and _b_, with _a < b_ looks like this:
197+
/// `impl From<a> for b`.
198+
///
199+
/// ```
200+
/// # use stackable_versioned_macros::versioned;
99201
/// #[versioned(
100202
/// version(name = "v1alpha1"),
101203
/// version(name = "v1beta1"),
@@ -104,62 +206,78 @@ mod consts;
104206
/// pub struct Foo {
105207
/// #[versioned(
106208
/// added(since = "v1beta1"),
107-
/// deprecated(since = "v1", note = "not needed")
209+
/// deprecated(since = "v1")
108210
/// )]
109211
/// deprecated_bar: usize,
110212
/// baz: bool,
111213
/// }
214+
/// ```
112215
///
113-
/// // Produces ...
216+
/// <details>
217+
/// <summary>Generated code</summary>
114218
///
115-
/// #[automatically_derived]
219+
/// 1. The field `bar` is not yet present in version `v1alpha1` and is therefore
220+
/// not generated.
221+
/// 2. Now the field `bar` is present and uses `Default::default()` to populate
222+
/// the field during conversion. This function can be customized as shown
223+
/// later in this guide.
224+
/// 3. In version `v1` the field `bar` is deprecated and as such includes the
225+
/// `deprecated_` prefix. Additionally, the `#[deprecated]` attribute is
226+
/// added to indicate that this part of the Rust code is deprecated. The
227+
/// note is optional.
228+
///
229+
/// ```ignore
116230
/// pub mod v1alpha1 {
117-
/// pub struct Foo {
231+
/// use super::*;
232+
/// pub struct Foo { // 1
118233
/// pub baz: bool,
119234
/// }
120235
/// }
121-
/// #[automatically_derived]
122-
/// #[allow(deprecated)]
236+
///
123237
/// impl From<v1alpha1::Foo> for v1beta1::Foo {
124238
/// fn from(__sv_foo: v1alpha1::Foo) -> Self {
125239
/// Self {
126-
/// bar: std::default::Default::default(),
240+
/// bar: ::std::default::Default::default(), // 2
127241
/// baz: __sv_foo.baz,
128242
/// }
129243
/// }
130244
/// }
131-
/// #[automatically_derived]
245+
///
132246
/// pub mod v1beta1 {
247+
/// use super::*;
133248
/// pub struct Foo {
134249
/// pub bar: usize,
135250
/// pub baz: bool,
136251
/// }
137252
/// }
138-
/// #[automatically_derived]
139-
/// #[allow(deprecated)]
253+
///
140254
/// impl From<v1beta1::Foo> for v1::Foo {
141255
/// fn from(__sv_foo: v1beta1::Foo) -> Self {
142256
/// Self {
143-
/// deprecated_bar: __sv_foo.bar,
257+
/// deprecated_bar: __sv_foo.bar, // 3
144258
/// baz: __sv_foo.baz,
145259
/// }
146260
/// }
147261
/// }
148-
/// #[automatically_derived]
262+
///
149263
/// pub mod v1 {
264+
/// use super::*;
150265
/// pub struct Foo {
151-
/// #[deprecated = "not needed"]
266+
/// #[deprecated] // 3
152267
/// pub deprecated_bar: usize,
153268
/// pub baz: bool,
154269
/// }
155270
/// }
156271
/// ```
272+
/// </details>
273+
///
274+
/// ### Skip [`From`] Generation
157275
///
158-
/// #### Skip [`From`] generation
276+
/// Generation of auto-generated [`From`] implementations can be skipped at the
277+
/// container and version level. This enables customization of the
278+
/// implementations if the default implementation is not sufficient.
159279
///
160-
/// Generation of these [`From`] implementations can be skipped at the container
161-
/// and version level. This enables customization of the implementations if the
162-
/// default implementation is not sufficient.
280+
/// #### Skipping at the Container Level
163281
///
164282
/// ```
165283
/// # use stackable_versioned_macros::versioned;
@@ -179,7 +297,7 @@ mod consts;
179297
/// }
180298
/// ```
181299
///
182-
/// #### Customize Default Function for Added Fields
300+
/// ### Customize Default Function for Added Fields
183301
///
184302
/// It is possible to customize the default function used in the generated
185303
/// [`From`] implementation for populating added fields. By default,

crates/stackable-versioned/src/lib.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,6 @@
33
//! data type. This will be extended to support SemVer versions, as well as
44
//! custom version formats in the future.
55
//!
6-
//! ## Usage Guide
7-
//!
8-
//! ```
9-
//! use stackable_versioned::versioned;
10-
//!
11-
//! #[versioned(
12-
//! version(name = "v1alpha1"),
13-
//! version(name = "v1beta1"),
14-
//! version(name = "v1"),
15-
//! version(name = "v2"),
16-
//! version(name = "v3")
17-
//! )]
18-
//! struct Foo {
19-
//! /// My docs
20-
//! #[versioned(
21-
//! added(since = "v1beta1"),
22-
//! changed(since = "v1", from_name = "gau"),
23-
//! deprecated(since = "v2", note = "not empty")
24-
//! )]
25-
//! deprecated_bar: usize,
26-
//! baz: bool,
27-
//! }
28-
//! ```
29-
//!
306
//! See [`versioned`] for an in-depth usage guide and a list of supported
317
//! parameters.
328

0 commit comments

Comments
 (0)