cross: list: extend fold
to work by reference.
This commit is contained in:
@@ -309,6 +309,7 @@ pub trait SplitHead {
|
||||
type Head;
|
||||
type Tail;
|
||||
fn split(self) -> (Self::Head, Self::Tail);
|
||||
fn split_ref<'a>(&'a self) -> (&'a Self::Head, &'a Self::Tail);
|
||||
}
|
||||
impl<H, T> SplitHead for Node<H, T> {
|
||||
type Head = H;
|
||||
@@ -316,6 +317,9 @@ impl<H, T> SplitHead for Node<H, T> {
|
||||
fn split(self) -> (Self::Head, Self::Tail) {
|
||||
(self.head, self.tail)
|
||||
}
|
||||
fn split_ref<'a>(&'a self) -> (&'a Self::Head, &'a Self::Tail) {
|
||||
(&self.head, &self.tail)
|
||||
}
|
||||
}
|
||||
|
||||
/// these are exported for the convenience of potential consumers: not needed internally
|
||||
|
@@ -97,7 +97,7 @@ where
|
||||
// - [x] map (calls into fold, with the accumulator being Appendable::append)
|
||||
// - [ ] visit (calls into fold, with a no-op accumulator)
|
||||
// - [ ] visit_ref, visit_mut (calls as_ref/as_mut, then visit)
|
||||
// - [ ] enumerate (calls fold, with the accumulator being a Peano counter + value copy)
|
||||
// - [x] enumerate (calls fold, with the accumulator being a Peano counter + value copy)
|
||||
|
||||
pub trait ListConsumer<L> {
|
||||
type Output;
|
||||
@@ -113,6 +113,7 @@ pub trait FoldOp<State, V> {
|
||||
|
||||
pub struct FoldImpl<Op, State>(Op, State);
|
||||
|
||||
//////// fold by-value
|
||||
impl<Op, State> ListConsumer<Empty> for FoldImpl<Op, State> {
|
||||
type Output = State;
|
||||
fn consume(self, _l: Empty) -> Self::Output {
|
||||
@@ -134,6 +135,28 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
//////// fold by-ref
|
||||
impl<Op, State> ListConsumer<&Empty> for FoldImpl<Op, State> {
|
||||
type Output = State;
|
||||
fn consume(self, _l: &Empty) -> Self::Output {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, H, T, Op, State> ListConsumer<&'a Node<H, T>> for FoldImpl<Op, State>
|
||||
where
|
||||
Op: FoldOp<State, &'a H>,
|
||||
FoldImpl<Op, Op::Output>: ListConsumer<&'a T>,
|
||||
{
|
||||
type Output = <FoldImpl<Op, Op::Output> as ListConsumer<&'a T>>::Output;
|
||||
fn consume(self, l: &'a Node<H, T>) -> Self::Output {
|
||||
let FoldImpl(op, state) = self;
|
||||
let (head, tail) = l.split_ref();
|
||||
let next_state = op.feed(state, head);
|
||||
FoldImpl(op, next_state).consume(tail)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Fold<Op, Init> {
|
||||
type Output;
|
||||
fn fold(self, op: Op, init: Init) -> Self::Output;
|
||||
@@ -309,6 +332,32 @@ mod test {
|
||||
assert_eq!(list.fold(Sum, 2i32), 28f32);
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct NotCopy(i32);
|
||||
|
||||
struct SumRef;
|
||||
impl FoldOp<i32, &NotCopy> for SumRef {
|
||||
type Output = i32;
|
||||
fn feed(&self, prev: i32, next: &NotCopy) -> Self::Output {
|
||||
prev + next.0
|
||||
}
|
||||
}
|
||||
impl FoldOp<i32, &i32> for SumRef {
|
||||
type Output = i32;
|
||||
fn feed(&self, prev: i32, next: &i32) -> Self::Output {
|
||||
prev + *next
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fold_ref() {
|
||||
let list = &(3i32, NotCopy(4i32), 5i32).into_list();
|
||||
assert_eq!(list.fold(SumRef, 2i32), 14i32);
|
||||
assert!(list == list); // just check that it wasn't consumed
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn reverse_empty() {
|
||||
assert!(Empty::default().reverse() == Empty::default());
|
||||
|
Reference in New Issue
Block a user