tagset 0.1.2

Easily create trait-dispatching sum types
Documentation
Easily create trait-dispatching sum types (TagSets).
* Fixed discriminant values - Each included type's discriminant will not change,
  even as new variants are added in future versions.
* Build-in serde support - Easily derive Serialize and Deserialize for your set.
* Supports any trait - Trait items which are not dispatchable (such as associated types) can be
  explicitly provided.
* Compositable sets - Sets can easily include other sets as sub-sets.
* Extended trait defaults - Annotate your trait to allow for trait defaults not supported by standard Rust,
  such as associated type defaults.
* (Mostly) scope-independent - With a few rare exceptions, nothing is required to be in scope, 
  and types and traits are not required to have unique identifiers.
```rust
/// Mark traits with `telety`(<https://crates.io/crates/telety>):
pub mod my_trait {
    #[telety::telety(crate::my_trait)]
    pub trait MyTrait {
        fn ascii_char(&self) -> u8;
    }
}
pub mod my_impl {
    #[derive(Debug)]
    pub struct A;
    impl super::my_trait::MyTrait for A {
        fn ascii_char(&self) -> u8 {
            b'A'
        }
    }
    #[derive(Debug)]
    pub struct B;
    impl super::my_trait::MyTrait for B {
        fn ascii_char(&self) -> u8 {
            b'B'
        }
    }
}
pub mod my_set {
    # use tagset::tagset;
    // Define your dispatching set type using tagset attributes:
    // Implements `MyTrait` for `MyImplementor`
    #[tagset(impl super::my_trait::MyTrait)]
    // Adds `A` as a variant of `MyImplementer` and generates a `From<A>` and `TryFrom<MySet>` impl
    #[tagset(super::my_impl::A)]
    // Adds `B` as a variant of `MyImplementer` and generates a `From<B>` and `TryFrom<MySet>` impl
    #[tagset(super::my_impl::B)]
    #[tagset(derive(Debug))]
    pub struct MySet;
}
fn main() {
    use my_trait::MyTrait as _;
    // MySet implements From for all variants
    let set_a: my_set::MySet = my_impl::A.into();
    let set_b: my_set::MySet = my_impl::B.into();
    assert_eq!(set_a.ascii_char(), b'A');
    assert_eq!(set_b.ascii_char(), b'B');

    // TryFrom<MySet> is implemented for all variants,
    // as well as &MySet and &mut MySet versions
    let a: my_impl::A = set_a.try_into().unwrap();
    // Conversion by value returns the original value in Err
    let result_b: Result<my_impl::A, my_set::MySet> = set_b.try_into();
    let set_b: my_set::MySet = result_b.unwrap_err();
}
```
You can also add generic parameters and bounds:
```rust
pub mod my_trait {
    #[telety::telety(crate::my_trait)]
    pub trait MyTrait<U> { }
}
pub mod my_impl {
    #[derive(Clone)]
    pub struct Parameter<T>(T);
    impl<T, U> super::my_trait::MyTrait<U> for Parameter<T> { }
}
pub mod my_set {
    # use tagset::tagset;
    #[tagset(impl<U> super::my_trait::MyTrait<U>
        // See the type bounds section for details
        where for<VAR> VAR: Clone
    )]
    // You can use type parameters from the set
    #[tagset(super::my_impl::Parameter<T>)]
    pub struct MySet<T>;
}
# fn main() { }
```
# Discriminants
tagset supports consistent discriminants. Like enums, by default numbering is incremental starting at 0.  
To choose the initial discriminant, use the `#[tagset(index(...))]` attribute. `index` takes an integer
literal with an optional suffix if you want to specify the discriminant type. e.g., `[tagset(index(-4ii8))]`
sets the discriminant type as `i8`, and the first discriminant value to `-4`.  
To modify the default numbering, use `#[tagset(reserved(...))]` or `#[tagset(deprecated(...))]` attributes.
(Both are functually equivalent, but semantically distinguish discriminants that can and cannot be used in
the future). Both attributes take a range literal with an open start and an inclusive or exclusive end, e.g.
`..5` or `..=5`. All discriminants starting after the previous variant to the end of the range will be skipped.
```rust
# use tagset::tagset;
pub struct A;
pub struct B;
pub struct C;
#[tagset(index(2u8))]
#[tagset(A)] // 2
#[tagset(deprecated(..5))]
#[tagset(B)] // 5
#[tagset(C)] // 6
#[tagset(reserved(..16))]
pub struct MySet;
fn main() {
    use tagset::TagSet as _;
    let a: MySet = A.into();
    let b: MySet = B.into();
    let c: MySet = C.into();
    
    assert_eq!(a.discriminant(), 2u8);
    assert_eq!(b.discriminant(), 5u8);
    assert_eq!(c.discriminant(), 6u8);
}
```  
Discriminant values are available at runtime through the [TagSet] trait, and at compile-time with
[TagSetDiscriminant] variant type to variant discriminant and [TagSetTypeI32] variant discriminant to variant 
(use the trait corresponding to the discriminant type, [TagSetTypeU8], etc.).  
# External traits
If a trait comes from an external crate, you can create a telety proxy for it:
```rust
pub mod external_crate {
    // No telety attribute
    pub trait MyTrait {
        fn ascii_char(&self) -> u8;
    }
}
pub mod internal_proxy {
    // The actual trait from external_crate is re-exported here, along with the
    // telety info as if it were defined here
    #[telety::telety(crate::internal_proxy, proxy = "crate::external_crate::MyTrait")]
    pub trait MyTrait {
        fn ascii_char(&self) -> u8;
    }
}
pub mod proxy_impl {
    # use tagset::tagset;
    pub struct A;
    
    impl super::external_crate::MyTrait for A {
        fn ascii_char(&self) -> u8 {
            b'A'
        }
    }
    pub struct B;
    // Either external_crate::MyTrait or internal_proxy::MyTrait can be used -
    // they refer to the exact same trait
    impl super::internal_proxy::MyTrait for B {
        fn ascii_char(&self) -> u8 {
            b'B'
        }
    }
    #[tagset(impl super::internal_proxy::MyTrait)]
    #[tagset(A)]
    #[tagset(B)]
    pub struct Set;
}
# fn main() { }
```
# Overrides
You can override item definitions inside traits:
```rust
pub mod my_trait {
    #[telety::telety(crate::my_trait)]
    pub trait MyTrait {
        type Output;
        fn get(&self) -> Self::Output;
    }
}
pub mod my_impl {
    pub struct A(pub i32);
    
    impl super::my_trait::MyTrait for A {
        type Output = i32;
        fn get(&self) -> Self::Output {
            self.0
        }
    }
    pub struct B(pub u32);
    
    impl super::my_trait::MyTrait for B {
        type Output = u32;
        fn get(&self) -> Self::Output {
            self.0
        }
    }
}
pub mod my_set {
    # use tagset::tagset;
    #[tagset(impl super::my_trait::MyTrait {
        // associated types usually require an override
        type Output = i64;
        // trait functions will usually delegate to the variant by default,
        // but sometimes this is not possible (e.g. there is no reciever,
        // or the reciever is not convertable such as Rc<Self>), or not
        // desired.
        // Overrides are provided 2 macros to generate implementations based
        // based on the included types:
        //   `match_by_value!(value, value_identifier => expr)`
        //     `value` is a value of type `Self`, `&Self`, or `&mut Self`.
        //     `value_identifier` is any identifier to be used in `expr` as
        //       the inner value of the set.
        //     `expr` is an expression in which `value_identifier` is the
        //       inner value of the set.
        //   `match_by_discriminant!(discriminant, type_identifier => expr)`
        //     `discriminant` is a value of the type of the set's discriminant.
        //       If the value is invalid, the function will panic.
        //     `type_identifier` is any identifier to be substituted with the
        //       type path corresponding to `discriminant`.
        //     `expr` is an expression in which `type_identifier` will be
        //       substituted for `discriminant`'s corresponding type path.
        fn get(&self) -> Self::Output {
            match_by_value!(self, value => value.get() as i64)
        }
    })]
    #[tagset(super::my_impl::A)]
    #[tagset(super::my_impl::B)]
    pub struct MySet;
}
fn main() {
    use my_trait::MyTrait as _;
    let a: my_set::MySet = my_impl::A(3i32).into();
    let b: my_set::MySet = my_impl::B(4u32).into();
    
    assert_eq!(a.get() + b.get(), 7);
}
```
# Type bounds
tagset support a special syntax when specifying type bounds:  
`for <VAR>: VAR: MyTrait`  
This bound is expanded for variant, substituting `VAR` in the bound for the type path of the variant.
For example, in a set containing types `A`, `B`, and `C`, this is equivalent to:
```rust, ignore
    A: MyTrait,
    B: MyTrait,
    C: MyTrait,
```
# Includes
Sets are compositable: you can use `#[tagset(include(MySubSet))]` to include all variant types from
a telety-enabled `MySubSet`.  
Included types will retain their *relative* discriminants, but not their *absolute* discriminants.  
```rust
pub mod my_subset {
    # use tagset::tagset;
    pub struct A;
    pub struct B;
    
    #[telety::telety(crate::my_subset)]
    #[tagset(index(7i32))]
    #[tagset(A)]
    #[tagset(reserved(..11))]
    #[tagset(B)]
    pub struct MySubSet;
}
pub mod my_set {
    # use tagset::tagset;
    pub struct C;
    pub struct D;
    #[tagset(index(3u64))]
    #[tagset(C)]
    // Though `A`'s discriminant is 7 in `MySubSet`,
    // here it will be 4
    #[tagset(include(super::my_subset::MySubSet))]
    // `D`'s discriminant will be directly after `C`'s (8 -> 9)
    #[tagset(D)]
    pub struct MySet;
}
fn main() {
    let a: my_subset::MySubSet = my_subset::A.into();
    let b: my_subset::MySubSet = my_subset::B.into();
    assert_eq!(a.discriminant(), 7);
    assert_eq!(b.discriminant(), 11);
    use tagset::TagSet as _;
    let a: my_set::MySet = my_subset::A.into();
    let b: my_set::MySet = my_subset::B.into();
    let c: my_set::MySet = my_set::C.into();
    let d: my_set::MySet = my_set::D.into();
    assert_eq!(a.discriminant(), 4);
    assert_eq!(b.discriminant(), 8);
    assert_eq!(c.discriminant(), 3);
    assert_eq!(d.discriminant(), 9);
}
```
# Metadata
tagset supports adding metadata to traits to control default implementation.  
To add metadata to a trait, use the [tagset_meta] attribute, then use `#[meta(...)]` attributes
where desired.
## default
`default` can be applied to associated types or associated functions.  
When applied to an associated type, it takes a type path which will serve as the default for
any implementing set. In this case, it is not necessary to provide an override in the set impl.  
When applied to a trait function, it takes a function body. The macros mentioned in the overrides
section are available here as well.  
Note: telety aliases all types used in the function body so they are usable at the set definition
without importing them, but it cannot alias `use` items or values. Those must be textually valid
at the location of the set definition.
## bounds
By default, the set implements traits when all its variants implement the trait. This may be too
strict or too lax for some default implementations. The `bounds` meta attribute takes
where predicates to use as the baseline bounds to implement the trait for a set. See the
type bounds section for special bounds syntax.
```rust
pub mod my_trait {
    #[telety::telety(crate::my_trait)]
    #[tagset::tagset_meta]
    // We don't need any bounds for our default impl
    #[meta(bounds())]
    pub trait MyTrait {
        #[meta(default(std::convert::Infallible))]
        type Error;
        #[meta(default {
            match_by_value!(self, value => Ok(std::any::type_name_of_val(value)))
        })]
        fn name(&self) -> Result<&'static str, Self::Error>;
    }
}
pub mod my_set {
    # use tagset::tagset;
    // Because MyTrait has no default bounds, these don't need to implement MyTrait
    pub struct A;
    pub struct B;
    
    #[tagset(impl super::my_trait::MyTrait)]
    #[tagset(A)]
    #[tagset(B)]
    pub struct MySet;
}
fn main() {
    use my_trait::MyTrait as _;
    let a: my_set::MySet = my_set::A.into();
    let b: my_set::MySet = my_set::B.into();
    assert_eq!(a.name().unwrap().split("::").last().unwrap(), "A");
    assert_eq!(b.name().unwrap().split("::").last().unwrap(), "B");
}
```
# derive
tagset currently uses a private internal type when implementing the set. Because of this,
derives do not work as-is. Wrap them in a tagset attribute:
```rust
pub mod my_set {
    # use tagset::tagset;
    #[derive(Clone)]
    pub struct A;
    #[tagset(derive(Clone))]
    #[tagset(A)]
    pub struct MySet;
}
fn main() {
    let before: my_set::MySet = my_set::A.into();
    let after = before.clone();
}
```
# serde
When the serde feature is enabled, tagset includes Serialize and Deserialize proxies
with default implementations. Currently, the Deserialize implementation requires also
implementing the trait [serde::DeserializeFromDiscriminant], but this may be automatic
in the future.
```rust,ignore
# // This does not work as a doctest for some reason, see tests/serde_roundtrip.rs
# use tagset::tagset;
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Number(pub i32);
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Text(pub String);
#[tagset(impl tagset::proxy::serde::Serialize)]
#[tagset(impl<'de> tagset::serde::DeserializeFromDiscriminant<'de>)]
#[tagset(impl<'de> tagset::proxy::serde::Deserialize<'de>)]
#[tagset(Number)]
#[tagset(Text)]
pub struct MySet;
fn main() -> anyhow::Result<()> {
    let value: MySet = Text("asdf".to_string()).into();
    let serialized = serde_json::to_string(&value)?;
    let deserialized: MySet = serde_json::from_str(&*serialized)?;
    
    let text: Text = deserialized.try_into().unwrap_or_else(|_| unreachable!());
    assert_eq!(text.0, "asdf");
    Ok(())
}
```
The default (de)serialization implementation structures the set as a 2-element tuple.
The first element is the discriminant, the second is the inner variant.