coremem_types: Enum: implement mutable dispatch
This commit is contained in:
@@ -60,20 +60,20 @@ pub trait DiscrHandler<N: Peano, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// helper used to call F with some (yet-to-be-determined) index of I
|
/// helper used to call F with some (yet-to-be-determined) index of I
|
||||||
struct DispatchIndexable<'a, I, F> {
|
struct DispatchIndexable<I, F> {
|
||||||
indexable: &'a I,
|
indexable: I,
|
||||||
f: F,
|
f: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, F> DispatchIndexable<'a, I, F> {
|
impl<I, F> DispatchIndexable<I, F> {
|
||||||
fn new(indexable: &'a I, f: F) -> Self {
|
fn new(indexable: I, f: F) -> Self {
|
||||||
Self { indexable, f }
|
Self { indexable, f }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// base case: we tried to index all cases >= 0 and failed.
|
// base case: we tried to index all cases >= 0 and failed.
|
||||||
// this should be unreachable.
|
// this should be unreachable.
|
||||||
impl<'a, I, F, R> DiscrHandler<P0, R> for DispatchIndexable<'a, I, F>
|
impl<'a, I, F, R> DiscrHandler<P0, R> for DispatchIndexable<I, F>
|
||||||
{
|
{
|
||||||
type PrevOrPanic = Self;
|
type PrevOrPanic = Self;
|
||||||
fn call(self) -> R {
|
fn call(self) -> R {
|
||||||
@@ -86,7 +86,7 @@ impl<'a, I, F, R> DiscrHandler<P0, R> for DispatchIndexable<'a, I, F>
|
|||||||
|
|
||||||
// inductive case: if we know how dispatch up through P, and the collection is P+1-indexable, then we can
|
// inductive case: if we know how dispatch up through P, and the collection is P+1-indexable, then we can
|
||||||
// index up through P+1
|
// index up through P+1
|
||||||
impl<'a, I, F, P: Peano, R> DiscrHandler<PNext<P>, R> for DispatchIndexable<'a, I, F>
|
impl<'a, I, F, P: Peano, R> DiscrHandler<PNext<P>, R> for DispatchIndexable<&'a I, F>
|
||||||
where
|
where
|
||||||
I: Indexable<P>,
|
I: Indexable<P>,
|
||||||
I::Element: Copy,
|
I::Element: Copy,
|
||||||
@@ -102,6 +102,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mutable indexing case: if we have a mutable handle to the Indexable,
|
||||||
|
// then assume the variants want to have mutable references to the items.
|
||||||
|
impl<'a, I, F, P: Peano, R> DiscrHandler<PNext<P>, R> for DispatchIndexable<&'a mut I, F>
|
||||||
|
where
|
||||||
|
I: Indexable<P>,
|
||||||
|
I::Element: 'a,
|
||||||
|
F: VariantHandler<P, &'a mut I::Element, R>,
|
||||||
|
Self: DiscrHandler<P, R>,
|
||||||
|
{
|
||||||
|
type PrevOrPanic = Self;
|
||||||
|
fn call(self) -> R {
|
||||||
|
self.f.call(self.indexable.get_mut())
|
||||||
|
}
|
||||||
|
fn prev(self) -> Self::PrevOrPanic {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||||
#[cfg_attr(feature = "fmt", derive(Debug))]
|
#[cfg_attr(feature = "fmt", derive(Debug))]
|
||||||
#[derive(Copy, Clone, Default, PartialEq)]
|
#[derive(Copy, Clone, Default, PartialEq)]
|
||||||
@@ -145,21 +163,29 @@ where
|
|||||||
impl<D, L> Enum<D, L>
|
impl<D, L> Enum<D, L>
|
||||||
where Self: EnumRequirements
|
where Self: EnumRequirements
|
||||||
{
|
{
|
||||||
|
/// invoke the closure on the active variant, passing the variant by-value
|
||||||
fn dispatch<'a, F, R>(&'a self, f: F) -> R
|
fn dispatch<'a, F, R>(&'a self, f: F) -> R
|
||||||
where
|
where
|
||||||
DispatchIndexable<'a, L, F>: DiscrHandler<<Self as EnumRequirements>::NumVariants, R>
|
DispatchIndexable<&'a L, F>: DiscrHandler<<Self as EnumRequirements>::NumVariants, R>
|
||||||
{
|
{
|
||||||
self.decode_discr().dispatch(DispatchIndexable::new(&self.1, f))
|
self.decode_discr().dispatch(DispatchIndexable::new(&self.1, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// invoke the closure on the active variant, passing the variant by mutable reference
|
||||||
|
fn dispatch_mut<'a, F, R>(&'a mut self, f: F) -> R
|
||||||
|
where
|
||||||
|
DispatchIndexable<&'a mut L, F>: DiscrHandler<<Self as EnumRequirements>::NumVariants, R>
|
||||||
|
{
|
||||||
|
self.decode_discr().dispatch(DispatchIndexable::new(&mut self.1, f))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
|
||||||
fn dispatch() {
|
struct ImmutableReceiver;
|
||||||
struct Receiver;
|
impl<P: Peano, T: TryInto<i32>> VariantHandler<P, T, i32> for ImmutableReceiver {
|
||||||
impl<P: Peano, T: TryInto<i32>> VariantHandler<P, T, i32> for Receiver {
|
|
||||||
fn call(&self, v: T) -> i32 {
|
fn call(&self, v: T) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
v.try_into().unwrap_unchecked() + P::VALUE as i32 + 5
|
v.try_into().unwrap_unchecked() + P::VALUE as i32 + 5
|
||||||
@@ -167,13 +193,34 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Add4Receiver;
|
||||||
|
impl<P: Peano, T: TryInto<i32> + TryFrom<i32> + Copy> VariantHandler<P, &mut T, ()> for Add4Receiver {
|
||||||
|
fn call(&self, v: &mut T) -> () {
|
||||||
|
unsafe {
|
||||||
|
*v = ((*v).try_into().unwrap_unchecked() + 4).try_into().unwrap_unchecked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dispatch() {
|
||||||
let mut e: Enum<(Discr<P3>,), List<(u32, i32, u8)>> = Enum::default();
|
let mut e: Enum<(Discr<P3>,), List<(u32, i32, u8)>> = Enum::default();
|
||||||
assert_eq!(e.dispatch(Receiver), 5);
|
assert_eq!(e.dispatch(ImmutableReceiver), 5);
|
||||||
|
|
||||||
e.encode_discr(Discr::new(1));
|
e.encode_discr(Discr::new(1));
|
||||||
assert_eq!(e.dispatch(Receiver), 6);
|
assert_eq!(e.dispatch(ImmutableReceiver), 6);
|
||||||
|
|
||||||
e.encode_discr(Discr::new(2));
|
e.encode_discr(Discr::new(2));
|
||||||
assert_eq!(e.dispatch(Receiver), 7);
|
assert_eq!(e.dispatch(ImmutableReceiver), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dispatch_mut() {
|
||||||
|
let mut e: Enum<(Discr<P3>,), List<(u32, i32, u8)>> = Enum::default();
|
||||||
|
e.dispatch_mut(Add4Receiver);
|
||||||
|
assert_eq!(e.dispatch(ImmutableReceiver), 9);
|
||||||
|
|
||||||
|
e.encode_discr(Discr::new(1));
|
||||||
|
assert_eq!(e.dispatch(ImmutableReceiver), 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user