cisness 1.0.1

Runtime 'live witness' of two types being the same
Documentation
# `cisness`
Crate containing a type to "live-witness" that two types are the same (["cismutable"][cismute]). 

In particular, it lets you assert that a codepath will not actually be executed at runtime if the types are NOT the same (and panic if it does), which is useful for - for instance - checking types via [`TypeId`][typeid], and selecting operations with type-specific output where you want the type specificity can be transferred to the user.

The key structure you want to use this library, is [`LiveWitness`][live-witness]. Using it "bare" from this library is somewhat clunky, but it can be used to build better abstractions (the author is working on a small crate called `tisel` that isn't published yet that will use this as a basis).

## Example
Here's an example of how to use [`LiveWitness`][live-witness] to invoke a trait method that has an associated type that can be output. Of course, in such a simple case, this isn't very useful, but it is much more useful in other situations.
```rust
use cisness::LiveWitness;

use std::{collections::HashMap, any::{TypeId, Any}};

pub trait PartyMember {
    type Age: core::fmt::Display;

    fn get_age(&self) -> Self::Age;
}

#[derive(Debug, Clone)]
pub struct Human {
    pub name: String,
    pub age: u32,
}


impl PartyMember for Human {
    type Age = u32;

    fn get_age(&self) -> Self::Age {
        self.age
    }
}


#[derive(Debug, Clone)]
pub struct Dragon {
    pub name: String
}

impl PartyMember for Dragon {
    type Age = &'static str;

    fn get_age(&self) -> Self::Age {
        "Unknowable and Eldritch"
    }
}

/// Party that stores the vocabulary "member" types in one hashmap dynamically.
/// Note that clearly, in this case, there are better ways to do it - but often that would not be the case. 
#[derive(Default)]
pub struct AdventuringParty {
    // Maps the `Member` type id to a vector of members of that type.
    members: HashMap<TypeId, Box<dyn Any>>
}


impl AdventuringParty {
    pub fn add_member<M: Any>(&mut self, member: M) {
        let new_member_typeid = TypeId::of::<M>();
        self.members
            .entry(new_member_typeid)
            .or_insert_with(|| Box::new(Vec::<M>::new()))
            .downcast_mut::<Vec::<M>>()
            .expect("<typeid> is mapped to Vec<type for typeid> and we just inited")
            .push(member);
    }

    // Note here - the better way to do this specific example would be to put a trait criteria on 
    // the `M` generic requiring `Ord`, and doing downcasting. However, for illustration purposes, we'll
    // be listing out supported types and manually implementing them, returning `None` for unorderable ages.
    pub fn get_oldest_age_of_type<M: Any + PartyMember>(&self) -> Option<<M as PartyMember>::Age> 
    {
        // Note that you could do this with `Any::downcast_ref`. However, that doesn't work if you can't 
        // get a value of `M`, and it doesn't work as well for more complex cases. 
        // To illustrate, we're going to use TypeId matching, even if for this case it would work better not to do that.
        let type_id = TypeId::of::<M>(); 
        match type_id {
            t if t == TypeId::of::<Human>() => {
                // Note here that we don't have to directly witness the type of the generic parameter, we can instead witness
                // the output (if we know it), or a vector. 
                // In this case, we're asserting that we'll only run through this code if the output type is the same as 
                // `Option<Human::Age>` - this lets us do "magical" coercions that will panic if we've made an error.
                let w = LiveWitness::<Option<<Human as PartyMember>::Age>, Option<M::Age>>::only_executed_if_same();
                let output = self.members.get(&t)
                    .and_then(|v| v.downcast_ref::<Vec<Human>>())
                    .map(|v| v.iter().map(PartyMember::get_age).max()).flatten();
                // Note here - our witness lets us turn this to the generic output, and will typecheck even if `M` != `Human` - because we don't go down
                // this path, it's fine.
                w.owned(output)
            },
            t if t == TypeId::of::<Dragon>() => {
                let w = LiveWitness::<Option<<Dragon as PartyMember>::Age>, Option<M::Age>>::only_executed_if_same();
                if !self.members.get(&t).is_some() { return None };
                // Note how at no point here did we actually have to downcast any values.
                let output = Some("[ELDRICH MEMETIC HAZARD]"); 
                w.owned(output)
            }
            _ => None
        } 
    }
}
```

## The Name
Yes, it's intentional. The author is trans 🏳️‍⚧️, and finds it funny.

[live-witness]: https://docs.rs/cisness/latest/cisness/struct.LiveWitness.html
[cismute]: https://docs.rs/cismute 
[typeid]: https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html