use core::ops::Deref;
pub mod premade {
mod mutref;
pub use mutref::{MutRefDatum, DatumMutRef};
}
#[derive(Copy, Clone, Eq, Hash, Debug)]
pub enum Datum<TextType, ExtraType, DatumRef>
where DatumRef: DerefTryMut<Target = Datum<TextType, ExtraType, DatumRef>>,
{
Text(TextType),
Combination {
operator: DatumRef,
operands: DatumRef,
},
EmptyNest,
List {
elem: DatumRef,
next: DatumRef,
},
EmptyList,
Extra(ExtraType),
}
#[allow(clippy::match_same_arms)]
impl<TT1, TT2, ET1, ET2, DR1, DR2>
PartialEq<Datum<TT2, ET2, DR2>>
for Datum<TT1, ET1, DR1>
where DR1: DerefTryMut<Target = Datum<TT1, ET1, DR1>>,
DR2: DerefTryMut<Target = Datum<TT2, ET2, DR2>>,
TT1: PartialEq<TT2>,
ET1: PartialEq<ET2>,
{
fn eq(&self, other: &Datum<TT2, ET2, DR2>) -> bool {
use Datum::*;
let (mut left, mut right) = (self, other);
loop {
match (left, right) {
(Text(txt1), Text(txt2))
=> break *txt1 == *txt2,
(Combination{operator: rtr1, operands: rnds1},
Combination{operator: rtr2, operands: rnds2})
=> if **rnds1 == **rnds2 {
left = &**rtr1;
right = &**rtr2;
} else { break false },
(EmptyNest, EmptyNest)
=> break true,
(List{elem: e1, next: n1}, List{elem: e2, next: n2})
=> if **e1 == **e2 {
left = &**n1;
right = &**n2;
} else { break false },
(EmptyList, EmptyList)
=> break true,
(Extra(et1), Extra(et2))
=> break et1 == et2,
_
=> break false
}
}
}
}
pub trait DerefTryMut: Deref
where <Self as Deref>::Target: Sized,
{
fn get_mut(this: &mut Self) -> Option<&mut Self::Target>;
}
#[cfg(test)]
mod tests {
use super::{*, premade::*};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct DummyText;
#[test]
fn equality_same() {
use Datum::*;
assert_eq!(Text::<_, (), DatumMutRef<'_, _, ()>>(DummyText),
Text::<_, (), DatumMutRef<'_, _, ()>>(DummyText));
assert_eq!(Combination::<DummyText, (), DatumMutRef<'_, _, ()>>{
operator: DatumMutRef(&mut EmptyNest),
operands: DatumMutRef(&mut EmptyList)},
Combination::<DummyText, (), DatumMutRef<'_, _, ()>>{
operator: DatumMutRef(&mut EmptyNest),
operands: DatumMutRef(&mut EmptyList)});
assert_eq!(EmptyNest::<DummyText, (), DatumMutRef<'_, _, ()>>,
EmptyNest::<DummyText, (), DatumMutRef<'_, _, ()>>);
assert_eq!(List::<DummyText, (), DatumMutRef<'_, _, ()>>{
elem: DatumMutRef(&mut EmptyNest),
next: DatumMutRef(&mut EmptyList)},
List::<DummyText, (), DatumMutRef<'_, _, ()>>{
elem: DatumMutRef(&mut EmptyNest),
next: DatumMutRef(&mut EmptyList)});
assert_eq!(EmptyList::<DummyText, (), DatumMutRef<'_, _, ()>>,
EmptyList::<DummyText, (), DatumMutRef<'_, _, ()>>);
assert_eq!(Extra::<DummyText, (), DatumMutRef<'_, _, ()>>(()),
Extra::<DummyText, (), DatumMutRef<'_, _, ()>>(()));
}
mod datumref {
use super::*;
#[derive(Copy, Clone, Debug)]
pub(super) struct DatumRef<'d, TT, ET>(
pub(super) &'d Datum<TT, ET, DatumRef<'d, TT, ET>>);
impl<'d, TT, ET> Deref for DatumRef<'d, TT, ET>
{
type Target = Datum<TT, ET, DatumRef<'d, TT, ET>>;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<TT, ET> DerefTryMut for DatumRef<'_, TT, ET>
{
fn get_mut(_this: &mut Self) -> Option<&mut Self::Target> {
None
}
}
}
#[test]
fn equality_diff_ref() {
use Datum::*;
use datumref::DatumRef;
assert_eq!(Text::<_, (), DatumMutRef<'_, _, ()>>(DummyText),
Text::<_, (), DatumRef<'_, _, ()>>(DummyText));
assert_eq!(Combination::<DummyText, (), DatumMutRef<'_, _, ()>>{
operator: DatumMutRef(&mut EmptyNest),
operands: DatumMutRef(&mut EmptyList)},
Combination::<DummyText, (), DatumRef<'_, _, ()>>{
operator: DatumRef(&EmptyNest),
operands: DatumRef(&EmptyList)});
assert_eq!(EmptyNest::<DummyText, (), DatumMutRef<'_, _, ()>>,
EmptyNest::<DummyText, (), DatumRef<'_, _, ()>>);
assert_eq!(List::<DummyText, (), DatumMutRef<'_, _, ()>>{
elem: DatumMutRef(&mut EmptyNest),
next: DatumMutRef(&mut EmptyList)},
List::<DummyText, (), DatumRef<'_, _, ()>>{
elem: DatumRef(&EmptyNest),
next: DatumRef(&EmptyList)});
assert_eq!(EmptyList::<DummyText, (), DatumMutRef<'_, _, ()>>,
EmptyList::<DummyText, (), DatumRef<'_, _, ()>>);
assert!(Extra::<DummyText, (), DatumMutRef<'_, _, ()>>(())
== Extra::<DummyText, (), DatumRef<'_, _, ()>>(()));
}
#[test]
fn copy_clone() {
use Datum::*;
use datumref::DatumRef;
let a = List::<DummyText, (), DatumRef<'_, _, ()>>{
elem: DatumRef(&EmptyNest::<_, (), DatumRef<'_, _, ()>>),
next: DatumRef(&EmptyList::<_, (), DatumRef<'_, _, ()>>)};
let b = a;
assert_eq!(a, b);
let c = List::<DummyText, (), DatumRef<'_, _, ()>>{
elem: DatumRef(&EmptyNest::<_, (), DatumRef<'_, _, ()>>),
next: DatumRef(&EmptyList::<_, (), DatumRef<'_, _, ()>>)};
#[allow(clippy::clone_on_copy)]
let d = c.clone();
assert_eq!(c, d);
}
}