-
-
Save Sgeo/ecee21895815fb2066e3 to your computer and use it in GitHub Desktop.
use std::marker::PhantomData; | |
pub enum Void {} | |
impl Void { | |
fn any(&self) -> ! { | |
match *self {} | |
} | |
} | |
trait UnwrapVoid<R> { | |
fn unwrap_void(self) -> R; | |
} | |
impl<R> UnwrapVoid<R> for Result<R, Void> { | |
fn unwrap_void(self) -> R { | |
match self { | |
Ok(r) => r, | |
Err(void) => void.any() | |
} | |
} | |
} | |
#[allow(dead_code)] | |
enum Here {} | |
#[allow(dead_code)] | |
struct There<T>(PhantomData<T>); | |
enum Cans<Head, Tail> { | |
Here(Head), | |
There(Tail) | |
} | |
trait NewCans<Item, Where> { | |
fn new(item: Item) -> Self; | |
} | |
impl<Item, Tail> NewCans<Item, Here> for Cans<Item, Tail> { | |
fn new(item: Item) -> Self { | |
Cans::Here(item) | |
} | |
} | |
impl<Item, Head, Tail, TailIndex> NewCans<Item, There<TailIndex>> for Cans<Head, Tail> | |
where Tail: NewCans<Item, TailIndex> { | |
fn new(item: Item) -> Self { | |
Cans::There(NewCans::new(item)) | |
} | |
} | |
impl<Head, Tail> Cans<Head, Tail> { | |
pub fn new<Item, Where>(item: Item) -> Self | |
where Self: NewCans<Item, Where> { | |
NewCans::new(item) | |
} | |
} | |
trait Find<T, Where> { | |
fn find(&self) -> Option<&T>; | |
fn find_mut(&mut self) -> Option<&mut T>; | |
} | |
impl<T, Tail> Find<T, Here> for Cans<T, Tail> { | |
fn find(&self) -> Option<&T> { | |
match *self { | |
Cans::Here(ref t) => Some(t), | |
Cans::There(_) => None, | |
} | |
} | |
fn find_mut(&mut self) -> Option<&mut T> { | |
match *self { | |
Cans::Here(ref mut t) => Some(t), | |
Cans::There(_) => None | |
} | |
} | |
} | |
impl<Head, T, Tail, TailIndex> Find<T, There<TailIndex>> for Cans<Head, Tail> | |
where Tail: Find<T, TailIndex> { | |
fn find(&self) -> Option<&T> { | |
match *self { | |
Cans::Here(_) => None, | |
Cans::There(ref there) => there.find() | |
} | |
} | |
fn find_mut(&mut self) -> Option<&mut T> { | |
match *self { | |
Cans::Here(_) => None, | |
Cans::There(ref mut there) => there.find_mut() | |
} | |
} | |
} | |
trait Select<T, R, Where> { | |
type Remainder; | |
fn select<F>(self, F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R; | |
} | |
impl<T, R, Tail> Select<T, R, Here> for Cans<T, Tail> { | |
type Remainder = Tail; | |
fn select<F>(self, f: F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R { | |
match self { | |
Cans::Here(t) => Ok(f(t)), | |
Cans::There(there) => Err(there) | |
} | |
} | |
} | |
impl<T, R, Head, Tail, TailIndex> Select<T, R, There<TailIndex>> for Cans<Head, Tail> | |
where Tail: Select<T, R, TailIndex> { | |
type Remainder = Cans<Head, Tail::Remainder>; | |
fn select<F>(self, f: F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R { | |
match self { | |
Cans::Here(t) => Err(Cans::Here(t)), | |
Cans::There(there) => there.select(f).map_err(|tail| Cans::There(tail)) | |
} | |
} | |
} | |
impl<T, R, Selectable, Index> Select<T, R, Index> for Result<R, Selectable> | |
where Selectable: Select<T, R, Index> { | |
type Remainder = Selectable::Remainder; | |
fn select<F>(self, f: F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R{ | |
self.or_else(|sel| sel.select(f)) | |
} | |
} | |
trait Reshape<Dest, Indices> { | |
fn reshape(self) -> Dest; | |
} | |
impl<Dest> Reshape<Dest, ()> for Void { | |
fn reshape(self) -> Dest { | |
self.any() | |
} | |
} | |
impl<Dest, SHead, STail, HIndex, TIndices> Reshape<Dest, (HIndex, TIndices)> for Cans<SHead, STail> | |
where STail: Reshape<Dest, TIndices>, | |
Dest: NewCans<SHead, HIndex> { | |
fn reshape(self) -> Dest { | |
match self { | |
Cans::Here(shead) => NewCans::new(shead), | |
Cans::There(stail) => stail.reshape() | |
} | |
} | |
} | |
fn main() { | |
let cans: Cans<i32, Cans<String, Void>> = Cans::new("Hello".to_string()); | |
{ | |
let s: Option<&String> = cans.find(); | |
let t: Option<&i32> = cans.find(); | |
println!("{:?}", s); | |
println!("{:?}", t); | |
} | |
let foo = cans.select(|s: String| "It's a string!").select(|i: i32| "It's an i32!").unwrap_void(); | |
println!("{:?}", foo); | |
let cans2: Cans<i32, Cans<String, Void>> = Cans::new("Hello".to_string()); | |
let cans3: Cans<String, Cans<i32, Cans<i64, Void>>> = cans2.reshape(); | |
} |
I can work on uploading it to crates.io, but I can't promise to pay attention to maintenance long term.
May I ask why you want this specific code? I see some similar things on crates.io already, some of which are focused on error handling, some of which aren't.
I can work on uploading it to crates.io, but I can't promise to pay attention to maintenance long term.
May I ask why you want this specific code? I see some similar things on crates.io already, some of which are focused on error handling, some of which aren't.
Sorry for 2 weeks of silence
This is the cleanest implementation I've seen so far, and also the smallest one. It could be refactored to be a little more better named, like Polymorph
or Poly
instead of Cans
#![feature(decl_macro)]
use std::marker::PhantomData;
#[derive(Clone, Debug)]
pub enum Void {}
impl Void {
fn any(&self) -> ! {
match *self {}
}
}
#[allow(dead_code)]
pub trait Unwrap<R> {
fn unwrap(self) -> R;
}
impl<R> Unwrap<R> for Result<R, Void> {
fn unwrap(self) -> R {
match self {
Ok(r) => r,
Err(void) => void.any(),
}
}
}
pub enum HeadMarker {}
pub struct TailMarker<T>(PhantomData<T>);
#[derive(Clone, Debug)]
pub enum Poly_<Head, Tail> {
Head(Head),
Tail(Tail),
}
pub trait Poly<Item, Where> {
fn new(item: Item) -> Self;
}
impl<Item, Tail> Poly<Item, HeadMarker> for Poly_<Item, Tail> {
fn new(item: Item) -> Self {
Poly_::Head(item)
}
}
impl<Item, Head, Tail, TailIndex> Poly<Item, TailMarker<TailIndex>> for Poly_<Head, Tail>
where
Tail: Poly<Item, TailIndex>,
{
fn new(item: Item) -> Self {
Poly_::Tail(Poly::new(item))
}
}
#[allow(dead_code)]
impl<A, B> Poly_<A, B> {
pub fn new<Item, Where>(item: Item) -> Self
where
Self: Poly<Item, Where>,
{
Poly::new(item)
}
}
pub trait Find<T, Where> {
/// Given that `P` is isomorphic to `poly![A, B]`, one of the following method calls
/// will successfully return `Some(&T)`: `P.find() as A`, `P.find() as B`
///
/// Example:
/// ```rs
/// use poly::{poly, Poly, Find, Void};
///
/// fn test() {
/// let p: poly![u32, i32] = Poly::new(123u32);
/// let a: Option<&u32> = p.find();
/// if let Some(a) = a {
/// println!("{a}");
/// }
/// }
/// ```
fn find(&self) -> Option<&T>;
fn find_mut(&mut self) -> Option<&mut T>;
}
impl<T, Tail> Find<T, HeadMarker> for Poly_<T, Tail> {
fn find(&self) -> Option<&T> {
match *self {
Poly_::Head(ref t) => Some(t),
Poly_::Tail(_) => None,
}
}
fn find_mut(&mut self) -> Option<&mut T> {
match *self {
Poly_::Head(ref mut t) => Some(t),
Poly_::Tail(_) => None,
}
}
}
impl<Head, T, Tail, TailIndex> Find<T, TailMarker<TailIndex>> for Poly_<Head, Tail>
where
Tail: Find<T, TailIndex>,
{
fn find(&self) -> Option<&T> {
match *self {
Poly_::Head(_) => None,
Poly_::Tail(ref there) => there.find(),
}
}
fn find_mut(&mut self) -> Option<&mut T> {
match *self {
Poly_::Head(_) => None,
Poly_::Tail(ref mut there) => there.find_mut(),
}
}
}
pub trait Select<T, R, Where> {
type Remainder;
fn select<F>(self, _: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R;
}
impl<T, R, Tail> Select<T, R, HeadMarker> for Poly_<T, Tail> {
type Remainder = Tail;
fn select<F>(self, f: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R,
{
match self {
Poly_::Head(t) => Ok(f(t)),
Poly_::Tail(there) => Err(there),
}
}
}
impl<T, R, Head, Tail, TailIndex> Select<T, R, TailMarker<TailIndex>> for Poly_<Head, Tail>
where
Tail: Select<T, R, TailIndex>,
{
type Remainder = Poly_<Head, Tail::Remainder>;
fn select<F>(self, f: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R,
{
match self {
Poly_::Head(t) => Err(Poly_::Head(t)),
Poly_::Tail(there) => there.select(f).map_err(|tail| Poly_::Tail(tail)),
}
}
}
impl<T, R, Selectable, Index> Select<T, R, Index> for Result<R, Selectable>
where
Selectable: Select<T, R, Index>,
{
type Remainder = Selectable::Remainder;
fn select<F>(self, f: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R,
{
self.or_else(|sel| sel.select(f))
}
}
pub trait Mash<Dest, Indices> {
fn mash(self) -> Dest;
}
impl<Dest> Mash<Dest, ()> for Void {
fn mash(self) -> Dest {
self.any()
}
}
impl<Dest, SHead, STail, HIndex, TIndices> Mash<Dest, (HIndex, TIndices)> for Poly_<SHead, STail>
where
STail: Mash<Dest, TIndices>,
Dest: Poly<SHead, HIndex>,
{
fn mash(self) -> Dest {
match self {
Poly_::Head(shead) => Poly::new(shead),
Poly_::Tail(stail) => stail.mash(),
}
}
}
pub macro poly {
() => {
$crate::poly::Void
},
($head:ty $(, $tail:ty)*) => {
$crate::poly::Poly_<$head, poly!($($tail),*) >
}
}
For example
Reshape
could be left as is instead of Mash
Could you please publish this to crates.io? Or can you grant me permission to do it if you can't or don't want to do it yourself?