oneof 0.2.0

Enum variant projection — access one variant at a time
Documentation
#![cfg_attr(not(test), no_std)]

/// # OneOf — Enum variant projection for Rust
///
/// `OneOf` generates ergonomic methods to access individual enum variants
/// without writing repetitive `match` arms. It provides a **zero-cost abstraction**
/// — the generated code compiles to the same machine code as hand-written match.
///
/// ## Motivation
///
/// Rust enums are powerful, but accessing one variant at a time requires
/// boilerplate:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Event {
///     Request { id: u64, path: String },
///     Error(String),
///     Timeout,
/// }
///
/// // Instead of hand-writing match arms just to check:
/// let event = Event::Timeout;
/// let is_timeout = match &event {
///     Event::Timeout => true,
///     _ => false,
/// };
///
/// // Write a single method call:
/// assert!(event.is_timeout());
///
/// // Instead of writing an accessor function every time:
/// fn get_error(e: &Event) -> Option<&String> {
///     match e {
///         Event::Error(msg) => Some(msg),
///         _ => None,
///     }
/// }
///
/// // Use the generated accessor directly:
/// let e = Event::Error("boom".into());
/// assert_eq!(e.error(), Some(&String::from("boom")));
/// ```
///
/// ## Generated API
///
/// For each variant `Foo`, `#[derive(OneOf)]` generates four methods.
/// The method name is the variant name converted to **snake_case**:
///
/// | Method | Signature (simplified) | Description |
/// |--------|----------------------|-------------|
/// | `foo()` | `(&self) -> Option<Payload>` | Immutable reference to the variant's data |
/// | `foo_mut()` | `(&mut self) -> Option<&mut Payload>` | Mutable reference to the variant's data |
/// | `into_foo()` | `(self) -> Option<Payload>` | Consume `self` and extract owned data |
/// | `is_foo()` | `(&self) -> bool` | Check whether this is the variant |
///
/// For example, a variant `ErrorKind` generates `error_kind()`, `error_kind_mut()`,
/// `into_error_kind()`, and `is_error_kind()`.
///
/// ### Naming conventions
///
/// Method names follow established Rust conventions rather than ad-hoc patterns:
///
/// - **Bare name** for getters — `error()` not `get_error()`, `get_err()`, or `err()`.
///   Per the [Rust API Guidelines][api-guidelines], `get_` prefixes are avoided.
/// - **`_mut` suffix** — `error_mut()` not `mut_error()`. This follows the language-wide
///   pattern of `iter_mut()`, `as_mut()`, `deref_mut()`, `borrow_mut()`. The base name
///   stays constant; the suffix signals mutability.
/// - **`into_` prefix** — `into_error()` follows `into_iter()`, `into_inner()`,
///   `into_bytes()`. Ownership transfer is signalled at the front.
/// - **`is_` prefix** — `is_error()` follows `is_some()`, `is_empty()`, `is_ok()`.
///
/// [api-guidelines]: https://rust-lang.github.io/api-guidelines/naming.html
///
/// ### Return types by variant shape
///
/// The payload type of `foo()` / `foo_mut()` / `into_foo()` depends on the
/// shape of the variant:
///
/// | Variant shape | `foo()` returns | Description |
/// |---------------|-----------------|-------------|
/// | `Foo` (unit) | `Option<()>` | No data to project |
/// | `Foo(T)` (single tuple) | `Option<&T>` | Single field projected directly |
/// | `Foo(T0, T1, ..)` (multi tuple) | `Option<(&T0, &T1, ..)>` | Tuple of field references |
/// | `Foo { field: T }` (single named) | `Option<&T>` | Single field unwrapped |
/// | `Foo { f0: T0, f1: T1, .. }` (multi named) | `Option<FooRef<'_>>` | Named projection struct |
///
/// ### Multi-field struct projections
///
/// For variants with multiple named fields (e.g. `Request { id: u64, path: String }`),
/// the macro generates three **projection structs** that preserve field names:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Event {
///     Request { id: u64, path: String },
///     Error(String),
///     Timeout,
/// }
/// // Generated for variant `Request` with fields `id` and `path`:
/// //   struct RequestRef<'a> { pub id: &'a u64, pub path: &'a String }
/// //   struct RequestRefMut<'a> { pub id: &'a mut u64, pub path: &'a mut String }
/// //   struct RequestOwned { pub id: u64, pub path: String }
/// ```
///
/// This lets you access fields by name instead of positional indices:
///
/// ```rust
/// # use oneof::OneOf;
/// # #[derive(OneOf)]
/// # enum Event {
/// #     Request { id: u64, path: String },
/// #     Error(String),
/// #     Timeout,
/// # }
/// let event = Event::Request { id: 42, path: "/".into() };
/// if let Some(req) = event.request() {
///     println!("id={}, path={}", req.id, req.path);
/// }
/// ```
///
/// ## Collection filtering
///
/// OneOf shines when filtering collections — no more verbose closures:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Status {
///     Active(u32),
///     Inactive,
///     Error(String),
/// }
///
/// let items = vec![
///     Status::Active(1),
///     Status::Inactive,
///     Status::Active(2),
///     Status::Error("fail".into()),
/// ];
///
/// // Extract all active IDs:
/// let active_ids: Vec<&u32> = items.iter().filter_map(|x| x.active()).collect();
/// assert_eq!(active_ids, vec![&1, &2]);
///
/// // Find the first error message:
/// let first_error: Option<&String> = items.iter().filter_map(|x| x.error()).next();
/// assert_eq!(first_error, Some(&String::from("fail")));
/// ```
///
/// ## Chained projection
///
/// Accessor methods compose naturally with combinators and nested enums:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Value {
///     Integer(i64),
///     Text(String),
/// }
///
/// #[derive(OneOf)]
/// enum Field {
///     Name(String),
///     Value(Value),
/// }
///
/// // Chain through nested enums:
/// let field = Field::Value(Value::Integer(42));
/// let inner: Option<&i64> = field.value().and_then(|v| v.integer());
/// assert_eq!(inner, Some(&42));
/// ```
///
/// ## Mutable access
///
/// Use `foo_mut()` to modify a variant's data in-place:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Value {
///     Integer(i64),
///     Text(String),
/// }
///
/// let mut value = Value::Integer(10);
/// if let Some(v) = value.integer_mut() {
///     *v = 42;
/// }
/// assert_eq!(value.into_integer(), Some(42));
/// ```
///
/// For multi-field struct variants, the generated `FooRefMut` projection gives
/// mutable access to each field by name:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Header {
///     ContentType { key: String, value: String },
/// }
///
/// let mut header = Header::ContentType {
///     key: "Content-Type".into(),
///     value: "text/plain".into(),
/// };
///
/// if let Some(h) = header.content_type_mut() {
///     *h.value = String::from("application/json");
/// }
///
/// assert_eq!(
///     header.into_content_type().unwrap().value,
///     "application/json",
/// );
/// ```
///
/// ## Generics and lifetimes
///
/// `OneOf` works with generic enums and lifetime parameters:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum RefOrOwned<'a, T: Clone> {
///     Ref(&'a T),
///     Owned(T),
/// }
///
/// let data = 42;
/// let value = RefOrOwned::Ref(&data);
/// assert_eq!(value.r#ref(), Some(&&data));
///
/// let value = RefOrOwned::Owned(data);
/// assert_eq!(value.into_owned(), Some(42));
/// ```
///
/// Multi-field struct variants with generics also generate properly-parameterized
/// projection structs:
///
/// ```rust
/// # use oneof::OneOf;
/// #[derive(OneOf)]
/// enum Response<T> {
///     Success { data: T, code: u16 },
///     Error { error: T, info: String },
/// }
///
/// let ok: Response<i32> = Response::Success { data: 200, code: 0 };
/// assert!(ok.is_success());
///
/// let err: Response<i32> = Response::Error { error: -1, info: String::from("timeout") };
/// if let Some(e) = err.error() {
///     println!("error: {} — {}", e.error, e.info);
/// }
/// ```
///
/// ## `no_std` support
///
/// This crate is `#![no_std]` compatible. The derive macro only depends on
/// `Option` and `match`, both available in `core`.
///
/// ## Comparison with `strum`
///
/// [`strum`](https://crates.io/crates/strum) is great for enum-wide operations
/// — iterating all variants, converting to/from strings, counting variants.
/// `OneOf` complements `strum` by generating per-variant accessor methods,
/// something `strum` doesn't provide. The two crates can be used together
/// on the same enum.
pub use oneof_derive::OneOf;

/// Marker trait for enums that support variant projection.
///
/// This trait is **not automatically derived** by `#[derive(OneOf)]`.
/// Implement it manually if you need a trait bound:
///
/// ```rust
/// use oneof::{OneOf, OneOfVariant};
///
/// #[derive(OneOf)]
/// enum MyEnum { A, B }
///
/// // Manual implementation (empty trait, one line):
/// impl OneOfVariant for MyEnum {}
///
/// fn accepts_one_of<T: OneOfVariant>() { /* ... */ }
/// accepts_one_of::<MyEnum>();
/// ```
pub trait OneOfVariant {}