Skip to main content

sumtype/
lib.rs

1#![doc = include_str!("README.md")]
2
3// Audit: cases that must fail to compile (intentional rejections + known limitations) are
4// reproduced as `compile_fail` doctests in `tests/compile_fail.md`. Gated on `cfg(doctest)` so
5// this neither appears in `cargo doc` output nor affects normal builds; it runs under
6// `cargo test` (Doc-tests sumtype).
7#[cfg(doctest)]
8#[doc = include_str!("tests/compile_fail.md")]
9struct CompileFailCases;
10
11#[doc(hidden)]
12pub use sumtype_macro::_sumtrait_internal;
13
14/// Makes a user-defined trait usable with `#[sumtype]`.
15///
16/// ## Arguments
17///
18/// - `implement` (optional) — the real trait that the generated sum type should implement. Use it
19///   to make a `std` (or other third-party) trait compatible with `sumtype` by declaring a local
20///   mock trait that mirrors it.
21/// - `krate` (optional) — the path to the `sumtype` crate (default: `::sumtype`).
22/// - `marker` — the absolute path of an empty type, defined in the same crate as the trait and
23///   visible to the crates that will use the trait with `#[sumtype]`.
24///
25/// ## Supertraits
26///
27/// Supertraits are declared with the usual `trait Foo: Bar { ... }` syntax. Each supertrait must be
28/// either a built-in trait that `sumtype` recognizes (`Copy`, `Clone`, `Hash`, `Debug`, `Display`,
29/// `Error`, `Iterator`, `Read` — bare or via a `std`/`core` path) or another `#[sumtrait]` trait;
30/// referring to a custom trait by an absolute path is recommended.
31///
32/// ## Sumtrait-safety
33///
34/// Every trait annotated with `#[sumtrait]` must be *sumtrait-safe*. This is similar to object
35/// safety, but not identical.
36///
37/// A trait is called sumtrait-safe when it satisfies all of the following:
38///
39/// - The trait should not accept any generic arguments.
40/// - All supertraits of the trait are also sumtrait-safe and annotated with `#[sumtrait]`.
41/// - All trait items are either associated types or associated functions.
42/// - All associated functions must take a receiver (`self`, `&self`, or `&mut self`) as their
43///   first parameter. Additional parameters are allowed, but their types must not contain `Self`.
44/// - All associated functions should return the `Self` type, or a return type that does not
45///   contain `Self`.
46/// ```
47/// # use sumtype::sumtrait;
48/// pub struct Marker(::core::convert::Infallible);
49/// #[sumtrait(marker = Marker)] // In practice, `Marker` must be an absolute path beginning with `::`
50/// trait MyTrait {}
51/// ```
52pub use sumtype_macro::sumtrait;
53
54/// Enables the `sumtype!(..)` macro within the annotated context.
55///
56/// For each context marked with `#[sumtype]`, the macro creates a single anonymous sum type that
57/// implements the trait(s) you specify. Wrap an expression with `sumtype!(expr)` to store it in
58/// that sum type. For example, to return a unified iterator:
59///
60/// ```
61/// # use sumtype::sumtype;
62/// # use std::iter::Iterator;
63/// #[sumtype(sumtype::traits::Iterator)]
64/// fn return_iter(a: bool) -> impl Iterator<Item = ()> {
65///     if a {
66///         sumtype!(std::iter::once(()))
67///     } else {
68///         sumtype!(vec![()].into_iter())
69///     }
70/// }
71/// ```
72///
73/// Depending on `a`, this returns a [`std::iter::Once`] or a [`std::vec::IntoIter`]. `#[sumtype]`
74/// creates an anonymous sum type that also implements [`std::iter::Iterator`] and wraps each
75/// `sumtype!(..)` expression in it. The abstraction is zero-cost when `a` is known at compile time.
76///
77/// You can also name the sum type explicitly with `sumtype!()` in type position. When you do, give
78/// each wrapped expression's concrete type using the `sumtype!(expr, Type)` form:
79///
80/// ```
81/// # use sumtype::sumtype;
82/// # use std::iter::Iterator;
83/// #[sumtype(sumtype::traits::Iterator)]
84/// fn return_iter_explicit(a: bool) -> sumtype!() {
85///     if a {
86///         sumtype!(std::iter::once(()), std::iter::Once<()>)
87///     } else {
88///         sumtype!(vec![()].into_iter(), std::vec::IntoIter<()>)
89///     }
90/// }
91/// ```
92pub use sumtype_macro::sumtype;
93
94#[doc(hidden)]
95pub trait TypeRef<const RANDOM: usize, const N: usize> {
96    type Type: ?Sized;
97}
98
99/// Recovers a concrete type `To` from a `#[sumtype]` sum type.
100///
101/// An implementation is generated automatically for every sum type produced by `#[sumtype]`.
102/// Because it inspects the active variant's type at runtime (via [`core::any::TypeId`]), both `To`
103/// and every wrapped type must be `'static`; the methods are unavailable for sum types that wrap a
104/// borrowed type. `downcast_ref`/`downcast_mut` are allocation-free; the owning `downcast` boxes the
105/// value briefly to move it out.
106///
107/// To call `Downcast` on a function's result, name the target type(s) in the return bound:
108/// `-> impl Trait + Downcast<To>` (add one `+ Downcast<T>` per type you want to recover). This works
109/// with the ordinary type-less `sumtype!(expr)` form. A bare `impl Trait` return exposes only
110/// `Trait`, so `Downcast` would not be reachable through it. (Exposing the **named** sum type — a
111/// `-> sumtype!()` return or a field — also works and makes every `To` available at once.)
112///
113/// `To` is the trait's type parameter, so it is chosen by context (a type annotation or a
114/// `Downcast::<To>::…` qualified call), not by a method turbofish — which is what lets `Downcast<To>`
115/// serve as a generic bound, e.g. `fn f<E: Downcast<u32>>(e: E) -> Option<u32> { e.downcast().ok() }`.
116///
117/// ```
118/// # use sumtype::{sumtype, Downcast};
119/// #[sumtype(sumtype::traits::Debug)]
120/// fn make(b: bool) -> impl std::fmt::Debug + Downcast<u32> + Downcast<String> {
121///     if b { sumtype!(1u32) } else { sumtype!(String::from("hi")) }
122/// }
123/// let v = make(true);
124/// assert_eq!(Downcast::<u32>::downcast_ref(&v), Some(&1u32));
125/// assert_eq!(Downcast::<String>::downcast_ref(&v), None);
126/// assert_eq!(Downcast::<String>::downcast(make(false)).ok(), Some(String::from("hi")));
127/// ```
128pub trait Downcast<To: 'static>: Sized {
129    /// Returns the wrapped value if the active variant holds a `To`; otherwise returns `self`
130    /// unchanged.
131    fn downcast(self) -> Result<To, Self>;
132    /// Returns a shared reference to the wrapped value if the active variant holds a `To`.
133    fn downcast_ref(&self) -> Option<&To>;
134    /// Returns a mutable reference to the wrapped value if the active variant holds a `To`.
135    fn downcast_mut(&mut self) -> Option<&mut To>;
136}
137
138/// Mock traits targeted by the `#[sumtype]` macro. They make the corresponding `std`/`core` traits
139/// usable with `#[sumtype]`.
140pub mod traits {
141    use super::sumtrait;
142
143    #[doc(hidden)]
144    #[allow(non_camel_case_types)]
145    trait __SumTrait_Sealed {}
146
147    macro_rules! emit_traits {
148        () => {
149            #[doc(hidden)]
150            pub struct Marker(::core::convert::Infallible);
151
152            /// Target of [`crate::sumtype`] macro, which implements [`std::io::Read`].
153            #[sumtrait(implement = ::std::io::Read, krate = $crate, marker = $crate::traits::Marker)]
154            #[allow(private_bounds)]
155            pub trait Read {
156                fn read(&mut self, buf: &mut [::core::primitive::u8]) -> ::std::io::Result<::core::primitive::usize>;
157            }
158
159            impl<T: ::std::io::Read> Read for T {
160                fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
161                    T::read(self, buf)
162                }
163            }
164
165            /// Target of [`crate::sumtype`] macro, which implements [`std::iter::Iterator`].
166            #[sumtrait(implement = ::core::iter::Iterator, krate = $crate, marker = $crate::traits::Marker)]
167            #[allow(private_bounds)]
168            pub trait Iterator {
169                type Item;
170                fn next(&mut self) -> ::core::option::Option<Self::Item>;
171            }
172
173            impl<T: ::core::iter::Iterator> Iterator for T {
174                type Item = T::Item;
175                fn next(&mut self) -> Option<Self::Item> {
176                    T::next(self)
177                }
178            }
179
180            /// Target of [`crate::sumtype`] macro, which implements [`std::marker::Copy`].
181            #[sumtrait(implement = ::core::marker::Copy, krate = $crate, marker = $crate::traits::Marker)]
182            #[allow(private_bounds)]
183            pub trait Copy: $crate::traits::Clone {
184            }
185
186            impl<T: ::core::marker::Copy> Copy for T {}
187
188            /// Target of [`crate::sumtype`] macro, which implements [`std::clone::Clone`].
189            #[sumtrait(implement = ::core::clone::Clone, krate = $crate, marker = $crate::traits::Marker)]
190            #[allow(private_bounds)]
191            pub trait Clone {
192                fn clone(&self) -> Self;
193            }
194
195            impl<T: ::core::clone::Clone> Clone for T {
196                fn clone(&self) -> Self {
197                    T::clone(self)
198                }
199            }
200
201            /// Target of [`crate::sumtype`] macro, which implements [`std::hash::Hash`].
202            ///
203            /// The generated sum type forwards `hash` to the active variant (no discriminant is
204            /// mixed in). The enum does not implement `Eq`/`PartialEq`, so there is no equality
205            /// relation for the hash to be inconsistent with.
206            #[sumtrait(implement = ::core::hash::Hash, krate = $crate, marker = $crate::traits::Marker)]
207            #[allow(private_bounds)]
208            pub trait Hash {
209                fn hash<H: ::core::hash::Hasher>(&self, state: &mut H);
210            }
211
212            impl<T: ::core::hash::Hash> Hash for T {
213                fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
214                    T::hash(self, state)
215                }
216            }
217
218            /// Target of [`crate::sumtype`] macro, which implements [`std::fmt::Display`].
219            #[sumtrait(implement = ::core::fmt::Display, krate = $crate, marker = $crate::traits::Marker)]
220            #[allow(private_bounds)]
221            pub trait Display {
222                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result;
223            }
224
225            impl<T: ::core::fmt::Display> Display for T {
226                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
227                    T::fmt(self, f)
228                }
229            }
230
231            /// Target of [`crate::sumtype`] macro, which implements [`std::fmt::Debug`].
232            #[sumtrait(implement = ::core::fmt::Debug, krate = $crate, marker = $crate::traits::Marker)]
233            #[allow(private_bounds)]
234            pub trait Debug {
235                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result;
236            }
237
238            impl<T: ::core::fmt::Debug> Debug for T {
239                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
240                    T::fmt(self, f)
241                }
242            }
243
244            /// Target of [`crate::sumtype`] macro, which implements [`std::error::Error`].
245            #[sumtrait(implement = ::std::error::Error, krate = $crate, marker = $crate::traits::Marker)]
246            #[allow(private_bounds)]
247            pub trait Error: $crate::traits::Debug + $crate::traits::Display {
248                fn source(&self) -> ::core::option::Option<&(dyn ::std::error::Error + 'static)>;
249            }
250
251            impl<T: ::std::error::Error> Error for T {
252                fn source(&self) -> ::core::option::Option<&(dyn ::std::error::Error + 'static)> {
253                    T::source(self)
254                }
255            }
256
257        };
258    }
259    emit_traits!();
260}