cross: list: extend fold
to work by reference.
This commit is contained in:
@@ -309,6 +309,7 @@ pub trait SplitHead {
|
|||||||
type Head;
|
type Head;
|
||||||
type Tail;
|
type Tail;
|
||||||
fn split(self) -> (Self::Head, Self::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> {
|
impl<H, T> SplitHead for Node<H, T> {
|
||||||
type Head = H;
|
type Head = H;
|
||||||
@@ -316,6 +317,9 @@ impl<H, T> SplitHead for Node<H, T> {
|
|||||||
fn split(self) -> (Self::Head, Self::Tail) {
|
fn split(self) -> (Self::Head, Self::Tail) {
|
||||||
(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
|
/// 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)
|
// - [x] map (calls into fold, with the accumulator being Appendable::append)
|
||||||
// - [ ] visit (calls into fold, with a no-op accumulator)
|
// - [ ] visit (calls into fold, with a no-op accumulator)
|
||||||
// - [ ] visit_ref, visit_mut (calls as_ref/as_mut, then visit)
|
// - [ ] 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> {
|
pub trait ListConsumer<L> {
|
||||||
type Output;
|
type Output;
|
||||||
@@ -113,6 +113,7 @@ pub trait FoldOp<State, V> {
|
|||||||
|
|
||||||
pub struct FoldImpl<Op, State>(Op, State);
|
pub struct FoldImpl<Op, State>(Op, State);
|
||||||
|
|
||||||
|
//////// fold by-value
|
||||||
impl<Op, State> ListConsumer<Empty> for FoldImpl<Op, State> {
|
impl<Op, State> ListConsumer<Empty> for FoldImpl<Op, State> {
|
||||||
type Output = State;
|
type Output = State;
|
||||||
fn consume(self, _l: Empty) -> Self::Output {
|
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> {
|
pub trait Fold<Op, Init> {
|
||||||
type Output;
|
type Output;
|
||||||
fn fold(self, op: Op, init: Init) -> Self::Output;
|
fn fold(self, op: Op, init: Init) -> Self::Output;
|
||||||
@@ -309,6 +332,32 @@ mod test {
|
|||||||
assert_eq!(list.fold(Sum, 2i32), 28f32);
|
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]
|
#[test]
|
||||||
fn reverse_empty() {
|
fn reverse_empty() {
|
||||||
assert!(Empty::default().reverse() == Empty::default());
|
assert!(Empty::default().reverse() == Empty::default());
|
||||||
|
Reference in New Issue
Block a user