1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Macros and traits to ease using enums whose sole purpose is to
//! enumerate a set of types.
//!
//! It exports a set of traits that help to this end:
//! * [`traits::TryAsRef`] - like `AsRef<T>`, but allowed to fail
//! * [`traits::TryAsMut`] - like `AsMut<T>`, but allowed to fail
//! * [`traits::TypedContainer`] - inspect types of a container
//!
//! And a set of macros that derive implementations from these and some
//! standard traits, namely:
//! * [`macros::From`] to convert from the types to the enum
//! * [`macros::TryInto`] to convert from the enum back into the types
//! * [`macros::TryAsMut`] to get references of the values of the enum
//! * [`macros::TryAsRef`] to get mutable references of the values of the enum
//! * [`macros::TypedContainer`] to inspect the type in the enum
//!
//! To derive the traits for an enum, the enum has to have the following shape:
//! * Each variant must have exactly one unnamed parameter
//! * Each variant argument type must appear at most once
//!
//! See also:
//! * crate [`macros`] (re-export of [`try_as_macros`])
//! * crate [`traits`] (re-export of [`try_as_traits`])
//!
//! ## Example
//!
//! Assume we have an enum that enumerates values of `i64`, `String` and `bool`:
//! ```rust
//! enum Value{
//!     Number(i64),
//!     String(String),
//!     Bool(bool)
//! }
//! ```
//!
//! And we want to convert between this enum and values of types `i64`, `String` and `bool`.
//! This crate exposes the following macros to ease this conversion:
//!
//! ```rust
//! # mod try_as {
//! #   pub extern crate try_as_macros as macros;
//! #   pub extern crate try_as_traits as traits;
//! # }
//! # use std::convert::TryInto;
//! use try_as::macros;
//!
//! #[derive(macros::From, macros::TryInto, Debug)]
//! enum Value{
//!     Number(i64),
//!     String(String),
//!     Bool(bool)
//! }
//!
//! // Convert to `Value` from `i64`, `String` or `bool` using `into`/`from`:
//! let x = Value::from(0);
//! let name = Value::from("Hello".to_owned());
//! let yes_or_no: Value = false.into();
//!
//! // Convert back with `try_into`
//! let maybe_i64: Result<i64, _> = x.try_into();
//! assert_eq!(maybe_i64.unwrap(), 0);
//! let maybe_i64: Result<i64, Value> = name.try_into();
//! assert!(maybe_i64.is_err());
//!
//! ```
//! If we only need a reference to the value, we can use the macros `TryAsRef` and `TryAsMut`,
//! which derive implementations for the new traits [`traits::TryAsRef`] and [`traits::TryAsMut`], respectively:
//!
//!
//! ```rust
//! # mod try_as {
//! #   pub extern crate try_as_macros as macros;
//! #   pub extern crate try_as_traits as traits;
//! # }
//! use try_as::{
//!     traits::{TryAsRef, TryAsMut},
//!     macros,
//! };
//!
//! #[derive(macros::TryAsRef, macros::TryAsMut)]
//! enum Value{
//!     Number(i64),
//!     String(String),
//!     Bool(bool)
//! }
//!
//! let mut x = Value::Number(0);
//!
//! let x_ref: &i64 = x.try_as_ref().unwrap();
//! assert_eq!(*x_ref, 0);
//!
//! let x_mut: &mut i64 = x.try_as_mut().unwrap();
//! *x_mut = 4;
//!
//! let x_ref: &i64 = x.try_as_ref().unwrap();
//! assert_eq!(*x_ref, 4);
//!
//! let str_ref: Option<&String> = x.try_as_ref();
//! assert!(str_ref.is_none());
//! ```
//!
//! Finally, to inspect the type, we can use the trait `traits::TypedContainer`, which allows
//! us to look at the [`std::any::TypeId`] of the contained type:
//! ```
//! # mod try_as {
//! #   pub extern crate try_as_macros as macros;
//! #   pub extern crate try_as_traits as traits;
//! # }
//! use try_as::{
//!     traits::TypedContainer,
//!     macros
//! };
//!
//! #[derive(macros::TypedContainer)]
//! enum Value{
//!     Number(i64),
//!     String(String),
//!     Bool(bool)
//! }
//!
//! let x = Value::Number(0);
//! let boolean: Value = Value::Bool(false);
//! assert!(x.holds::<i64>());
//! assert!(!boolean.holds::<i64>());
//! assert!(std::any::TypeId::of::<bool>() == boolean.type_id());
//!
//! ```

pub extern crate try_as_macros as macros;
pub extern crate try_as_traits as traits;