diff --git a/crates/types/src/compound/enumerated.rs b/crates/types/src/compound/enumerated.rs index 18df3dc..32725c5 100644 --- a/crates/types/src/compound/enumerated.rs +++ b/crates/types/src/compound/enumerated.rs @@ -60,20 +60,20 @@ pub trait DiscrHandler { } /// helper used to call F with some (yet-to-be-determined) index of I -struct DispatchIndexable<'a, I, F> { - indexable: &'a I, +struct DispatchIndexable { + indexable: I, f: F, } -impl<'a, I, F> DispatchIndexable<'a, I, F> { - fn new(indexable: &'a I, f: F) -> Self { +impl DispatchIndexable { + fn new(indexable: I, f: F) -> Self { Self { indexable, f } } } // base case: we tried to index all cases >= 0 and failed. // this should be unreachable. -impl<'a, I, F, R> DiscrHandler for DispatchIndexable<'a, I, F> +impl<'a, I, F, R> DiscrHandler for DispatchIndexable { type PrevOrPanic = Self; fn call(self) -> R { @@ -86,7 +86,7 @@ impl<'a, I, F, R> DiscrHandler 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 // index up through P+1 -impl<'a, I, F, P: Peano, R> DiscrHandler, R> for DispatchIndexable<'a, I, F> +impl<'a, I, F, P: Peano, R> DiscrHandler, R> for DispatchIndexable<&'a I, F> where I: Indexable

, 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, R> for DispatchIndexable<&'a mut I, F> +where + I: Indexable

, + I::Element: 'a, + F: VariantHandler, + Self: DiscrHandler, +{ + 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 = "fmt", derive(Debug))] #[derive(Copy, Clone, Default, PartialEq)] @@ -145,35 +163,64 @@ where impl Enum 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 where - DispatchIndexable<'a, L, F>: DiscrHandler<::NumVariants, R> + DispatchIndexable<&'a L, F>: DiscrHandler<::NumVariants, R> { 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<::NumVariants, R> + { + self.decode_discr().dispatch(DispatchIndexable::new(&mut self.1, f)) + } } #[cfg(test)] mod test { use super::*; - #[test] - fn dispatch() { - struct Receiver; - impl> VariantHandler for Receiver { - fn call(&self, v: T) -> i32 { - unsafe { - v.try_into().unwrap_unchecked() + P::VALUE as i32 + 5 - } + + struct ImmutableReceiver; + impl> VariantHandler for ImmutableReceiver { + fn call(&self, v: T) -> i32 { + unsafe { + v.try_into().unwrap_unchecked() + P::VALUE as i32 + 5 } } + } + struct Add4Receiver; + impl + TryFrom + Copy> VariantHandler 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,), List<(u32, i32, u8)>> = Enum::default(); - assert_eq!(e.dispatch(Receiver), 5); + assert_eq!(e.dispatch(ImmutableReceiver), 5); e.encode_discr(Discr::new(1)); - assert_eq!(e.dispatch(Receiver), 6); + assert_eq!(e.dispatch(ImmutableReceiver), 6); 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,), 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); } }