Skip to content

Commit fac0109

Browse files
authored
Document custom error types in README (#125)
Also fix up heading structures
1 parent 3d96bb2 commit fac0109

File tree

1 file changed

+78
-61
lines changed

1 file changed

+78
-61
lines changed

README.md

Lines changed: 78 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
num_enum
2-
========
1+
# num_enum
32

43
Procedural macros to make inter-operation between primitives and enums easier.
54
This crate is no_std compatible.
@@ -8,8 +7,7 @@ This crate is no_std compatible.
87
[![Documentation](https://docs.rs/num_enum/badge.svg)](https://docs.rs/num_enum)
98
[![Build Status](https://travis-ci.org/illicitonion/num_enum.svg?branch=master)](https://travis-ci.org/illicitonion/num_enum)
109

11-
Turning an enum into a primitive
12-
--------------------------------
10+
## Turning an enum into a primitive
1311

1412
```rust
1513
use num_enum::IntoPrimitive;
@@ -29,8 +27,7 @@ fn main() {
2927

3028
`num_enum`'s `IntoPrimitive` is more type-safe than using `as`, because `as` will silently truncate - `num_enum` only derives `From` for exactly the discriminant type of the enum.
3129

32-
Attempting to turn a primitive into an enum with try_from
33-
----------------------------------------------
30+
## Attempting to turn a primitive into an enum with try_from
3431

3532
```rust
3633
use num_enum::TryFromPrimitive;
@@ -55,8 +52,7 @@ fn main() {
5552
}
5653
```
5754

58-
Variant alternatives
59-
---------------
55+
### Variant alternatives
6056

6157
Sometimes a single enum variant might be representable by multiple numeric values.
6258

@@ -122,43 +118,34 @@ fn main() {
122118
}
123119
```
124120

125-
Default variant
126-
---------------
121+
### Custom error types
127122

128-
Sometimes it is desirable to have an `Other` variant in an enum that acts as a kind of a wildcard matching all the value not yet covered by other variants.
129-
130-
The `#[num_enum(default)]` attribute (or the stdlib `#[default]` attribute) allows you to mark variant as the default.
123+
`TryFromPrimitive` by default will use `num_enum::TryFromPrimitiveError` as its `Error` type.
131124

132-
(The behavior of `IntoPrimitive` is unaffected by this attribute, it will always return the canonical value.)
125+
If you want to use a different type, you can use an annotation for this:
133126

134127
```rust
135-
use num_enum::FromPrimitive;
136-
use std::convert::TryFrom;
128+
use num_enum::TryFromPrimitive;
137129

138-
#[derive(Debug, Eq, PartialEq, FromPrimitive)]
130+
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
131+
#[num_enum(error_type(name = CustomError, constructor = CustomError::new))]
139132
#[repr(u8)]
140-
enum Number {
141-
Zero = 0,
142-
#[num_enum(default)]
143-
NonZero = 1,
133+
enum FirstNumber {
134+
Zero,
135+
One,
136+
Two,
144137
}
145138

146-
fn main() {
147-
let zero = Number::from(0u8);
148-
assert_eq!(zero, Number::Zero);
149-
150-
let one = Number::from(1u8);
151-
assert_eq!(one, Number::NonZero);
139+
struct CustomError {}
152140

153-
let two = Number::from(2u8);
154-
assert_eq!(two, Number::NonZero);
141+
impl CustomError {
142+
fn new(value: u8) -> CustomError {
143+
CustomError {}
144+
}
155145
}
156146
```
157147

158-
Only `FromPrimitive` pays attention to `default` attributes, `TryFromPrimitive` ignores them.
159-
160-
Safely turning a primitive into an exhaustive enum with from_primitive
161-
-------------------------------------------------------------
148+
## Safely turning a primitive into an exhaustive enum with from_primitive
162149

163150
If your enum has all possible primitive values covered, you can derive `FromPrimitive` for it (which auto-implement stdlib's `From`):
164151

@@ -191,8 +178,41 @@ fn main() {
191178
}
192179
```
193180

194-
Catch-all variant
195-
-----------------
181+
### Default variant
182+
183+
Sometimes it is desirable to have an `Other` variant in an enum that acts as a kind of a wildcard matching all the value not yet covered by other variants.
184+
185+
The `#[num_enum(default)]` attribute (or the stdlib `#[default]` attribute) allows you to mark variant as the default.
186+
187+
(The behavior of `IntoPrimitive` is unaffected by this attribute, it will always return the canonical value.)
188+
189+
```rust
190+
use num_enum::FromPrimitive;
191+
use std::convert::TryFrom;
192+
193+
#[derive(Debug, Eq, PartialEq, FromPrimitive)]
194+
#[repr(u8)]
195+
enum Number {
196+
Zero = 0,
197+
#[num_enum(default)]
198+
NonZero = 1,
199+
}
200+
201+
fn main() {
202+
let zero = Number::from(0u8);
203+
assert_eq!(zero, Number::Zero);
204+
205+
let one = Number::from(1u8);
206+
assert_eq!(one, Number::NonZero);
207+
208+
let two = Number::from(2u8);
209+
assert_eq!(two, Number::NonZero);
210+
}
211+
```
212+
213+
Only `FromPrimitive` pays attention to `default` attributes, `TryFromPrimitive` ignores them.
214+
215+
### Catch-all variant
196216

197217
Sometimes it is desirable to have an `Other` variant which holds the otherwise un-matched value as a field.
198218

@@ -224,34 +244,13 @@ fn main() {
224244

225245
As this is naturally exhaustive, this is only supported for `FromPrimitive`, not also `TryFromPrimitive`.
226246

227-
Unsafely turning a primitive into an enum with unchecked_transmute_from
228-
-----------------------------------------------------------------------
247+
## Unsafely turning a primitive into an enum with unchecked_transmute_from
229248

230249
If you're really certain a conversion will succeed (and have not made use of `#[num_enum(default)]` or `#[num_enum(alternatives = [..])]`
231250
for any of its variants), and want to avoid a small amount of overhead, you can use unsafe code to do this conversion.
232251
Unless you have data showing that the match statement generated in the `try_from` above is a bottleneck for you,
233252
you should avoid doing this, as the unsafe code has potential to cause serious memory issues in your program.
234253

235-
Note that this derive ignores any `default`, `catch_all`, and `alternatives` attributes on the enum.
236-
If you need support for conversions from these values, you should use `TryFromPrimitive` or `FromPrimitive`.
237-
238-
- This means, for instance, that the following is UB:
239-
240-
```rust,no_run
241-
use num_enum::UnsafeFromPrimitive;
242-
243-
#[derive(UnsafeFromPrimitive)]
244-
#[repr(u8)]
245-
enum Number {
246-
Zero = 0,
247-
248-
// Same for `#[num_enum(catch_all)]`, and `#[num_enum(alternatives = [2, ...])]`
249-
#[num_enum(default)]
250-
One = 1,
251-
}
252-
let _undefined_behavior = unsafe { Number::unchecked_transmute_from(2) };
253-
```
254-
255254
```rust
256255
use num_enum::UnsafeFromPrimitive;
257256

@@ -278,8 +277,27 @@ unsafe fn undefined_behavior() {
278277
}
279278
```
280279

281-
Optional features
282-
-----------------
280+
Note that this derive ignores any `default`, `catch_all`, and `alternatives` attributes on the enum.
281+
If you need support for conversions from these values, you should use `TryFromPrimitive` or `FromPrimitive`.
282+
283+
This means, for instance, that the following is undefined behaviour:
284+
285+
```rust,no_run
286+
use num_enum::UnsafeFromPrimitive;
287+
288+
#[derive(UnsafeFromPrimitive)]
289+
#[repr(u8)]
290+
enum Number {
291+
Zero = 0,
292+
293+
// Same for `#[num_enum(catch_all)]`, and `#[num_enum(alternatives = [2, ...])]`
294+
#[num_enum(default)]
295+
One = 1,
296+
}
297+
let _undefined_behavior = unsafe { Number::unchecked_transmute_from(2) };
298+
```
299+
300+
## Optional features
283301

284302
Some enum values may be composed of complex expressions, for example:
285303

@@ -293,7 +311,6 @@ enum Number {
293311
To cut down on compile time, these are not supported by default, but if you enable the `complex-expressions`
294312
feature of your dependency on `num_enum`, these should start working.
295313

296-
License
297-
-------
314+
## License
298315

299316
num_enum may be used under your choice of the BSD 3-clause, Apache 2, or MIT license.

0 commit comments

Comments
 (0)