Skip to content

Commit 3a97625

Browse files
committed
Add non-value consuming HList mapping function
Sadly, due to rust-lang/rust#39959, we can't make take the mapper by reference
1 parent 094bc95 commit 3a97625

File tree

1 file changed

+77
-23
lines changed

1 file changed

+77
-23
lines changed

core/src/hlist.rs

+77-23
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929
//! );
3030
//! assert_eq!(folded, 9001);
3131
//!
32-
//! // Mapping over an HList
3332
//! let h3 = hlist![9000, "joe", 41f32];
34-
//! let mapped = h3.map(hlist![
35-
//! |n| n + 1,
36-
//! |s| s,
37-
//! |f| f + 1f32]);
33+
//! // Mapping over an HList (we use as_ref() to map over the HList without consuming it,
34+
//! // but you can use the value-consuming version by leaving it off.)
35+
//! let mapped = h3.as_ref().map(hlist![
36+
//! |&n| n + 1,
37+
//! |&s| s,
38+
//! |&f| f + 1f32]);
3839
//! assert_eq!(mapped, hlist![9001, "joe", 42f32]);
3940
//!
4041
//! // Plucking a value out by type
@@ -112,6 +113,10 @@ impl HList for HNil {
112113
}
113114
}
114115

116+
impl AsRef<HNil> for HNil {
117+
fn as_ref(&self) -> &HNil { self }
118+
}
119+
115120
/// Represents the most basic non-empty HList. Its value is held in `head`
116121
/// while its tail is another HList.
117122
#[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord)]
@@ -126,6 +131,10 @@ impl<H, T: HList> HList for HCons<H, T> {
126131
}
127132
}
128133

134+
impl<H, T> AsRef<HCons<H, T>> for HCons<H, T> {
135+
fn as_ref(&self) -> &HCons<H, T> { self }
136+
}
137+
129138
impl<H, T> HCons<H, T> {
130139
/// Returns the head of the list and the tail of the list as a tuple2.
131140
/// The original list is consumed
@@ -160,7 +169,7 @@ impl<H, T> HCons<H, T> {
160169
/// assert_eq!(h2, 1.23f32);
161170
/// ```
162171
pub fn h_cons<H, T: HList>(h: H, tail: T) -> HCons<H, T> {
163-
tail.prepend(h)
172+
HCons { head: h, tail: tail}
164173
}
165174

166175
/// Returns an `HList` based on the values passed in.
@@ -440,8 +449,8 @@ impl<Source> Sculptor<HNil, HNil> for Source {
440449
/// Index for Plucking the first item of type THead out of Self and the rest (IndexTail) is for the
441450
/// Plucker's remainder induce.
442451
impl<THead, TTail, SHead, STail, IndexHead, IndexTail> Sculptor<HCons<THead, TTail>,
443-
HCons<IndexHead, IndexTail>>
444-
for HCons<SHead, STail>
452+
HCons<IndexHead, IndexTail>>
453+
for HCons<SHead, STail>
445454
where HCons<SHead, STail>: Plucker<THead, IndexHead>,
446455
<HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder: Sculptor<TTail, IndexTail>
447456
{
@@ -452,9 +461,9 @@ impl<THead, TTail, SHead, STail, IndexHead, IndexTail> Sculptor<HCons<THead, TTa
452461
self.pluck();
453462
let (tail, tail_remainder): (TTail, Self::Remainder) = r.sculpt();
454463
(HCons {
455-
head: p,
456-
tail: tail,
457-
},
464+
head: p,
465+
tail: tail,
466+
},
458467
tail_remainder)
459468
}
460469
}
@@ -498,10 +507,10 @@ impl<H, Tail> IntoReverse for HCons<H, Tail>
498507

499508
fn into_reverse(self) -> Self::Output {
500509
self.tail.into_reverse() +
501-
HCons {
502-
head: self.head,
503-
tail: HNil,
504-
}
510+
HCons {
511+
head: self.head,
512+
tail: HNil,
513+
}
505514
}
506515
}
507516

@@ -547,6 +556,17 @@ impl<F> HMappable<F> for HNil {
547556
}
548557
}
549558

559+
impl<'a, F, R, H> HMappable<HCons<F, HNil>> for &'a HCons<H, HNil>
560+
where F: Fn(&'a H) -> R {
561+
type Output = HCons<R, HNil>;
562+
563+
fn map(self, f: HCons<F, HNil>) -> Self::Output {
564+
let ref h = self.head;
565+
let f = f.head;
566+
HCons { head: f(h), tail: HNil }
567+
}
568+
}
569+
550570
impl<F, MapperHeadR, MapperTail, H, Tail> HMappable<HCons<F, MapperTail>> for HCons<H, Tail>
551571
where F: FnOnce(H) -> MapperHeadR,
552572
Tail: HMappable<MapperTail>
@@ -561,6 +581,23 @@ impl<F, MapperHeadR, MapperTail, H, Tail> HMappable<HCons<F, MapperTail>> for HC
561581
}
562582
}
563583

584+
impl<'a, F, MapperHeadR, MapperTail, H, Tail> HMappable<HCons<F, MapperTail>> for &'a HCons<H, Tail>
585+
where F: Fn(&'a H) -> MapperHeadR,
586+
&'a Tail: HMappable<MapperTail>
587+
{
588+
type Output = HCons<MapperHeadR, <&'a Tail as HMappable<MapperTail>>::Output>;
589+
fn map(self, mapper: HCons<F, MapperTail>) -> Self::Output {
590+
let f = mapper.head;
591+
let mapper_tail = mapper.tail;
592+
let ref self_head = self.head;
593+
let ref self_tail = self.tail;
594+
HCons {
595+
head: f(self_head),
596+
tail: self_tail.map(mapper_tail),
597+
}
598+
}
599+
}
600+
564601
/// Foldr for HLists
565602
pub trait HFoldRightable<Folder, Init> {
566603
type Output;
@@ -602,7 +639,7 @@ impl<F, Init> HFoldRightable<F, Init> for HNil {
602639
}
603640

604641
impl<F, FolderHeadR, FolderTail, H, Tail, Init> HFoldRightable<HCons<F, FolderTail>, Init>
605-
for HCons<H, Tail>
642+
for HCons<H, Tail>
606643
where Tail: HFoldRightable<FolderTail, Init>,
607644
F: FnOnce(H, <Tail as HFoldRightable<FolderTail, Init>>::Output) -> FolderHeadR
608645
{
@@ -655,7 +692,7 @@ impl<F, Acc> HFoldLeftable<F, Acc> for HNil {
655692
}
656693

657694
impl<F, FolderHeadR, FolderTail, H, Tail, Acc> HFoldLeftable<HCons<F, FolderTail>, Acc>
658-
for HCons<H, Tail>
695+
for HCons<H, Tail>
659696
where Tail: HFoldLeftable<FolderTail, FolderHeadR>,
660697
F: FnOnce(Acc, H) -> FolderHeadR
661698
{
@@ -772,10 +809,14 @@ mod tests {
772809
#[test]
773810
#[allow(non_snake_case)]
774811
fn test_Hlist_macro() {
775-
let h1: Hlist!(i32, &str, i32) = hlist![1, "2", 3];
776-
let h2: Hlist!(i32, &str, i32,) = hlist![1, "2", 3];
777-
let h3: Hlist!(i32) = hlist![1];
778-
let h4: Hlist!(i32,) = hlist![1,];
812+
let h1: Hlist
813+
!(i32, &str, i32) = hlist![1, "2", 3];
814+
let h2: Hlist
815+
!(i32, &str, i32, ) = hlist![1, "2", 3];
816+
let h3: Hlist
817+
!(i32) = hlist![1];
818+
let h4: Hlist
819+
!(i32, ) = hlist![1,];
779820
assert_eq!(h1, h2);
780821
assert_eq!(h3, h4);
781822
}
@@ -838,9 +879,22 @@ mod tests {
838879
}
839880

840881
#[test]
841-
fn test_map() {
882+
fn test_map_consuming() {
883+
let h = hlist![9000, "joe", 41f32];
884+
let mapped = h.map(hlist![
885+
|n| n + 1,
886+
|s| s,
887+
|f| f + 1f32]);
888+
assert_eq!(mapped, hlist![9001, "joe", 42f32]);
889+
}
890+
891+
#[test]
892+
fn test_map_non_consuming() {
842893
let h = hlist![9000, "joe", 41f32];
843-
let mapped = h.map(hlist![|n| n + 1, |s| s, |f| f + 1f32]);
894+
let mapped = h.as_ref().map(hlist![
895+
|&n| n + 1,
896+
|&s| s,
897+
|&f| f + 1f32]);
844898
assert_eq!(mapped, hlist![9001, "joe", 42f32]);
845899
}
846900

0 commit comments

Comments
 (0)