zeroable/
zeroable_docs.rs

1/*!
2Documentation for the `Zeroable` derive macro.
3
4This macro is for deriving the
5[`bytemuck::Zeroable` trait](https://docs.rs/bytemuck/1/bytemuck/trait.Zeroable.html).
6
7
8# Restrictions
9
10All of these restrictions are enforced at compile-time.
11
12### Structs
13
14All fields are required to implement Zeroable.
15
16```rust
17use zeroable::Zeroable;
18
19#[derive(Zeroable)]
20struct AStruct{
21    left:u32,
22    right:u32,
23}
24```
25
26### Enums
27
28Enums must satisfy one of these:
29
30- Having a `#[repr(C/u8/i8/u16/i16/u32/i32/u64/i64/u128/i128/usize/isize)]` attribute,
31    with either an implicit discriminant for the first variant (which is always `0`),
32    or an explicit `0` discriminant for some variant.
33    <br>
34    The fields of the variant with a `0` discriminant will then be required to
35    implement Zeroable,while the fields of other variants won't be.
36
37- Having a `#[repr(transparent)]` attribute,with a single variant and field,
38    which must implement Zeroable.
39
40### Unions
41
42All fields are required to implement Zeroable by default,
43opting out of Zeroable for fields individually with `#[zero(nonzero)]`.
44
45The alternative to using the `#[zero(nonzero)]` attribute on fields is
46to use the `#[zero(nonzero_fields)]` attribute on the union
47(which makes not requiring zeroable for fields the default for that union),
48then using the `#[zero(zeroable)]` attribute on zeroable fields.
49
50Zeroable impls for unions have documentation mentioning
51which fields were marked as zeroable,and which are not.
52
53# Attributes
54
55These are all the attributes for the derive macro,grouped by where they can be used.
56
57## Container attributes
58
59##### `#[zero(bound="Type:ATrait")]`
60
61Adds a contraint to the `Zeroable` impl.
62
63##### `#[zero(not_zeroable(TypeParamA,TypeParamB,TypeParamC))]`
64
65Removes the default `Zeroable` bound for one/many type parameters.
66
67##### `#[zero(nonzero_fields)]`
68
69For unions only.
70
71Marks all the fields as not being zeroable,
72removing the assertion that they implement Zeroable,
73requiring some fields to have a `#[zero(zeroable)]` attribute.
74
75##### `#[zero(debug_print)]`
76
77Prints the generated code,stopping compilation.
78
79## Field attributes
80
81##### `#[zero(zeroable)]`
82
83For unions only.
84
85Marks the field as being initializable with zeroes,
86adding an assertion that it implements Zeroable.
87
88The field is then mentioned in the generated documentation for
89the Zeroable impl under `Zeroable Fields`.
90
91##### `#[zero(nonzero)]`
92
93For unions only.
94
95Marks the field as not being initializable with zeroes,
96removing the assertion that it implements Zeroable.
97
98The field is then mentioned in the generated documentation for
99the Zeroable impl under `NonZero Fields`.
100
101# Examples
102
103### Enum
104
105A Result-like enum,with `Ok` as the variant instantiated by `zeroed`.
106
107```rust
108use zeroable::Zeroable;
109
110#[derive(Debug,PartialEq,Zeroable)]
111#[repr(u8)]
112#[zero(not_zeroable(E))]
113enum MyResult<T,E>{
114    Ok(T),
115    Err(E),
116}
117
118assert_eq!( MyResult::<(),String>::zeroed(), MyResult::Ok(()) );
119assert_eq!( MyResult::<bool,Vec<()>>::zeroed(), MyResult::Ok(false) );
120
121// This won't compile because Vec is not zeroable.
122// assert_eq!( MyResult::<Vec<()>,String>::zeroed(), MyResult::Ok(vec![]) );
123
124```
125
126### Enum
127
128A simple Option-like enum.
129
130In this the None variant is the one instantiated by `zeroed`.
131
132`#[zero(not_zeroable(T))]` doesn't cause an error because `T` is not in
133the variant instantiated by `zeroed`
134(if `None` contained a `T`,then it would be an error).
135
136```rust
137use zeroable::Zeroable;
138
139#[derive(Debug,PartialEq,Zeroable)]
140#[repr(u8)]
141#[zero(not_zeroable(T))]
142enum MyOption<T>{
143    None,
144    Some(T)
145}
146
147
148assert_eq!( MyOption::<String>::zeroed(), MyOption::None );
149
150```
151
152### Enum
153
154Here is an Ordering-like enum.
155
156```rust
157use zeroable::Zeroable;
158
159#[derive(Debug,PartialEq,Zeroable)]
160#[repr(i8)]
161enum Ordering{
162    Less=-1,
163    Equal=0,
164    Greater=1,
165}
166
167assert_eq!( Ordering::zeroed(), Ordering::Equal );
168
169```
170
171### Enum (non-compiling)
172
173This doesn't compile because there is no variant with a `0` discriminant.
174
175```compile_fail
176use zeroable::Zeroable;
177
178#[derive(Debug,PartialEq,Zeroable)]
179#[repr(u8)]
180enum Directions{
181    Left=1,
182    Right,
183    Up,
184    Down,
185}
186
187```
188
189### Enum (non-compiling)
190
191This doesn't compile because the first variant contains a `NonZeroU8`,
192which is not zeroable.
193
194```compile_fail
195use zeroable::Zeroable;
196
197use core::num::NonZeroU8;
198
199#[derive(Debug,PartialEq,Zeroable)]
200#[repr(u8)]
201enum NonZeroOrZeroable{
202    NonZero(NonZeroU8),
203    Zeroable(u8),
204}
205
206```
207
208It compiles if you swap the variants:
209```rust
210use zeroable::Zeroable;
211
212use core::num::NonZeroU8;
213
214#[derive(Debug,PartialEq,Zeroable)]
215#[repr(u8)]
216enum NonZeroOrZeroable{
217    Zeroable(u8),
218    NonZero(NonZeroU8),
219}
220
221assert_eq!( NonZeroOrZeroable::zeroed(), NonZeroOrZeroable::Zeroable(0) );
222
223```
224this is because the first variant of an enum implicitly has a `0` discriminant,
225and `u8` is zeroable.
226
227### Enum (requires nightly)
228
229This is an example of a `#[repr(transparent)]` enum.
230
231*/
232#![cfg_attr(feature="nightly_docs",doc="```rust")]
233#![cfg_attr(not(feature="nightly_docs"),doc="```ignore")]
234/*!
235#![feature(transparent_enums)]
236
237use zeroable::Zeroable;
238
239#[derive(Debug,PartialEq,Zeroable)]
240#[repr(transparent)]
241enum Wrapper<T>{
242    Value(T),
243}
244
245assert_eq!( Wrapper::<isize>::zeroed(), Wrapper::Value(0_isize) );
246assert_eq!( Wrapper::<usize>::zeroed(), Wrapper::Value(0_usize) );
247assert_eq!( Wrapper::<(usize,usize)>::zeroed(), Wrapper::Value((0_usize,0_usize)) );
248```
249
250### Enum (requires nightly) (non-compiling)
251
252This is an example that fixes a non-compiling enum by setting the discriminant
253of a variant to 0.
254
255*/
256#![cfg_attr(feature="nightly_docs",doc="```compile_fail")]
257#![cfg_attr(not(feature="nightly_docs"),doc="```ignore")]
258/*!
259use zeroable::Zeroable;
260
261use std::error::Error;
262
263#[derive(Debug,Zeroable)]
264#[repr(i8)]
265enum MyError{
266    PageNotFound{name:String},
267    Undefined,
268    Other(Box<dyn Error>)
269}
270```
271This fails to compile because String isn't zeroable,
272so let's change the variant with a zero discriminant to `Undefined`
273
274*/
275#![cfg_attr(feature="nightly_docs",doc="```rust")]
276#![cfg_attr(not(feature="nightly_docs"),doc="```ignore")]
277/*!
278#![feature(arbitrary_enum_discriminant)]
279
280use zeroable::Zeroable;
281
282use std::error::Error;
283
284#[derive(Debug,Zeroable)]
285#[repr(i8)]
286enum MyError{
287    PageNotFound{name:String}=-1,
288    Undefined=0,
289    Other(Box<dyn Error>),
290}
291```
292The first variant has to have an explicit discriminant,
293because otherwise it uses `0` as its discriminant,
294causing a compile time error.
295
296### Struct
297
298A Rectangle type.
299
300```rust
301use zeroable::Zeroable;
302
303#[derive(Debug,PartialEq,Zeroable)]
304struct Rectangle<T>{
305    x:T,
306    y:T,
307    w:T,
308    h:T,
309}
310
311assert_eq!( Rectangle::zeroed(), Rectangle{ x:0, y:0, w:0, h:0 } );
312
313```
314
315### Struct
316
317Here we define a binary tree of zeroable with indices instead of pointers:
318
319```
320use zeroable::Zeroable;
321
322use core::num::NonZeroU32;
323
324#[derive(Debug,PartialEq)]
325struct Tree<T>{
326    list:Vec<TreeNode<T>>,
327}
328
329#[derive(Debug,PartialEq,Zeroable)]
330struct TreeNode<T>{
331    value:T,
332    left:Option<NonZeroU32>,
333    right:Option<NonZeroU32>,
334}
335
336assert_eq!(
337    TreeNode::<[u8;32]>::zeroed(),
338    TreeNode{
339        value:[0;32],
340        left:None,
341        right:None,
342    },
343);
344
345```
346
347### Struct (non-compiling)
348
349This doesn't compile because `&[T]` is not zeroable.
350
351```compile_fail
352use zeroable::Zeroable;
353
354#[derive(Debug,PartialEq,Zeroable)]
355struct NonEmptySlice<'a,T>{
356    slice:&'a [T],
357}
358
359```
360
361### Union
362
363```rust
364use zeroable::Zeroable;
365
366#[derive(Zeroable)]
367#[repr(C)] // This isn't necessary for Zeroable
368union U32OrArray{
369    num:u32,
370    arr:[u8;4],
371}
372
373unsafe{
374    let zeroed=U32OrArray::zeroed();
375
376    assert_eq!( zeroed.num, 0 );
377
378    assert_eq!( zeroed.arr, [0;4] );
379}
380```
381
382### Union
383
384```rust
385use zeroable::Zeroable;
386
387#[derive(Zeroable)]
388#[zero(not_zeroable(T))]
389#[zero(nonzero_fields)]
390union CondValue<T:Copy>{
391    #[zero(zeroable)]
392    cond:bool,
393    value:T,
394}
395
396unsafe{
397    let zeroed=CondValue::<&'static str>::zeroed();
398    assert_eq!( zeroed.cond, false );
399    // You can't read from `zeroed.value` because a reference can't be zeroed.
400}
401unsafe{
402    let zeroed=CondValue::<char>::zeroed();
403    assert_eq!( zeroed.cond, false );
404    assert_eq!( zeroed.value, '\0' );
405}
406```
407
408### Union (requires nightly)
409
410This is an example of a `#[repr(transparent)]` union.
411
412*/
413#![cfg_attr(feature="nightly_docs",doc="```rust")]
414#![cfg_attr(not(feature="nightly_docs"),doc="```ignore")]
415/*!
416#![feature(transparent_unions)]
417
418use zeroable::Zeroable;
419
420#[derive(Zeroable)]
421#[repr(transparent)]
422union Wrapper<T:Copy>{
423    value:T,
424}
425
426unsafe{
427    assert_eq!( Wrapper::<isize>::zeroed().value, 0_isize );
428    assert_eq!( Wrapper::<usize>::zeroed().value, 0_usize );
429    assert_eq!( Wrapper::<(usize,usize)>::zeroed().value, (0_usize,0_usize) );
430}
431```
432
433### Union (non-compiling)
434
435This doesn't compile because `ManuallyDrop<T>` is not zeroable.
436
437```compile_fail
438use zeroable::Zeroable;
439
440use core::mem::ManuallyDrop;
441
442#[derive(Zeroable)]
443#[zero(not_zeroable(T))]
444union MaybeUninitialized<T:Copy>{
445    uninit:(),
446    init:ManuallyDrop<T>,
447}
448```
449
450To fix it simply remove the default `Zeroable` bound on the field like this:
451```
452use zeroable::Zeroable;
453
454use core::mem::ManuallyDrop;
455
456#[derive(Zeroable)]
457#[zero(not_zeroable(T))]
458union MaybeUninitialized<T:Copy>{
459    uninit:(),
460    #[zero(nonzero)]
461    init:ManuallyDrop<T>,
462}
463```
464
465
466
467### Union (non-compiling)
468
469This doesn't compile because the union has a `#[zero(nonzero_fields)]` attribute,
470but no field has a `#[zero(zeroable)]` attribute.
471
472```compile_fail
473use zeroable::Zeroable;
474
475use core::mem::ManuallyDrop;
476
477#[derive(Zeroable)]
478#[zero(not_zeroable(T))]
479#[zero(nonzero_fields)]
480union UnsafeEither<T:Copy,U:Copy>{
481    left:T,
482    right:U,
483}
484```
485
486To fix this instance simply add a `#[zero(zeroable)]` attribute to a field like this:
487```
488use zeroable::Zeroable;
489
490use core::mem::ManuallyDrop;
491
492#[derive(Zeroable)]
493#[zero(not_zeroable(T))]
494#[zero(nonzero_fields)]
495union UnsafeEither<T:Copy,U:Copy>{
496    left:T,
497    #[zero(zeroable)]
498    right:U,
499}
500```
501
502
503
504*/