cisness
Crate containing a type to "live-witness" that two types are the same ("cismutable").
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, 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. 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 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.
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"
}
}
#[derive(Default)]
pub struct AdventuringParty {
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);
}
pub fn get_oldest_age_of_type<M: Any + PartyMember>(&self) -> Option<<M as PartyMember>::Age>
{
let type_id = TypeId::of::<M>();
match type_id {
t if t == TypeId::of::<Human>() => {
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();
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 };
let output = Some("[ELDRICH MEMETIC HAZARD]");
w.owned(output)
}
_ => None
}
}
}
The Name
Yes, it's intentional. The author is trans 🏳️⚧️, and finds it funny.