abi_stable/docs/sabi_nonexhaustive.rs
1/*!
2
3Using the `#[sabi(kind(WithNonExhaustive(...)))]` helper attribute for
4`#[derive(StableAbi)]` allows you to store the enum
5in `NonExhaustive`,
6using it as a non-exhaustive enum across ffi.
7
8The enum can then be wrapped in a
9[`NonExhaustive<>`](../../nonexhaustive_enum/struct.NonExhaustive.html),
10but can only be converted back into it if the discriminant is valid in that context.
11
12Nonexhaustive enums can safely add variants in minor versions,
13giving library authors some flexibility in their design.
14
15# Items
16
17These are the items relevant to nonexhaustive enums:
18
19`Enum`: this is the annotated enum,which does not derive `StableAbi`,
20requiring it to be wrapped in a `NonExhaustive<>` to be passed through ffi.
21
22`Enum_NE`(generated): A type alias for `NonExhaustive<Enum,_,_>`.
23
24`Enum_NEMarker`(generated):
25A marker type which implements StableAbi with the layout of `Enum`,
26used as a phantom field of NonExhaustive.
27
28`Enum_Storage`(generated):
29A type used as storage space by the `NonExhaustive<>` type to store the enum.
30
31`Enum_Bounds`(generated):
32Acts as an alias for the traits that were specified in the `traits(...)` parameter.
33This is only created if the `traits(...)` parameter is specified.
34
35`Enum_Interface`(generated):
36Describes the traits required when constructing a `NonExhaustive<Enum,_,_>`
37and usable with it afterwards
38(this is a type that implements [`InterfaceType`]).
39
40# Parameters
41
42These are the required and optional parameters for the
43`#[sabi(kind(WithNonExhaustive(...)))]` helper attribute.
44
45### Specifying alignment (optional parameter)
46
47Specifies the alignment of Enum_Storage.
48
49With a specific alignemnt.<br>
50Syntax:`align = integer_literal`<br>
51Example:`align = 8`<br>
52A non-literal constant expression can also be used:<br>
53Syntax:`align = { (<statement>;)* <expression> }`<br>
54Example:`align = { foo() }` <br>
55
56With the same alignment is that of another type.<br>
57Syntax:`align = type`<br>
58Example:`align = usize`<br>
59
60### size (required parameter)
61
62Specifies the size of Enum_Storage.
63
64The size of Enum_TE in bytes.<br>
65Syntax:`size=integer_literal`<br>
66Example:`size = 8` <br>
67A non-literal constant expression can also be used:<br>
68Syntax:`size = { (<statement>;)* <expression> }`<br>
69Example:`size = { foo() }` <br>
70
71The size of Enum_TE is that of of another type<br>
72Syntax:`size = type`<br>
73Example:`size = [usize;8]`<br>
74Recommendation:
75Use a type that has a stable layout,generally a concrete type.
76It is a bad idea to use `Enum` since its size is allowed to change.<br>
77
78### Traits (optional parameter)
79
80Specifies the traits required when constructing NonExhaustive from this enum and
81usable after constructing it.
82
83If neither this parameter nor interface are specified,
84no traits will be required in `NonExhaustive<>` and none will be usable.
85
86Syntax:`traits(trait0, trait1 = false, trait2 = true, trait3)`
87
88Example0:`traits(Debug,Display)`<br>
89Example1:`traits(Sync = false, Debug,Display)`<br>
90Example2:`traits(Sync = false, Send = false, Debug, Display)`<br>
91Example3:`traits(Clone, Debug, Display, Error)`<br>
92
93All the traits are optional.
94
95These are the valid traits:
96
97- `Send`: Required by default, must be unrequired with `Send = false`
98
99- `Sync`: Required by default, must be unrequired with `Sync = false`
100
101- `Clone`
102
103- `Debug`
104
105- `Display`
106
107- `Serialize`: `serde::Serialize`.Look below for clarifications on how to use serde.
108
109- `Deserialize`: `serde::Deserialize`.Look below for clarifications on how to use serde.
110
111- `Eq`
112
113- `PartialEq`
114
115- `Ord`
116
117- `PartialOrd`
118
119- `Hash`
120
121- `Error`: `std::error::Error`
122
123### Interface (optional parameter)
124
125This allows using a pre-existing to specify which traits are
126required when constructing `NonExhaustive<>` from this enum and are then usable with it.
127
128The type describes which traits are required using the [`InterfaceType`] trait.
129
130Syntax:`interface=type`
131
132Example0:`interface = ()`.
133This means that no trait is usable/required.<br>
134
135Example1:`interface = CloneInterface`.
136This means that only Clone is usable/required.<br>
137
138Example2:`interface = PartialEqInterface`.
139This means that only Debug/PartialEq are usable/required.<br>
140
141Example3:`interface = CloneEqInterface`.
142This means that only Debug/Clone/Eq/PartialEq are usable/required.<br>
143
144The `*Interface` types from the examples come from the
145`abi_stable::erased_types::interfaces` module.
146
147
148### NonExhaustive assertions
149
150This generates a static assertion that the listed types can be stored within `NonExhaustive`.
151
152Note that this attribute is implicitly added for non-generic enums,
153it is only required for generic enums.
154
155Syntax:`assert_nonexhaustive = type`<br>
156Example:`assert_nonexhaustive = Foo<u8>`<br>
157Example:`assert_nonexhaustive = Foo<RArc<u8>>`<br>
158Example:`assert_nonexhaustive = Foo<RBox<u8>>`<br>
159
160Syntax:`assert_nonexhaustive(type0, type1)`<br>
161Example:`assert_nonexhaustive(Foo<RArc<u8>>)`<br>
162Example:`assert_nonexhaustive(Foo<u8>, Foo<RVec<()>>)`<br>
163
164[full example below](#using_assert_nonexhaustive_example)
165
166# `serde` support
167
168`NonExhaustive<Enum, Storage, Interface>` only implements `serde::{Serialize,Deserialize}`
169if `Interface` allows them in its [`InterfaceType`] implementation,
170and also implements the [`SerializeEnum`] and [`DeserializeEnum`] traits.
171
172# Examples
173
174### Defining a (de)serializable nonexhaustive enum.
175
176This defines a nonexhaustive enum and demonstrates how it is (de)serialized.
177
178For a more realistic example you can look at the
179"examples/2_nonexhaustive/interface" crate in the repository for this crate.
180
181```
182use abi_stable::{
183 external_types::{RawValueBox, RawValueRef},
184 nonexhaustive_enum::{DeserializeEnum, NonExhaustive, SerializeEnum},
185 prefix_type::WithMetadata,
186 sabi_extern_fn,
187 std_types::{RBoxError, RErr, ROk, RResult, RStr, RString},
188 StableAbi,
189};
190
191use serde::{Deserialize, Serialize};
192
193#[repr(u8)]
194#[derive(StableAbi, Debug, Clone, PartialEq, Deserialize, Serialize)]
195#[sabi(kind(WithNonExhaustive(
196 // Determines the maximum size of this enum in semver compatible versions.
197 size = [usize;10],
198 // Determines the traits that are required when wrapping this enum in NonExhaustive,
199 // and are then available with it.
200 traits(Debug,Clone,PartialEq,Serialize,Deserialize),
201)))]
202// The `#[sabi(with_constructor)]` helper attribute here generates constructor functions
203// that look take the fields of the variant as parameters and return a `ValidTag_NE`.
204#[sabi(with_constructor)]
205#[non_exhaustive]
206pub enum ValidTag {
207 Foo,
208 Bar,
209 Tag {
210 name: RString,
211 tag: RString,
212 },
213}
214
215/*
216//This was generated by the StableAbi derive macro on ValidTag.
217pub type ValidTag_NE=
218 NonExhaustive<
219 ValidTag,
220 ValidTag_Storage,
221 ValidTag_Interface,
222 >;
223*/
224
225/// This describes how the enum is serialized.
226impl SerializeEnum<ValidTag> for ValidTag_Interface {
227 /// A type that `ValidTag` is converted into(inside `SerializeEnum::serialize_enum`),
228 /// and then serialized.
229 type Proxy = RawValueBox;
230
231 fn serialize_enum(this: &ValidTag) -> Result<RawValueBox, RBoxError> {
232 match serde_json::value::to_raw_value(this) {
233 Ok(v) => Ok(v.into()),
234 Err(e) => Err(RBoxError::new(e)),
235 }
236 }
237}
238
239/// This describes how the enum is deserialized.
240impl<'a> DeserializeEnum<'a, ValidTag_NE> for ValidTag_Interface {
241 /// A type that is deserialized,
242 /// and then converted into `ValidTag_NE` inside `DeserializeEnum::deserialize_enum`.
243 type Proxy = RawValueRef<'a>;
244
245 fn deserialize_enum(s: RawValueRef<'a>) -> Result<ValidTag_NE, RBoxError> {
246 Module::VALUE.deserialize_tag()(s.get_rstr()).into_result()
247 }
248}
249
250# fn main(){
251
252assert_eq!(
253 serde_json::from_str::<ValidTag_NE>(r#""Foo""#).unwrap(),
254 ValidTag::Foo_NE()
255);
256
257assert_eq!(
258 serde_json::from_str::<ValidTag_NE>(r#""Bar""#).unwrap(),
259 ValidTag::Bar_NE()
260);
261
262assert_eq!(
263 serde_json::from_str::<ValidTag_NE>(
264 r#"
265 {"Tag":{
266 "name":"what",
267 "tag":"the"
268 }}
269"#
270 )
271 .unwrap(),
272 ValidTag::Tag_NE("what".into(), "the".into())
273);
274
275assert_eq!(
276 &serde_json::to_string(&ValidTag::Foo_NE()).unwrap(),
277 r#""Foo""#,
278);
279
280assert_eq!(
281 &serde_json::to_string(&ValidTag::Bar_NE()).unwrap(),
282 r#""Bar""#,
283);
284
285# }
286
287// In this struct:
288//
289// - `#[sabi(kind(Prefix))]`
290// Declares this type as being a prefix-type, generating both of these types:
291//
292// - Module_Prefix`: A struct with the fields up to (and including) the field with the
293// `#[sabi(last_prefix_field)]` attribute.
294//
295// - Module_Ref`: An ffi-safe pointer to a `Module`,with methods to get `Module`'s fields.
296//
297// - `#[sabi(missing_field(panic))]`
298// makes the field accessors of `ModuleRef` panic when attempting to
299// access nonexistent fields instead of the default of returning an Option<FieldType>.
300//
301#[repr(C)]
302#[derive(StableAbi)]
303#[sabi(kind(Prefix))]
304#[sabi(missing_field(panic))]
305pub struct Module {
306 /// `#[sabi(last_prefix_field)]`means that it is the last field in the struct
307 /// that was defined in the first compatible version of the library
308 /// (0.1.0, 0.2.0, 0.3.0, 1.0.0, 2.0.0 ,etc),
309 /// requiring new fields to always be added below preexisting ones.
310 #[sabi(last_prefix_field)]
311 pub deserialize_tag:
312 extern "C" fn(s: RStr<'_>) -> RResult<ValidTag_NE, RBoxError>,
313}
314
315// This is how you can construct `Module` in a way that allows it to become generic later.
316impl Module {
317 // This macro declares a `StaticRef<WithMetadata<BoxVtable<T>>>` constant.
318 //
319 // StaticRef represents a reference to data that lives forever,
320 // but is not necessarily `'static` according to the type system.
321 //
322 // StaticRef not necessary in this case, it's more useful with generic types..
323 abi_stable::staticref!(const TMP0: WithMetadata<Self> = WithMetadata::new(
324 Self{
325 deserialize_tag,
326 },
327 ));
328
329 const VALUE: Module_Ref = Module_Ref(Self::TMP0.as_prefix());
330}
331
332/////////////////////////////////////////////////////////////////////////////////////////
333//// In implementation crate (the one that gets compiled as a dynamic library) /////
334/////////////////////////////////////////////////////////////////////////////////////////
335
336#[sabi_extern_fn]
337pub fn deserialize_tag(s: RStr<'_>) -> RResult<ValidTag_NE, RBoxError> {
338 match serde_json::from_str::<ValidTag>(s.into()) {
339 Ok(x) => ROk(NonExhaustive::new(x)),
340 Err(e) => RErr(RBoxError::new(e)),
341 }
342}
343
344```
345
346### Boxing variants of unknown size
347
348This example demonstrates how one can use boxing to store types larger than `[usize;2]`
349(the size of `RBox<_>`),
350because one of the variant contains a generic type.
351
352
353
354```
355use abi_stable::{
356 nonexhaustive_enum::{NonExhaustive, NonExhaustiveFor},
357 sabi_trait,
358 std_types::{RBox, RString},
359 StableAbi,
360};
361
362use std::{
363 cmp::PartialEq,
364 fmt::{self, Debug, Display},
365};
366
367#[repr(u8)]
368#[derive(StableAbi, Debug, Clone, PartialEq)]
369#[sabi(kind(WithNonExhaustive(
370 size = [usize;3],
371 traits(Debug, Display, Clone, PartialEq),
372)))]
373#[non_exhaustive]
374pub enum Message<T> {
375 SaysHello,
376 SaysGoodbye,
377
378 #[sabi(with_boxed_constructor)]
379 Custom(RBox<T>),
380
381 ////////////////////////////////////////
382 // Available since 1.1
383 ////////////////////////////////////////
384 #[sabi(with_boxed_constructor)]
385 SaysThankYou(RBox<SaysThankYou>),
386}
387
388impl<T> Display for Message<T>
389where
390 T: Display,
391{
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 match self {
394 Message::SaysHello => write!(f, "Hello!"),
395 Message::SaysGoodbye => write!(f, "Goodbye!"),
396 Message::Custom(custom) => Display::fmt(&**custom, f),
397 Message::SaysThankYou(x) => writeln!(f, "Thank you,{}!", x.to),
398 _ => unreachable!(),
399 }
400 }
401}
402
403// Only available since 1.1
404#[repr(C)]
405#[derive(StableAbi, Debug, Clone, PartialEq)]
406pub struct SaysThankYou {
407 to: RString,
408}
409
410# fn main(){
411
412// Constructing Message::Custom wrapped in a NonExhaustive
413{
414 let custom_message: Message_NE<RString> = Message::Custom_NE("Hello".into());
415
416 let custom_message_desugar: Message_NE<RString> = {
417 let x = RBox::new("Hello".into());
418 let x = Message::Custom(x);
419 NonExhaustive::new(x)
420 };
421
422 assert_eq!(custom_message, custom_message_desugar);
423}
424
425// Constructing Message::SaysThankYou wrapped in a NonExhaustive
426// This variant is only available since 1.1
427{
428 let says_thank_you: Message_NE<RString> =
429 Message::SaysThankYou_NE(SaysThankYou { to: "Hello".into() });
430
431 let says_thank_you_desugar: Message_NE<RString> = {
432 let x = SaysThankYou { to: "Hello".into() };
433 let x = Message::SaysThankYou(RBox::new(x));
434 NonExhaustive::new(x)
435 };
436
437 assert_eq!(says_thank_you, says_thank_you_desugar);
438}
439
440# }
441
442
443```
444
445
446
447### Generic enum with `RSmallBox`
448
449This example shows how one can use RSmallBox to define a generic nonexhausitve enum.
450
451```
452
453use abi_stable::{
454 reexports::SelfOps,
455 sabi_types::RSmallBox,
456 std_types::{RString, RVec},
457 StableAbi,
458};
459
460#[repr(u8)]
461#[derive(StableAbi, Debug, Clone, PartialEq)]
462#[sabi(kind(WithNonExhaustive(
463 // Determines the maximum size of this enum in semver compatible versions.
464 // This is 11 usize large because:
465 // - The enum discriminant occupies 1 usize(because the enum is usize aligned).
466 // - RSmallBox<T,[usize;8]>: is 10 usize large
467 size = [usize;11],
468 // Determines the traits that are required when wrapping this enum in NonExhaustive,
469 // and are then available with it.
470 traits(Debug,Clone,PartialEq),
471)))]
472#[sabi(with_constructor)]
473#[non_exhaustive]
474pub enum SomeEnum<T> {
475 Foo,
476 Bar,
477 Crash {
478 reason: RString,
479 animal: RString,
480 },
481 // This variant was added in a newer (compatible) version of the library.
482 #[sabi(with_boxed_constructor)]
483 Other(RSmallBox<T, [usize; 8]>),
484}
485
486impl<T> SomeEnum<T> {
487 pub fn is_inline(&self) -> bool {
488 match self {
489 SomeEnum::Foo => true,
490 SomeEnum::Bar => true,
491 SomeEnum::Crash { .. } => true,
492 SomeEnum::Other(rsbox) => RSmallBox::is_inline(rsbox),
493 _ => true,
494 }
495 }
496
497 pub fn is_heap_allocated(&self) -> bool {
498 !self.is_inline()
499 }
500}
501
502#[repr(C)]
503#[derive(StableAbi, Debug, Clone, PartialEq)]
504pub struct FullName {
505 pub name: RString,
506 pub surname: RString,
507}
508
509/// A way to represent a frozen `Vec<Vec<T>>`.
510///
511/// This example just constructs NestedVec directly,
512/// realistically it would be constructed in an associated function of NestedVec.
513#[repr(C)]
514#[derive(StableAbi, Debug, Clone, PartialEq)]
515pub struct NestedVec<T> {
516 indices: RVec<usize>,
517 nested: RVec<T>,
518 dummy_field: u32,
519}
520
521# fn main(){
522
523let crash = SomeEnum::<()>::Crash_NE("No reason".into(), "Bandi____".into());
524
525let other_fullname = SomeEnum::Other_NE(FullName {
526 name: "R__e".into(),
527 surname: "L_____e".into(),
528});
529
530let other_nestedlist = {
531 let nestedlist = NestedVec {
532 indices: vec![0, 2, 3, 5].into(),
533 // Each line here is a nested list.
534 nested: vec![false, false, true, true, false, true, true, true].into(),
535 dummy_field: 0,
536 };
537 SomeEnum::Other_NE(nestedlist)
538};
539
540assert!(crash.as_enum().unwrap().is_inline());
541assert!(other_fullname.as_enum().unwrap().is_inline());
542assert!(other_nestedlist.as_enum().unwrap().is_heap_allocated());
543
544# }
545
546
547
548```
549
550### Add variant to "private" enum across versions
551
552Say that we want to define a "private" enum
553(it's exposed to the ABI but it's not public API),
554used internally to send information between instances of the same library,
555of potentially different (compatible) versions.
556
557If one of the variants from newer versions are sent into a library/binary
558that has a previous version of `Event`,
559`Event_NE` (an alias for NonExhaustive wrapping an Event)
560won't be convertible back into `Event`.
561
562```
563use abi_stable::{
564 nonexhaustive_enum::{NonExhaustive, NonExhaustiveFor},
565 sabi_trait,
566 std_types::{RArc, RString},
567 StableAbi,
568};
569
570#[doc(hidden)]
571#[repr(C)]
572#[derive(StableAbi, Debug, Clone, Copy, PartialEq)]
573pub struct ObjectId(pub usize);
574
575#[doc(hidden)]
576#[repr(C)]
577#[derive(StableAbi, Debug, Clone, Copy, PartialEq)]
578pub struct GroupId(pub usize);
579
580#[repr(u8)]
581#[derive(StableAbi, Debug, Clone, PartialEq)]
582#[sabi(kind(WithNonExhaustive(
583 size = [usize;8],
584 traits(Debug, Clone, PartialEq),
585)))]
586#[sabi(with_constructor)]
587#[non_exhaustive]
588pub enum Event {
589 CreatedInstance {
590 object_id: ObjectId,
591 },
592 RemovedInstance {
593 object_id: ObjectId,
594 },
595
596 /////////////////
597 // Added in 1.1
598 /////////////////
599 CreatedGroup {
600 name: RString,
601 group_id: GroupId,
602 },
603 RemovedGroup {
604 name: RString,
605 group_id: GroupId,
606 },
607 AssociatedWithGroup {
608 object_id: ObjectId,
609 group_id: GroupId,
610 },
611
612 /////////////////
613 // Added in 1.2
614 /////////////////
615 RemovedAssociationWithGroup {
616 object_id: ObjectId,
617 group_id: GroupId,
618 },
619 #[sabi(with_boxed_constructor)]
620 DummyVariant {
621 pointer: RArc<()>,
622 },
623}
624
625let objectid_0 = ObjectId(0);
626let objectid_1 = ObjectId(1);
627
628let groupid_0 = GroupId(0);
629let groupid_1 = GroupId(0);
630
631// Constructing a Event::CreatedInstance wrapped in a NonExhaustive
632{
633 let from_ne_constructor: Event_NE = Event::CreatedInstance_NE(objectid_0);
634 let regular = {
635 let ev = Event::CreatedInstance {
636 object_id: objectid_0,
637 };
638 NonExhaustive::new(ev)
639 };
640
641 assert_eq!(from_ne_constructor, regular);
642}
643
644// Constructing a Event::RemovedInstance wrapped in a NonExhaustive
645{
646 let from_ne_constructor = Event::RemovedInstance_NE(objectid_0);
647 let regular = {
648 let ev = Event::RemovedInstance {
649 object_id: objectid_0,
650 };
651 NonExhaustive::new(ev)
652 };
653
654 assert_eq!(from_ne_constructor, regular);
655}
656
657// Constructing a Event::RemovedInstance wrapped in a NonExhaustive
658{
659 let from_ne_constructor = Event::RemovedInstance_NE(objectid_0);
660 let regular = {
661 let ev = Event::RemovedInstance {
662 object_id: objectid_0,
663 };
664 NonExhaustive::new(ev)
665 };
666
667 assert_eq!(from_ne_constructor, regular);
668}
669
670// Constructing a Event::CreatedGroup wrapped in a NonExhaustive
671// This is only available from 1.1
672{
673 let from_ne_constructor = Event::CreatedGroup_NE("hello".into(), groupid_0);
674 let regular = {
675 let ev = Event::CreatedGroup {
676 name: "hello".into(),
677 group_id: groupid_0,
678 };
679 NonExhaustive::new(ev)
680 };
681
682 assert_eq!(from_ne_constructor, regular);
683}
684
685// Constructing a Event::RemovedGroup wrapped in a NonExhaustive
686// This is only available from 1.1
687{
688 let from_ne_constructor = Event::RemovedGroup_NE("hello".into(), groupid_0);
689 let regular = {
690 let ev = Event::RemovedGroup {
691 name: "hello".into(),
692 group_id: groupid_0,
693 };
694 NonExhaustive::new(ev)
695 };
696
697 assert_eq!(from_ne_constructor, regular);
698}
699
700// Constructing a Event::AssociatedWithGroup wrapped in a NonExhaustive
701// This is only available from 1.1
702{
703 let from_ne_constructor = Event::AssociatedWithGroup_NE(objectid_0, groupid_0);
704 let regular = {
705 let ev = Event::AssociatedWithGroup {
706 object_id: objectid_0,
707 group_id: groupid_0,
708 };
709 NonExhaustive::new(ev)
710 };
711
712 assert_eq!(from_ne_constructor, regular);
713}
714
715// Constructing a Event::RemovedAssociationWithGroup wrapped in a NonExhaustive
716// This is only available from 1.2
717{
718 let from_ne_constructor =
719 Event::RemovedAssociationWithGroup_NE(objectid_0, groupid_0);
720 let regular = {
721 let ev = Event::RemovedAssociationWithGroup {
722 object_id: objectid_0,
723 group_id: groupid_0,
724 };
725 NonExhaustive::new(ev)
726 };
727
728 assert_eq!(from_ne_constructor, regular);
729}
730
731// Constructing a Event::DummyVariant wrapped in a NonExhaustive
732// This is only available from 1.2
733{
734 let from_ne_constructor = Event::DummyVariant_NE(());
735 let regular = {
736 let x = RArc::new(());
737 let x = Event::DummyVariant { pointer: x };
738 NonExhaustive::new(x)
739 };
740
741 assert_eq!(from_ne_constructor, regular);
742}
743
744```
745
746
747<span id = "using_assert_nonexhaustive_example"></span>
748### Using `assert_nonexhaustive`
749
750This example demonstrates the `assert_nonexhaustive` helper attribute,
751and the errors produced when the enum is too large or is misaligned for its default storage.
752
753```compile_fail
754use abi_stable::StableAbi;
755
756#[repr(u8)]
757#[derive(StableAbi)]
758#[sabi(kind(WithNonExhaustive(
759 // Determines the maximum size of this enum in semver compatible versions.
760 // maximum size is `size_of::<[u16; 3]>()`
761 size = [u16; 3],
762 // Determines the maximum alignment of this enum in semver compatible versions.
763 // aligned at most `align_of::<u16>()`
764 align = u16,
765 // The below attribute is implied for non-generic enums,
766 // it generates a static assertion checking that `Concrete`
767 // fits within its default storage.
768 // assert_nonexhaustive(Concrete)
769)))]
770#[non_exhaustive]
771pub enum Concrete {
772 Foo,
773 Bar,
774 Tag([u16; 3]),
775}
776
777
778#[repr(u8)]
779#[derive(StableAbi)]
780#[sabi(kind(WithNonExhaustive(
781 // Determines the maximum size of this enum in semver compatible versions.
782 size = 8,
783 // Determines the maximum alignment of this enum in semver compatible versions.
784 // non-literal constants have to be wrapped in braces
785 align = {alignment()},
786 // generic enums don't implicitly assert that the enum is compatible with the
787 // default storage, you must specify the tested concrete types
788 assert_nonexhaustive(Generic<[u16; 4]>, Generic<u32>, Generic<u64>)
789)))]
790#[non_exhaustive]
791pub enum Generic<T> {
792 Foo,
793 Bar,
794 Qux(T),
795}
796
797const fn alignment() -> usize {
798 2
799}
800```
801
802This is the compile-time error for the above code:
803```text
804error[E0080]: evaluation of constant value failed
805 --> src/docs/sabi_nonexhaustive.rs:767:10
806 |
8077 | #[derive(StableAbi)]
808 | ^^^^^^^^^ the evaluated program panicked at '
809The size of the storage is smaller than the contained type:
810 enum_: "Concrete"
811 enum_size: 8
812 enum_alignment: 2
813 storage_: "Concrete_Storage"
814 storage_size: 6
815 storage_alignment: 2
816', src/docs/sabi_nonexhaustive.rs:7:10
817 |
818 = note: this error originates in the derive macro `StableAbi` (in Nightly builds, run with -Z macro-backtrace for more info)
819
820error[E0080]: evaluation of constant value failed
821 --> src/docs/sabi_nonexhaustive.rs:789:10
822 |
82329 | #[derive(StableAbi)]
824 | ^^^^^^^^^ the evaluated program panicked at '
825The size of the storage is smaller than the contained type:
826 enum_: "Generic < [u16 ; 4] >"
827 enum_size: 10
828 enum_alignment: 2
829 storage_: "Generic_Storage"
830 storage_size: 8
831 storage_alignment: 2
832', src/docs/sabi_nonexhaustive.rs:29:10
833 |
834 = note: this error originates in the derive macro `StableAbi` (in Nightly builds, run with -Z macro-backtrace for more info)
835
836error[E0080]: evaluation of constant value failed
837 --> src/docs/sabi_nonexhaustive.rs:789:10
838 |
83929 | #[derive(StableAbi)]
840 | ^^^^^^^^^ the evaluated program panicked at '
841The alignment of the storage is lower than the contained type:
842 enum_: "Generic < u32 >"
843 enum_size: 8
844 enum_alignment: 4
845 storage_: "Generic_Storage"
846 storage_size: 8
847 storage_alignment: 2
848', src/docs/sabi_nonexhaustive.rs:29:10
849 |
850 = note: this error originates in the derive macro `StableAbi` (in Nightly builds, run with -Z macro-backtrace for more info)
851
852error[E0080]: evaluation of constant value failed
853 --> src/docs/sabi_nonexhaustive.rs:789:10
854 |
85529 | #[derive(StableAbi)]
856 | ^^^^^^^^^ the evaluated program panicked at '
857The alignment and size of the storage is smaller than the contained type:
858 enum_: "Generic < u64 >"
859 enum_size: 16
860 enum_alignment: 8
861 storage_: "Generic_Storage"
862 storage_size: 8
863 storage_alignment: 2
864', src/docs/sabi_nonexhaustive.rs:29:10
865 |
866 = note: this error originates in the derive macro `StableAbi` (in Nightly builds, run with -Z macro-backtrace for more info)
867
868error: aborting due to 4 previous errors
869```
870
871
872[`InterfaceType`]: crate::InterfaceType
873[`SerializeEnum`]: crate::nonexhaustive_enum::SerializeEnum
874[`DeserializeEnum`]: crate::nonexhaustive_enum::DeserializeEnum
875
876*/