frunk_core/hlist.rs
1//! Module that holds HList data structures, implementations, and typeclasses.
2//!
3//! Typically, you would want to use the `hlist!` macro to make it easier
4//! for you to use HList.
5//!
6//! # Examples
7//!
8//! ```
9//! # fn main() {
10//! use frunk_core::{hlist, HList, poly_fn};
11//!
12//! let h = hlist![1, "hi"];
13//! assert_eq!(h.len(), 2);
14//! let (a, b) = h.into_tuple2();
15//! assert_eq!(a, 1);
16//! assert_eq!(b, "hi");
17//!
18//! // Reverse
19//! let h1 = hlist![true, "hi"];
20//! assert_eq!(h1.into_reverse(), hlist!["hi", true]);
21//!
22//! // foldr (foldl also available)
23//! let h2 = hlist![1, false, 42f32];
24//! let folded = h2.foldr(
25//! hlist![|acc, i| i + acc,
26//! |acc, _| if acc > 42f32 { 9000 } else { 0 },
27//! |acc, f| f + acc],
28//! 1f32
29//! );
30//! assert_eq!(folded, 9001);
31//!
32//! let h3 = hlist![9000, "joe", 41f32];
33//! // Mapping over an HList with a polymorphic function,
34//! // declared using the poly_fn! macro (you can choose to impl
35//! // it manually)
36//! let mapped = h3.map(
37//! poly_fn![
38//! |f: f32| -> f32 { f + 1f32 },
39//! |i: isize| -> isize { i + 1 },
40//! ['a] |s: &'a str| -> &'a str { s }
41//! ]);
42//! assert_eq!(mapped, hlist![9001, "joe", 42f32]);
43//!
44//! // Plucking a value out by type
45//! let h4 = hlist![1, "hello", true, 42f32];
46//! let (t, remainder): (bool, _) = h4.pluck();
47//! assert!(t);
48//! assert_eq!(remainder, hlist![1, "hello", 42f32]);
49//!
50//! // Resculpting an HList
51//! let h5 = hlist![9000, "joe", 41f32, true];
52//! let (reshaped, remainder2): (HList![f32, i32, &str], _) = h5.sculpt();
53//! assert_eq!(reshaped, hlist![41f32, 9000, "joe"]);
54//! assert_eq!(remainder2, hlist![true]);
55//! # }
56//! ```
57
58use crate::indices::{Here, Suffixed, There};
59use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef};
60#[cfg(feature = "alloc")]
61use alloc::vec::Vec;
62#[cfg(feature = "serde")]
63use serde::{Deserialize, Serialize};
64
65use core::ops::Add;
66
67/// Typeclass for HList-y behaviour
68///
69/// An HList is a heterogeneous list, one that is statically typed at compile time. In simple terms,
70/// it is just an arbitrarily-nested Tuple2.
71pub trait HList: Sized {
72 /// Returns the length of a given HList type without making use of any references, or
73 /// in fact, any values at all.
74 ///
75 /// # Examples
76 /// ```
77 /// # fn main() {
78 /// use frunk::prelude::*;
79 /// use frunk_core::HList;
80 ///
81 /// assert_eq!(<HList![i32, bool, f32]>::LEN, 3);
82 /// # }
83 /// ```
84 const LEN: usize;
85
86 /// Returns the length of a given HList
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// # fn main() {
92 /// use frunk_core::hlist;
93 ///
94 /// let h = hlist![1, "hi"];
95 /// assert_eq!(h.len(), 2);
96 /// # }
97 /// ```
98 #[inline]
99 fn len(&self) -> usize {
100 Self::LEN
101 }
102
103 /// Returns whether a given HList is empty
104 ///
105 /// # Examples
106 ///
107 /// ```
108 /// # fn main() {
109 /// use frunk_core::hlist;
110 ///
111 /// let h = hlist![];
112 /// assert!(h.is_empty());
113 /// # }
114 /// ```
115 #[inline]
116 fn is_empty(&self) -> bool {
117 Self::LEN == 0
118 }
119
120 /// Returns the length of a given HList type without making use of any references, or
121 /// in fact, any values at all.
122 ///
123 /// # Examples
124 /// ```
125 /// # fn main() {
126 /// use frunk::prelude::*;
127 /// use frunk_core::HList;
128 ///
129 /// assert_eq!(<HList![i32, bool, f32]>::static_len(), 3);
130 /// # }
131 /// ```
132 #[deprecated(since = "0.1.31", note = "Please use LEN instead")]
133 fn static_len() -> usize;
134
135 /// Prepends an item to the current HList
136 ///
137 /// # Examples
138 ///
139 /// ```
140 /// # fn main() {
141 /// use frunk_core::hlist;
142 ///
143 /// let h1 = hlist![1, "hi"];
144 /// let h2 = h1.prepend(true);
145 /// let (a, (b, c)) = h2.into_tuple2();
146 /// assert_eq!(a, true);
147 /// assert_eq!(b, 1);
148 /// assert_eq!(c, "hi");
149 /// # }
150 fn prepend<H>(self, h: H) -> HCons<H, Self> {
151 HCons {
152 head: h,
153 tail: self,
154 }
155 }
156}
157
158/// Represents the right-most end of a heterogeneous list
159///
160/// # Examples
161///
162/// ```
163/// # use frunk_core::hlist::{h_cons, HNil};
164/// let h = h_cons(1, HNil);
165/// let h = h.head;
166/// assert_eq!(h, 1);
167/// ```
168#[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
170pub struct HNil;
171
172impl HList for HNil {
173 const LEN: usize = 0;
174 fn static_len() -> usize {
175 Self::LEN
176 }
177}
178
179/// Represents the most basic non-empty HList. Its value is held in `head`
180/// while its tail is another HList.
181#[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
182#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
183pub struct HCons<H, T> {
184 pub head: H,
185 pub tail: T,
186}
187
188impl<H, T: HList> HList for HCons<H, T> {
189 const LEN: usize = 1 + <T as HList>::LEN;
190 fn static_len() -> usize {
191 Self::LEN
192 }
193}
194
195impl<H, T> HCons<H, T> {
196 /// Returns the head of the list and the tail of the list as a tuple2.
197 /// The original list is consumed
198 ///
199 /// # Examples
200 ///
201 /// ```
202 /// # fn main() {
203 /// use frunk_core::hlist;
204 ///
205 /// let h = hlist!("hi");
206 /// let (h, tail) = h.pop();
207 /// assert_eq!(h, "hi");
208 /// assert_eq!(tail, hlist![]);
209 /// # }
210 /// ```
211 pub fn pop(self) -> (H, T) {
212 (self.head, self.tail)
213 }
214}
215
216/// Takes an element and an Hlist and returns another one with
217/// the element prepended to the original list. The original list
218/// is consumed
219///
220/// # Examples
221///
222/// ```
223/// # extern crate frunk; fn main() {
224/// use frunk::hlist::{HNil, h_cons};
225///
226/// let h_list = h_cons("what", h_cons(1.23f32, HNil));
227/// let (h1, h2) = h_list.into_tuple2();
228/// assert_eq!(h1, "what");
229/// assert_eq!(h2, 1.23f32);
230/// # }
231/// ```
232pub fn h_cons<H, T: HList>(h: H, tail: T) -> HCons<H, T> {
233 HCons { head: h, tail }
234}
235
236// Inherent methods shared by HNil and HCons.
237macro_rules! gen_inherent_methods {
238 (impl<$($TyPar:ident),*> $Struct:ty { ... })
239 => {
240 impl<$($TyPar),*> $Struct {
241 /// Returns the length of a given HList
242 ///
243 /// # Examples
244 ///
245 /// ```
246 /// # fn main() {
247 /// use frunk_core::hlist;
248 ///
249 /// let h = hlist![1, "hi"];
250 /// assert_eq!(h.len(), 2);
251 /// # }
252 /// ```
253 #[inline(always)]
254 pub fn len(&self) -> usize
255 where Self: HList,
256 {
257 HList::len(self)
258 }
259
260 /// Returns whether a given HList is empty
261 ///
262 /// # Examples
263 ///
264 /// ```
265 /// # fn main() {
266 /// use frunk_core::hlist;
267 ///
268 /// let h = hlist![];
269 /// assert!(h.is_empty());
270 /// # }
271 /// ```
272 #[inline(always)]
273 pub fn is_empty(&self) -> bool
274 where Self: HList,
275 {
276 HList::is_empty(self)
277 }
278
279 /// Prepend an item to the current HList
280 ///
281 /// # Examples
282 ///
283 /// ```
284 /// # fn main() {
285 /// use frunk_core::hlist;
286 ///
287 /// let h1 = hlist![1, "hi"];
288 /// let h2 = h1.prepend(true);
289 /// let (a, (b, c)) = h2.into_tuple2();
290 /// assert_eq!(a, true);
291 /// assert_eq!(b, 1);
292 /// assert_eq!(c, "hi");
293 /// # }
294 #[inline(always)]
295 pub fn prepend<H>(self, h: H) -> HCons<H, Self>
296 where Self: HList,
297 {
298 HList::prepend(self, h)
299 }
300
301 /// Consume the current HList and return an HList with the requested shape.
302 ///
303 /// `sculpt` allows us to extract/reshape/sculpt the current HList into another shape,
304 /// provided that the requested shape's types are are contained within the current HList.
305 ///
306 /// The `Indices` type parameter allows the compiler to figure out that `Ts`
307 /// and `Self` can be morphed into each other.
308 ///
309 /// # Examples
310 ///
311 /// ```
312 /// # fn main() {
313 /// use frunk_core::{hlist, HList};
314 ///
315 /// let h = hlist![9000, "joe", 41f32, true];
316 /// let (reshaped, remainder): (HList![f32, i32, &str], _) = h.sculpt();
317 /// assert_eq!(reshaped, hlist![41f32, 9000, "joe"]);
318 /// assert_eq!(remainder, hlist![true]);
319 /// # }
320 /// ```
321 #[inline(always)]
322 pub fn sculpt<Ts, Indices>(self) -> (Ts, <Self as Sculptor<Ts, Indices>>::Remainder)
323 where Self: Sculptor<Ts, Indices>,
324 {
325 Sculptor::sculpt(self)
326 }
327
328 /// Reverse the HList.
329 ///
330 /// # Examples
331 ///
332 /// ```
333 /// # fn main() {
334 /// use frunk_core::hlist;
335 ///
336 /// assert_eq!(hlist![].into_reverse(), hlist![]);
337 ///
338 /// assert_eq!(
339 /// hlist![1, "hello", true, 42f32].into_reverse(),
340 /// hlist![42f32, true, "hello", 1],
341 /// )
342 /// # }
343 /// ```
344 #[inline(always)]
345 pub fn into_reverse(self) -> <Self as IntoReverse>::Output
346 where Self: IntoReverse,
347 {
348 IntoReverse::into_reverse(self)
349 }
350
351 /// Return an HList where the contents are references to
352 /// the original HList on which this method was called.
353 ///
354 /// # Examples
355 ///
356 /// ```
357 /// # fn main() {
358 /// use frunk_core::hlist;
359 ///
360 /// assert_eq!(hlist![].to_ref(), hlist![]);
361 ///
362 /// assert_eq!(hlist![1, true].to_ref(), hlist![&1, &true]);
363 /// # }
364 /// ```
365 #[inline(always)]
366 #[allow(clippy::wrong_self_convention)]
367 pub fn to_ref<'a>(&'a self) -> <Self as ToRef<'a>>::Output
368 where Self: ToRef<'a>,
369 {
370 ToRef::to_ref(self)
371 }
372
373 /// Return an `HList` where the contents are mutable references
374 /// to the original `HList` on which this method was called.
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// # fn main() {
380 /// use frunk_core::hlist;
381 ///
382 /// assert_eq!(hlist![].to_mut(), hlist![]);
383 ///
384 /// assert_eq!(hlist![1, true].to_mut(), hlist![&mut 1, &mut true]);
385 /// # }
386 /// ```
387 #[inline(always)]
388 pub fn to_mut<'a>(&'a mut self) -> <Self as ToMut<'a>>::Output
389 where
390 Self: ToMut<'a>,
391 {
392 ToMut::to_mut(self)
393 }
394
395 /// Apply a function to each element of an HList.
396 ///
397 /// This transforms some `HList![A, B, C, ..., E]` into some
398 /// `HList![T, U, V, ..., Z]`. A variety of types are supported
399 /// for the folder argument:
400 ///
401 /// * An `hlist![]` of closures (one for each element).
402 /// * A single closure (for mapping an HList that is homogenous).
403 /// * A single [`Poly`].
404 ///
405 /// [`Poly`]: ../traits/struct.Poly.html
406 ///
407 /// # Examples
408 ///
409 /// ```
410 /// # fn main() {
411 /// use frunk::HNil;
412 /// use frunk_core::hlist;
413 ///
414 /// assert_eq!(HNil.map(HNil), HNil);
415 ///
416 /// let h = hlist![1, false, 42f32];
417 ///
418 /// // Sadly we need to help the compiler understand the bool type in our mapper
419 ///
420 /// let mapped = h.to_ref().map(hlist![
421 /// |&n| n + 1,
422 /// |b: &bool| !b,
423 /// |&f| f + 1f32]);
424 /// assert_eq!(mapped, hlist![2, true, 43f32]);
425 ///
426 /// // There is also a value-consuming version that passes values to your functions
427 /// // instead of just references:
428 ///
429 /// let mapped2 = h.map(hlist![
430 /// |n| n + 3,
431 /// |b: bool| !b,
432 /// |f| f + 8959f32]);
433 /// assert_eq!(mapped2, hlist![4, true, 9001f32]);
434 /// # }
435 /// ```
436 #[inline(always)]
437 pub fn map<F>(self, mapper: F) -> <Self as HMappable<F>>::Output
438 where Self: HMappable<F>,
439 {
440 HMappable::map(self, mapper)
441 }
442
443 /// Zip two HLists together.
444 ///
445 /// This zips a `HList![A1, B1, ..., C1]` with a `HList![A2, B2, ..., C2]`
446 /// to make a `HList![(A1, A2), (B1, B2), ..., (C1, C2)]`
447 ///
448 /// # Example
449 ///
450 /// ```
451 /// # fn main() {
452 /// use frunk::HNil;
453 /// use frunk_core::hlist;
454 ///
455 /// assert_eq!(HNil.zip(HNil), HNil);
456 ///
457 /// let h1 = hlist![1, false, 42f32];
458 /// let h2 = hlist![true, "foo", 2];
459 ///
460 /// let zipped = h1.zip(h2);
461 /// assert_eq!(zipped, hlist![
462 /// (1, true),
463 /// (false, "foo"),
464 /// (42f32, 2),
465 /// ]);
466 /// # }
467 /// ```
468 #[inline(always)]
469 pub fn zip<Other>(self, other: Other) -> <Self as HZippable<Other>>::Zipped
470 where Self: HZippable<Other>,
471 {
472 HZippable::zip(self, other)
473 }
474
475 /// Perform a left fold over an HList.
476 ///
477 /// This transforms some `HList![A, B, C, ..., E]` into a single
478 /// value by visiting all of the elements in left-to-right order.
479 /// A variety of types are supported for the mapper argument:
480 ///
481 /// * An `hlist![]` of closures (one for each element).
482 /// * A single closure (for folding an HList that is homogenous).
483 /// * A single [`Poly`].
484 ///
485 /// The accumulator can freely change type over the course of the call.
486 /// When called with a list of `N` functions, an expanded form of the
487 /// implementation with type annotations might look something like this:
488 ///
489 /// ```ignore
490 /// let acc: Acc0 = init_value;
491 /// let acc: Acc1 = f1(acc, x1);
492 /// let acc: Acc2 = f2(acc, x2);
493 /// let acc: Acc3 = f3(acc, x3);
494 /// ...
495 /// let acc: AccN = fN(acc, xN);
496 /// acc
497 /// ```
498 ///
499 /// [`Poly`]: ../traits/struct.Poly.html
500 ///
501 /// # Examples
502 ///
503 /// ```
504 /// # fn main() {
505 /// use frunk_core::hlist;
506 ///
507 /// let nil = hlist![];
508 ///
509 /// assert_eq!(nil.foldl(hlist![], 0), 0);
510 ///
511 /// let h = hlist![1, false, 42f32];
512 ///
513 /// let folded = h.to_ref().foldl(
514 /// hlist![
515 /// |acc, &i| i + acc,
516 /// |acc, b: &bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
517 /// |acc, &f| f + acc
518 /// ],
519 /// 1
520 /// );
521 ///
522 /// assert_eq!(42f32, folded);
523 ///
524 /// // There is also a value-consuming version that passes values to your folding
525 /// // functions instead of just references:
526 ///
527 /// let folded2 = h.foldl(
528 /// hlist![
529 /// |acc, i| i + acc,
530 /// |acc, b: bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
531 /// |acc, f| f + acc
532 /// ],
533 /// 8918
534 /// );
535 ///
536 /// assert_eq!(9042f32, folded2)
537 /// # }
538 /// ```
539 #[inline(always)]
540 pub fn foldl<Folder, Acc>(
541 self,
542 folder: Folder,
543 acc: Acc,
544 ) -> <Self as HFoldLeftable<Folder, Acc>>::Output
545 where Self: HFoldLeftable<Folder, Acc>,
546 {
547 HFoldLeftable::foldl(self, folder, acc)
548 }
549
550 /// Perform a right fold over an HList.
551 ///
552 /// This transforms some `HList![A, B, C, ..., E]` into a single
553 /// value by visiting all of the elements in reverse order.
554 /// A variety of types are supported for the mapper argument:
555 ///
556 /// * An `hlist![]` of closures (one for each element).
557 /// * A single closure (for folding an HList that is homogenous),
558 /// taken by reference.
559 /// * A single [`Poly`].
560 ///
561 /// The accumulator can freely change type over the course of the call.
562 ///
563 /// [`Poly`]: ../traits/struct.Poly.html
564 ///
565 /// # Comparison to `foldl`
566 ///
567 /// While the order of element traversal in `foldl` may seem more natural,
568 /// `foldr` does have its use cases, in particular when it is used to build
569 /// something that reflects the structure of the original HList (such as
570 /// folding an HList of `Option`s into an `Option` of an HList).
571 /// An implementation of such a function using `foldl` will tend to
572 /// reverse the list, while `foldr` will tend to preserve its order.
573 ///
574 /// The reason for this is because `foldr` performs what is known as
575 /// "structural induction;" it can be understood as follows:
576 ///
577 /// * Write out the HList in terms of [`h_cons`] and [`HNil`].
578 /// * Substitute each [`h_cons`] with a function,
579 /// and substitute [`HNil`] with `init`
580 ///
581 /// ```text
582 /// the list:
583 /// h_cons(x1, h_cons(x2, h_cons(x3, ...h_cons(xN, HNil)...)))
584 ///
585 /// becomes:
586 /// f1( x1, f2( x2, f3( x3, ... fN( xN, init)...)))
587 /// ```
588 ///
589 /// [`HNil`]: struct.HNil.html
590 /// [`h_cons`]: fn.h_cons.html
591 ///
592 /// # Examples
593 ///
594 /// ```
595 /// # fn main() {
596 /// use frunk_core::hlist;
597 ///
598 /// let nil = hlist![];
599 ///
600 /// assert_eq!(nil.foldr(hlist![], 0), 0);
601 ///
602 /// let h = hlist![1, false, 42f32];
603 ///
604 /// let folded = h.foldr(
605 /// hlist![
606 /// |acc, i| i + acc,
607 /// |acc, b: bool| if !b && acc > 42f32 { 9000 } else { 0 },
608 /// |acc, f| f + acc
609 /// ],
610 /// 1f32
611 /// );
612 ///
613 /// assert_eq!(9001, folded)
614 /// # }
615 /// ```
616 #[inline(always)]
617 pub fn foldr<Folder, Init>(
618 self,
619 folder: Folder,
620 init: Init,
621 ) -> <Self as HFoldRightable<Folder, Init>>::Output
622 where Self: HFoldRightable<Folder, Init>,
623 {
624 HFoldRightable::foldr(self, folder, init)
625 }
626
627 /// Extend the contents of this HList with another HList
628 ///
629 /// This exactly the same as the [`Add`][Add] impl.
630 ///
631 /// [Add]: struct.HCons.html#impl-Add%3CRHS%3E-for-HCons%3CH,+T%3E
632 ///
633 /// # Examples
634 ///
635 /// ```
636 /// use frunk_core::hlist;
637 ///
638 /// let first = hlist![0u8, 1u16];
639 /// let second = hlist![2u32, 3u64];
640 ///
641 /// assert_eq!(first.extend(second), hlist![0u8, 1u16, 2u32, 3u64]);
642 /// ```
643 pub fn extend<Other>(
644 self,
645 other: Other
646 ) -> <Self as Add<Other>>::Output
647 where
648 Self: Add<Other>,
649 Other: HList,
650 {
651 self + other
652 }
653 }
654 };
655}
656
657gen_inherent_methods! {
658 impl<> HNil { ... }
659}
660gen_inherent_methods! {
661 impl<Head, Tail> HCons<Head, Tail> { ... }
662}
663
664// HCons-only inherent methods.
665impl<Head, Tail> HCons<Head, Tail> {
666 /// Borrow an element by type from an HList.
667 ///
668 /// # Examples
669 ///
670 /// ```
671 /// # fn main() {
672 /// use frunk_core::hlist;
673 ///
674 /// let h = hlist![1i32, 2u32, "hello", true, 42f32];
675 ///
676 /// // Often, type inference can figure out the type you want.
677 /// // You can help guide type inference when necessary by
678 /// // using type annotations.
679 /// let b: &bool = h.get();
680 /// if !b { panic!("no way!") };
681 ///
682 /// // If space is tight, you can also use turbofish syntax.
683 /// // The Index is still left to type inference by using `_`.
684 /// match *h.get::<u32, _>() {
685 /// 2 => { }
686 /// _ => panic!("it can't be!!"),
687 /// }
688 /// # }
689 /// ```
690 #[inline(always)]
691 pub fn get<T, Index>(&self) -> &T
692 where
693 Self: Selector<T, Index>,
694 {
695 Selector::get(self)
696 }
697
698 /// Mutably borrow an element by type from an HList.
699 ///
700 /// # Examples
701 ///
702 /// ```
703 /// # fn main() {
704 /// use frunk_core::hlist;
705 ///
706 /// let mut h = hlist![1i32, true];
707 ///
708 /// // Type inference ensures we fetch the correct type.
709 /// *h.get_mut() = false;
710 /// *h.get_mut() = 2;
711 /// // *h.get_mut() = "neigh"; // Won't compile.
712 ///
713 /// assert_eq!(h, hlist![2i32, false]);
714 /// # }
715 /// ```
716 #[inline(always)]
717 pub fn get_mut<T, Index>(&mut self) -> &mut T
718 where
719 Self: Selector<T, Index>,
720 {
721 Selector::get_mut(self)
722 }
723
724 /// Remove an element by type from an HList.
725 ///
726 /// The remaining elements are returned along with it.
727 ///
728 /// # Examples
729 ///
730 /// ```
731 /// # fn main() {
732 /// use frunk_core::hlist;
733 ///
734 /// let list = hlist![1, "hello", true, 42f32];
735 ///
736 /// // Often, type inference can figure out the target type.
737 /// let (b, list): (bool, _) = list.pluck();
738 /// assert!(b);
739 ///
740 /// // When type inference will not suffice, you can use a turbofish.
741 /// // The Index is still left to type inference by using `_`.
742 /// let (s, list) = list.pluck::<i32, _>();
743 ///
744 /// // Each time we plucked, we got back a remainder.
745 /// // Let's check what's left:
746 /// assert_eq!(list, hlist!["hello", 42.0])
747 /// # }
748 /// ```
749 #[inline(always)]
750 pub fn pluck<T, Index>(self) -> (T, <Self as Plucker<T, Index>>::Remainder)
751 where
752 Self: Plucker<T, Index>,
753 {
754 Plucker::pluck(self)
755 }
756
757 /// Turns an HList into nested Tuple2s, which are less troublesome to pattern match
758 /// and have a nicer type signature.
759 ///
760 /// # Examples
761 ///
762 /// ```
763 /// # fn main() {
764 /// use frunk_core::hlist;
765 ///
766 /// let h = hlist![1, "hello", true, 42f32];
767 ///
768 /// // We now have a much nicer pattern matching experience
769 /// let (first,(second,(third, fourth))) = h.into_tuple2();
770 ///
771 /// assert_eq!(first , 1);
772 /// assert_eq!(second, "hello");
773 /// assert_eq!(third , true);
774 /// assert_eq!(fourth, 42f32);
775 /// # }
776 /// ```
777 #[inline(always)]
778 pub fn into_tuple2(
779 self,
780 ) -> (
781 <Self as IntoTuple2>::HeadType,
782 <Self as IntoTuple2>::TailOutput,
783 )
784 where
785 Self: IntoTuple2,
786 {
787 IntoTuple2::into_tuple2(self)
788 }
789}
790
791impl<RHS> Add<RHS> for HNil
792where
793 RHS: HList,
794{
795 type Output = RHS;
796
797 fn add(self, rhs: RHS) -> RHS {
798 rhs
799 }
800}
801
802impl<H, T, RHS> Add<RHS> for HCons<H, T>
803where
804 T: Add<RHS>,
805 RHS: HList,
806{
807 type Output = HCons<H, <T as Add<RHS>>::Output>;
808
809 fn add(self, rhs: RHS) -> Self::Output {
810 HCons {
811 head: self.head,
812 tail: self.tail + rhs,
813 }
814 }
815}
816
817/// Trait for borrowing an HList element by type
818///
819/// This trait is part of the implementation of the inherent method
820/// [`HCons::get`]. Please see that method for more information.
821///
822/// You only need to import this trait when working with generic
823/// HLists of unknown type. If you have an HList of known type,
824/// then `list.get()` should "just work" even without the trait.
825///
826/// [`HCons::get`]: struct.HCons.html#method.get
827pub trait Selector<S, I> {
828 /// Borrow an element by type from an HList.
829 ///
830 /// Please see the [inherent method] for more information.
831 ///
832 /// The only difference between that inherent method and this
833 /// trait method is the location of the type parameters
834 /// (here, they are on the trait rather than the method).
835 ///
836 /// [inherent method]: struct.HCons.html#method.get
837 fn get(&self) -> &S;
838
839 /// Mutably borrow an element by type from an HList.
840 ///
841 /// Please see the [inherent method] for more information.
842 ///
843 /// The only difference between that inherent method and this
844 /// trait method is the location of the type parameters
845 /// (here, they are on the trait rather than the method).
846 ///
847 /// [inherent method]: struct.HCons.html#method.get_mut
848 fn get_mut(&mut self) -> &mut S;
849}
850
851impl<T, Tail> Selector<T, Here> for HCons<T, Tail> {
852 fn get(&self) -> &T {
853 &self.head
854 }
855
856 fn get_mut(&mut self) -> &mut T {
857 &mut self.head
858 }
859}
860
861impl<Head, Tail, FromTail, TailIndex> Selector<FromTail, There<TailIndex>> for HCons<Head, Tail>
862where
863 Tail: Selector<FromTail, TailIndex>,
864{
865 fn get(&self) -> &FromTail {
866 self.tail.get()
867 }
868
869 fn get_mut(&mut self) -> &mut FromTail {
870 self.tail.get_mut()
871 }
872}
873
874/// Trait defining extraction from a given HList
875///
876/// This trait is part of the implementation of the inherent method
877/// [`HCons::pluck`]. Please see that method for more information.
878///
879/// You only need to import this trait when working with generic
880/// HLists of unknown type. If you have an HList of known type,
881/// then `list.pluck()` should "just work" even without the trait.
882///
883/// [`HCons::pluck`]: struct.HCons.html#method.pluck
884pub trait Plucker<Target, Index> {
885 /// What is left after you pluck the target from the Self
886 type Remainder;
887
888 /// Remove an element by type from an HList.
889 ///
890 /// Please see the [inherent method] for more information.
891 ///
892 /// The only difference between that inherent method and this
893 /// trait method is the location of the type parameters.
894 /// (here, they are on the trait rather than the method)
895 ///
896 /// [inherent method]: struct.HCons.html#method.pluck
897 fn pluck(self) -> (Target, Self::Remainder);
898}
899
900/// Implementation when the pluck target is in head
901impl<T, Tail> Plucker<T, Here> for HCons<T, Tail> {
902 type Remainder = Tail;
903
904 fn pluck(self) -> (T, Self::Remainder) {
905 (self.head, self.tail)
906 }
907}
908
909/// Implementation when the pluck target is in the tail
910impl<Head, Tail, FromTail, TailIndex> Plucker<FromTail, There<TailIndex>> for HCons<Head, Tail>
911where
912 Tail: Plucker<FromTail, TailIndex>,
913{
914 type Remainder = HCons<Head, <Tail as Plucker<FromTail, TailIndex>>::Remainder>;
915
916 fn pluck(self) -> (FromTail, Self::Remainder) {
917 let (target, tail_remainder): (
918 FromTail,
919 <Tail as Plucker<FromTail, TailIndex>>::Remainder,
920 ) = <Tail as Plucker<FromTail, TailIndex>>::pluck(self.tail);
921 (
922 target,
923 HCons {
924 head: self.head,
925 tail: tail_remainder,
926 },
927 )
928 }
929}
930
931/// Implementation when target is reference and the pluck target is in head
932impl<'a, T, Tail: ToRef<'a>> Plucker<&'a T, Here> for &'a HCons<T, Tail> {
933 type Remainder = <Tail as ToRef<'a>>::Output;
934
935 fn pluck(self) -> (&'a T, Self::Remainder) {
936 (&self.head, self.tail.to_ref())
937 }
938}
939
940/// Implementation when target is reference the pluck target is in the tail
941impl<'a, Head, Tail, FromTail, TailIndex> Plucker<&'a FromTail, There<TailIndex>>
942 for &'a HCons<Head, Tail>
943where
944 &'a Tail: Plucker<&'a FromTail, TailIndex>,
945{
946 type Remainder = HCons<&'a Head, <&'a Tail as Plucker<&'a FromTail, TailIndex>>::Remainder>;
947
948 fn pluck(self) -> (&'a FromTail, Self::Remainder) {
949 let (target, tail_remainder): (
950 &'a FromTail,
951 <&'a Tail as Plucker<&'a FromTail, TailIndex>>::Remainder,
952 ) = <&'a Tail as Plucker<&'a FromTail, TailIndex>>::pluck(&self.tail);
953 (
954 target,
955 HCons {
956 head: &self.head,
957 tail: tail_remainder,
958 },
959 )
960 }
961}
962
963/// Trait for pulling out some subset of an HList, using type inference.
964///
965/// This trait is part of the implementation of the inherent method
966/// [`HCons::sculpt`]. Please see that method for more information.
967///
968/// You only need to import this trait when working with generic
969/// HLists of unknown type. If you have an HList of known type,
970/// then `list.sculpt()` should "just work" even without the trait.
971///
972/// [`HCons::sculpt`]: struct.HCons.html#method.sculpt
973pub trait Sculptor<Target, Indices> {
974 type Remainder;
975
976 /// Consumes the current HList and returns an HList with the requested shape.
977 ///
978 /// Please see the [inherent method] for more information.
979 ///
980 /// The only difference between that inherent method and this
981 /// trait method is the location of the type parameters.
982 /// (here, they are on the trait rather than the method)
983 ///
984 /// [inherent method]: struct.HCons.html#method.sculpt
985 fn sculpt(self) -> (Target, Self::Remainder);
986}
987
988/// Implementation for when the target is an empty HList (HNil)
989///
990/// Index type is HNil because we don't need an index for finding HNil
991impl<Source> Sculptor<HNil, HNil> for Source {
992 type Remainder = Source;
993
994 #[inline(always)]
995 fn sculpt(self) -> (HNil, Self::Remainder) {
996 (HNil, self)
997 }
998}
999
1000/// Implementation for when we have a non-empty HCons target
1001///
1002/// Indices is HCons<IndexHead, IndexTail> here because the compiler is being asked to figure out the
1003/// Index for Plucking the first item of type THead out of Self and the rest (IndexTail) is for the
1004/// Plucker's remainder induce.
1005impl<THead, TTail, SHead, STail, IndexHead, IndexTail>
1006 Sculptor<HCons<THead, TTail>, HCons<IndexHead, IndexTail>> for HCons<SHead, STail>
1007where
1008 HCons<SHead, STail>: Plucker<THead, IndexHead>,
1009 <HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder: Sculptor<TTail, IndexTail>,
1010{
1011 type Remainder = <<HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder as Sculptor<
1012 TTail,
1013 IndexTail,
1014 >>::Remainder;
1015
1016 #[inline(always)]
1017 fn sculpt(self) -> (HCons<THead, TTail>, Self::Remainder) {
1018 let (p, r): (
1019 THead,
1020 <HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder,
1021 ) = self.pluck();
1022 let (tail, tail_remainder): (TTail, Self::Remainder) = r.sculpt();
1023 (HCons { head: p, tail }, tail_remainder)
1024 }
1025}
1026
1027impl IntoReverse for HNil {
1028 type Output = HNil;
1029 fn into_reverse(self) -> Self::Output {
1030 self
1031 }
1032}
1033
1034impl<H, Tail> IntoReverse for HCons<H, Tail>
1035where
1036 Tail: IntoReverse,
1037 <Tail as IntoReverse>::Output: Add<HCons<H, HNil>>,
1038{
1039 type Output = <<Tail as IntoReverse>::Output as Add<HCons<H, HNil>>>::Output;
1040
1041 fn into_reverse(self) -> Self::Output {
1042 self.tail.into_reverse()
1043 + HCons {
1044 head: self.head,
1045 tail: HNil,
1046 }
1047 }
1048}
1049
1050impl<P, H, Tail> HMappable<Poly<P>> for HCons<H, Tail>
1051where
1052 P: Func<H>,
1053 Tail: HMappable<Poly<P>>,
1054{
1055 type Output = HCons<<P as Func<H>>::Output, <Tail as HMappable<Poly<P>>>::Output>;
1056 fn map(self, poly: Poly<P>) -> Self::Output {
1057 HCons {
1058 head: P::call(self.head),
1059 tail: self.tail.map(poly),
1060 }
1061 }
1062}
1063
1064/// Trait for mapping over an HList
1065///
1066/// This trait is part of the implementation of the inherent method
1067/// [`HCons::map`]. Please see that method for more information.
1068///
1069/// You only need to import this trait when working with generic
1070/// HLists or Mappers of unknown type. If the type of everything is known,
1071/// then `list.map(f)` should "just work" even without the trait.
1072///
1073/// [`HCons::map`]: struct.HCons.html#method.map
1074pub trait HMappable<Mapper> {
1075 type Output;
1076
1077 /// Apply a function to each element of an HList.
1078 ///
1079 /// Please see the [inherent method] for more information.
1080 ///
1081 /// The only difference between that inherent method and this
1082 /// trait method is the location of the type parameters.
1083 /// (here, they are on the trait rather than the method)
1084 ///
1085 /// [inherent method]: struct.HCons.html#method.map
1086 fn map(self, mapper: Mapper) -> Self::Output;
1087}
1088
1089impl<F> HMappable<F> for HNil {
1090 type Output = HNil;
1091
1092 fn map(self, _: F) -> Self::Output {
1093 HNil
1094 }
1095}
1096
1097impl<F, R, H, Tail> HMappable<F> for HCons<H, Tail>
1098where
1099 F: Fn(H) -> R,
1100 Tail: HMappable<F>,
1101{
1102 type Output = HCons<R, <Tail as HMappable<F>>::Output>;
1103
1104 fn map(self, f: F) -> Self::Output {
1105 let HCons { head, tail } = self;
1106 HCons {
1107 head: f(head),
1108 tail: tail.map(f),
1109 }
1110 }
1111}
1112
1113impl<F, R, MapperTail, H, Tail> HMappable<HCons<F, MapperTail>> for HCons<H, Tail>
1114where
1115 F: FnOnce(H) -> R,
1116 Tail: HMappable<MapperTail>,
1117{
1118 type Output = HCons<R, <Tail as HMappable<MapperTail>>::Output>;
1119
1120 fn map(self, mapper: HCons<F, MapperTail>) -> Self::Output {
1121 let HCons { head, tail } = self;
1122 HCons {
1123 head: (mapper.head)(head),
1124 tail: tail.map(mapper.tail),
1125 }
1126 }
1127}
1128
1129/// Trait for zipping HLists
1130///
1131/// This trait is part of the implementation of the inherent method
1132/// [`HCons::zip`]. Please see that method for more information.
1133///
1134/// You only need to import this trait when working with generic
1135/// HLists of unknown type. If the type of everything is known,
1136/// then `list.zip(list2)` should "just work" even without the trait.
1137///
1138/// [`HCons::zip`]: struct.HCons.html#method.zip
1139pub trait HZippable<Other> {
1140 type Zipped: HList;
1141
1142 /// Zip this HList with another one.
1143 ///
1144 /// Please see the [inherent method] for more information.
1145 ///
1146 /// [inherent method]: struct.HCons.html#method.zip
1147 fn zip(self, other: Other) -> Self::Zipped;
1148}
1149
1150impl HZippable<HNil> for HNil {
1151 type Zipped = HNil;
1152 fn zip(self, _other: HNil) -> Self::Zipped {
1153 HNil
1154 }
1155}
1156
1157impl<H1, T1, H2, T2> HZippable<HCons<H2, T2>> for HCons<H1, T1>
1158where
1159 T1: HZippable<T2>,
1160{
1161 type Zipped = HCons<(H1, H2), T1::Zipped>;
1162 fn zip(self, other: HCons<H2, T2>) -> Self::Zipped {
1163 HCons {
1164 head: (self.head, other.head),
1165 tail: self.tail.zip(other.tail),
1166 }
1167 }
1168}
1169
1170/// Trait for performing a right fold over an HList
1171///
1172/// This trait is part of the implementation of the inherent method
1173/// [`HCons::foldr`]. Please see that method for more information.
1174///
1175/// You only need to import this trait when working with generic
1176/// HLists or Folders of unknown type. If the type of everything is known,
1177/// then `list.foldr(f, init)` should "just work" even without the trait.
1178///
1179/// [`HCons::foldr`]: struct.HCons.html#method.foldr
1180pub trait HFoldRightable<Folder, Init> {
1181 type Output;
1182
1183 /// Perform a right fold over an HList.
1184 ///
1185 /// Please see the [inherent method] for more information.
1186 ///
1187 /// The only difference between that inherent method and this
1188 /// trait method is the location of the type parameters.
1189 /// (here, they are on the trait rather than the method)
1190 ///
1191 /// [inherent method]: struct.HCons.html#method.foldr
1192 fn foldr(self, folder: Folder, i: Init) -> Self::Output;
1193}
1194
1195impl<F, Init> HFoldRightable<F, Init> for HNil {
1196 type Output = Init;
1197
1198 fn foldr(self, _: F, i: Init) -> Self::Output {
1199 i
1200 }
1201}
1202
1203impl<F, FolderHeadR, FolderTail, H, Tail, Init> HFoldRightable<HCons<F, FolderTail>, Init>
1204 for HCons<H, Tail>
1205where
1206 Tail: HFoldRightable<FolderTail, Init>,
1207 F: FnOnce(<Tail as HFoldRightable<FolderTail, Init>>::Output, H) -> FolderHeadR,
1208{
1209 type Output = FolderHeadR;
1210
1211 fn foldr(self, folder: HCons<F, FolderTail>, init: Init) -> Self::Output {
1212 let folded_tail = self.tail.foldr(folder.tail, init);
1213 (folder.head)(folded_tail, self.head)
1214 }
1215}
1216
1217impl<F, R, H, Tail, Init> HFoldRightable<F, Init> for HCons<H, Tail>
1218where
1219 Tail: foldr_owned::HFoldRightableOwned<F, Init>,
1220 F: Fn(<Tail as HFoldRightable<F, Init>>::Output, H) -> R,
1221{
1222 type Output = R;
1223
1224 fn foldr(self, folder: F, init: Init) -> Self::Output {
1225 foldr_owned::HFoldRightableOwned::real_foldr(self, folder, init).0
1226 }
1227}
1228
1229/// [`HFoldRightable`] inner mechanics for folding with a folder that needs to be owned.
1230pub mod foldr_owned {
1231 use super::{HCons, HFoldRightable, HNil};
1232
1233 /// A real `foldr` for the folder that must be owned to fold.
1234 ///
1235 /// Due to `HList` being a recursive struct and not linear array,
1236 /// the only way to fold it is recursive.
1237 ///
1238 /// However, there are differences in the `foldl` and `foldr` traversing
1239 /// the `HList`:
1240 ///
1241 /// 1. `foldl` calls `folder(head)` and then passes the ownership
1242 /// of the folder to the next recursive call.
1243 /// 2. `foldr` passes the ownership of the folder to the next recursive call,
1244 /// and then tries to call `folder(head)`; but the ownership is already gone!
1245 pub trait HFoldRightableOwned<Folder, Init>: HFoldRightable<Folder, Init> {
1246 fn real_foldr(self, folder: Folder, init: Init) -> (Self::Output, Folder);
1247 }
1248
1249 impl<F, Init> HFoldRightableOwned<F, Init> for HNil {
1250 fn real_foldr(self, f: F, i: Init) -> (Self::Output, F) {
1251 (i, f)
1252 }
1253 }
1254
1255 impl<F, H, Tail, Init> HFoldRightableOwned<F, Init> for HCons<H, Tail>
1256 where
1257 Self: HFoldRightable<F, Init>,
1258 Tail: HFoldRightableOwned<F, Init>,
1259 F: Fn(<Tail as HFoldRightable<F, Init>>::Output, H) -> Self::Output,
1260 {
1261 fn real_foldr(self, folder: F, init: Init) -> (Self::Output, F) {
1262 let (folded_tail, folder) = self.tail.real_foldr(folder, init);
1263 ((folder)(folded_tail, self.head), folder)
1264 }
1265 }
1266}
1267
1268impl<P, R, H, Tail, Init> HFoldRightable<Poly<P>, Init> for HCons<H, Tail>
1269where
1270 Tail: HFoldRightable<Poly<P>, Init>,
1271 P: Func<(<Tail as HFoldRightable<Poly<P>, Init>>::Output, H), Output = R>,
1272{
1273 type Output = R;
1274
1275 fn foldr(self, poly: Poly<P>, init: Init) -> Self::Output {
1276 let HCons { head, tail } = self;
1277 let folded_tail = tail.foldr(poly, init);
1278 P::call((folded_tail, head))
1279 }
1280}
1281
1282impl<'a> ToRef<'a> for HNil {
1283 type Output = HNil;
1284
1285 #[inline(always)]
1286 fn to_ref(&'a self) -> Self::Output {
1287 HNil
1288 }
1289}
1290
1291impl<'a, H, Tail> ToRef<'a> for HCons<H, Tail>
1292where
1293 H: 'a,
1294 Tail: ToRef<'a>,
1295{
1296 type Output = HCons<&'a H, <Tail as ToRef<'a>>::Output>;
1297
1298 #[inline(always)]
1299 fn to_ref(&'a self) -> Self::Output {
1300 HCons {
1301 head: &self.head,
1302 tail: self.tail.to_ref(),
1303 }
1304 }
1305}
1306
1307impl<'a> ToMut<'a> for HNil {
1308 type Output = HNil;
1309
1310 #[inline(always)]
1311 fn to_mut(&'a mut self) -> Self::Output {
1312 HNil
1313 }
1314}
1315
1316impl<'a, H, Tail> ToMut<'a> for HCons<H, Tail>
1317where
1318 H: 'a,
1319 Tail: ToMut<'a>,
1320{
1321 type Output = HCons<&'a mut H, <Tail as ToMut<'a>>::Output>;
1322
1323 #[inline(always)]
1324 fn to_mut(&'a mut self) -> Self::Output {
1325 HCons {
1326 head: &mut self.head,
1327 tail: self.tail.to_mut(),
1328 }
1329 }
1330}
1331
1332/// Trait for performing a left fold over an HList
1333///
1334/// This trait is part of the implementation of the inherent method
1335/// [`HCons::foldl`]. Please see that method for more information.
1336///
1337/// You only need to import this trait when working with generic
1338/// HLists or Mappers of unknown type. If the type of everything is known,
1339/// then `list.foldl(f, acc)` should "just work" even without the trait.
1340///
1341/// [`HCons::foldl`]: struct.HCons.html#method.foldl
1342pub trait HFoldLeftable<Folder, Acc> {
1343 type Output;
1344
1345 /// Perform a left fold over an HList.
1346 ///
1347 /// Please see the [inherent method] for more information.
1348 ///
1349 /// The only difference between that inherent method and this
1350 /// trait method is the location of the type parameters.
1351 /// (here, they are on the trait rather than the method)
1352 ///
1353 /// [inherent method]: struct.HCons.html#method.foldl
1354 fn foldl(self, folder: Folder, acc: Acc) -> Self::Output;
1355}
1356
1357impl<F, Acc> HFoldLeftable<F, Acc> for HNil {
1358 type Output = Acc;
1359
1360 fn foldl(self, _: F, acc: Acc) -> Self::Output {
1361 acc
1362 }
1363}
1364
1365impl<F, R, FTail, H, Tail, Acc> HFoldLeftable<HCons<F, FTail>, Acc> for HCons<H, Tail>
1366where
1367 Tail: HFoldLeftable<FTail, R>,
1368 F: FnOnce(Acc, H) -> R,
1369{
1370 type Output = <Tail as HFoldLeftable<FTail, R>>::Output;
1371
1372 fn foldl(self, folder: HCons<F, FTail>, acc: Acc) -> Self::Output {
1373 let HCons { head, tail } = self;
1374 tail.foldl(folder.tail, (folder.head)(acc, head))
1375 }
1376}
1377
1378impl<P, R, H, Tail, Acc> HFoldLeftable<Poly<P>, Acc> for HCons<H, Tail>
1379where
1380 Tail: HFoldLeftable<Poly<P>, R>,
1381 P: Func<(Acc, H), Output = R>,
1382{
1383 type Output = <Tail as HFoldLeftable<Poly<P>, R>>::Output;
1384
1385 fn foldl(self, poly: Poly<P>, acc: Acc) -> Self::Output {
1386 let HCons { head, tail } = self;
1387 let r = P::call((acc, head));
1388 tail.foldl(poly, r)
1389 }
1390}
1391
1392/// Implementation for folding over an HList using a single function that
1393/// can handle all cases
1394///
1395/// ```
1396/// # fn main() {
1397/// use frunk_core::hlist;
1398///
1399/// let h = hlist![1, 2, 3, 4, 5];
1400///
1401/// let r: isize = h.foldl(|acc, next| acc + next, 0);
1402/// assert_eq!(r, 15);
1403/// # }
1404/// ```
1405impl<F, H, Tail, Acc> HFoldLeftable<F, Acc> for HCons<H, Tail>
1406where
1407 Tail: HFoldLeftable<F, Acc>,
1408 F: Fn(Acc, H) -> Acc,
1409{
1410 type Output = <Tail as HFoldLeftable<F, Acc>>::Output;
1411
1412 fn foldl(self, f: F, acc: Acc) -> Self::Output {
1413 let HCons { head, tail } = self;
1414 let acc = f(acc, head);
1415 tail.foldl(f, acc)
1416 }
1417}
1418
1419/// Trait for transforming an HList into a nested tuple.
1420///
1421/// This trait is part of the implementation of the inherent method
1422/// [`HCons::into_tuple2`]. Please see that method for more information.
1423///
1424/// This operation is not useful in generic contexts, so it is unlikely
1425/// that you should ever need to import this trait. Do not worry;
1426/// if you have an HList of known type, then `list.into_tuple2()`
1427/// should "just work," even without the trait.
1428///
1429/// [`HCons::into_tuple2`]: struct.HCons.html#method.into_tuple2
1430pub trait IntoTuple2 {
1431 /// The 0 element in the output tuple
1432 type HeadType;
1433
1434 /// The 1 element in the output tuple
1435 type TailOutput;
1436
1437 /// Turns an HList into nested Tuple2s, which are less troublesome to pattern match
1438 /// and have a nicer type signature.
1439 ///
1440 /// Please see the [inherent method] for more information.
1441 ///
1442 /// [inherent method]: struct.HCons.html#method.into_tuple2
1443 fn into_tuple2(self) -> (Self::HeadType, Self::TailOutput);
1444}
1445
1446impl<T1, T2> IntoTuple2 for HCons<T1, HCons<T2, HNil>> {
1447 type HeadType = T1;
1448 type TailOutput = T2;
1449
1450 fn into_tuple2(self) -> (Self::HeadType, Self::TailOutput) {
1451 (self.head, self.tail.head)
1452 }
1453}
1454
1455impl<T, Tail> IntoTuple2 for HCons<T, Tail>
1456where
1457 Tail: IntoTuple2,
1458{
1459 type HeadType = T;
1460 type TailOutput = (
1461 <Tail as IntoTuple2>::HeadType,
1462 <Tail as IntoTuple2>::TailOutput,
1463 );
1464
1465 fn into_tuple2(self) -> (Self::HeadType, Self::TailOutput) {
1466 (self.head, self.tail.into_tuple2())
1467 }
1468}
1469
1470#[cfg(feature = "alloc")]
1471#[allow(clippy::from_over_into)]
1472impl<H, Tail> Into<Vec<H>> for HCons<H, Tail>
1473where
1474 Tail: Into<Vec<H>> + HList,
1475{
1476 fn into(self) -> Vec<H> {
1477 let h = self.head;
1478 let t = self.tail;
1479 let mut v = Vec::with_capacity(<Self as HList>::LEN);
1480 v.push(h);
1481 let mut t_vec: Vec<H> = t.into();
1482 v.append(&mut t_vec);
1483 v
1484 }
1485}
1486
1487#[cfg(feature = "alloc")]
1488#[allow(clippy::from_over_into)]
1489impl<T> Into<Vec<T>> for HNil {
1490 fn into(self) -> Vec<T> {
1491 Vec::with_capacity(0)
1492 }
1493}
1494
1495impl Default for HNil {
1496 fn default() -> Self {
1497 HNil
1498 }
1499}
1500
1501impl<T: Default, Tail: Default + HList> Default for HCons<T, Tail> {
1502 fn default() -> Self {
1503 h_cons(T::default(), Tail::default())
1504 }
1505}
1506
1507/// Indexed type conversions of `T -> Self` with index `I`.
1508/// This is a generalized version of `From` which for example allows the caller
1509/// to use default values for parts of `Self` and thus "fill in the blanks".
1510///
1511/// `LiftFrom` is the reciprocal of `LiftInto`.
1512///
1513/// ```
1514/// # fn main() {
1515/// use frunk::lift_from;
1516/// use frunk::prelude::*;
1517/// use frunk_core::{HList, hlist};
1518///
1519/// type H = HList![(), usize, f64, (), bool];
1520///
1521/// let x = H::lift_from(42.0);
1522/// assert_eq!(x, hlist![(), 0, 42.0, (), false]);
1523///
1524/// let x: H = lift_from(true);
1525/// assert_eq!(x, hlist![(), 0, 0.0, (), true]);
1526/// # }
1527/// ```
1528pub trait LiftFrom<T, I> {
1529 /// Performs the indexed conversion.
1530 fn lift_from(part: T) -> Self;
1531}
1532
1533/// Free function version of `LiftFrom::lift_from`.
1534pub fn lift_from<I, T, PF: LiftFrom<T, I>>(part: T) -> PF {
1535 PF::lift_from(part)
1536}
1537
1538/// An indexed conversion that consumes `self`, and produces a `T`. To produce
1539/// `T`, the index `I` may be used to for example "fill in the blanks".
1540/// `LiftInto` is the reciprocal of `LiftFrom`.
1541///
1542/// ```
1543/// # fn main() {
1544/// use frunk::prelude::*;
1545/// use frunk_core::{HList, hlist};
1546///
1547/// type H = HList![(), usize, f64, (), bool];
1548///
1549/// // Type inference works as expected:
1550/// let x: H = 1337.lift_into();
1551/// assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
1552///
1553/// // Sublists:
1554/// let x: H = hlist![(), true].lift_into();
1555/// assert_eq!(x, hlist![(), 0, 0.0, (), true]);
1556///
1557/// let x: H = hlist![3.0, ()].lift_into();
1558/// assert_eq!(x, hlist![(), 0, 3.0, (), false]);
1559///
1560/// let x: H = hlist![(), 1337].lift_into();
1561/// assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
1562///
1563/// let x: H = hlist![(), 1337, 42.0, (), true].lift_into();
1564/// assert_eq!(x, hlist![(), 1337, 42.0, (), true]);
1565/// # }
1566/// ```
1567pub trait LiftInto<T, I> {
1568 /// Performs the indexed conversion.
1569 fn lift_into(self) -> T;
1570}
1571
1572impl<T, U, I> LiftInto<U, I> for T
1573where
1574 U: LiftFrom<T, I>,
1575{
1576 fn lift_into(self) -> U {
1577 LiftFrom::lift_from(self)
1578 }
1579}
1580
1581impl<T, Tail> LiftFrom<T, Here> for HCons<T, Tail>
1582where
1583 Tail: Default + HList,
1584{
1585 fn lift_from(part: T) -> Self {
1586 h_cons(part, Tail::default())
1587 }
1588}
1589
1590impl<Head, Tail, ValAtIx, TailIx> LiftFrom<ValAtIx, There<TailIx>> for HCons<Head, Tail>
1591where
1592 Head: Default,
1593 Tail: HList + LiftFrom<ValAtIx, TailIx>,
1594{
1595 fn lift_from(part: ValAtIx) -> Self {
1596 h_cons(Head::default(), Tail::lift_from(part))
1597 }
1598}
1599
1600impl<Prefix, Suffix> LiftFrom<Prefix, Suffixed<Suffix>> for <Prefix as Add<Suffix>>::Output
1601where
1602 Prefix: HList + Add<Suffix>,
1603 Suffix: Default,
1604{
1605 fn lift_from(part: Prefix) -> Self {
1606 part + Suffix::default()
1607 }
1608}
1609
1610#[cfg(test)]
1611mod tests {
1612 use super::*;
1613
1614 use alloc::string::ToString;
1615 use alloc::vec;
1616
1617 #[test]
1618 fn test_hcons() {
1619 let hlist1 = h_cons(1, HNil);
1620 let (h, _) = hlist1.pop();
1621 assert_eq!(h, 1);
1622
1623 let hlist2 = h_cons("hello", h_cons(1, HNil));
1624 let (h2, tail2) = hlist2.pop();
1625 let (h1, _) = tail2.pop();
1626 assert_eq!(h2, "hello");
1627 assert_eq!(h1, 1);
1628 }
1629
1630 struct HasHList<T: HList>(T);
1631
1632 #[test]
1633 fn test_contained_list() {
1634 let c = HasHList(h_cons(1, HNil));
1635 let retrieved = c.0;
1636 assert_eq!(retrieved.len(), 1);
1637 let new_list = h_cons(2, retrieved);
1638 assert_eq!(new_list.len(), 2);
1639 }
1640
1641 #[test]
1642 fn test_pluck() {
1643 let h = hlist![1, "hello".to_string(), true, 42f32];
1644 let (t, r): (f32, _) = h.clone().pluck();
1645 assert_eq!(t, 42f32);
1646 assert_eq!(r, hlist![1, "hello".to_string(), true]);
1647 }
1648
1649 #[test]
1650 fn test_ref_pluck() {
1651 let h = &hlist![1, "hello".to_string(), true, 42f32];
1652 let (t, r): (&f32, _) = h.pluck();
1653 assert_eq!(t, &42f32);
1654 assert_eq!(r, hlist![&1, &"hello".to_string(), &true]);
1655 }
1656
1657 #[test]
1658 fn test_hlist_macro() {
1659 assert_eq!(hlist![], HNil);
1660 let h: HList!(i32, &str, i32) = hlist![1, "2", 3];
1661 let (h1, tail1) = h.pop();
1662 assert_eq!(h1, 1);
1663 assert_eq!(tail1, hlist!["2", 3]);
1664 let (h2, tail2) = tail1.pop();
1665 assert_eq!(h2, "2");
1666 assert_eq!(tail2, hlist![3]);
1667 let (h3, tail3) = tail2.pop();
1668 assert_eq!(h3, 3);
1669 assert_eq!(tail3, HNil);
1670 }
1671
1672 #[test]
1673 #[allow(non_snake_case)]
1674 fn test_Hlist_macro() {
1675 let h1: HList!(i32, &str, i32) = hlist![1, "2", 3];
1676 let h2: HList!(i32, &str, i32,) = hlist![1, "2", 3];
1677 let h3: HList!(i32) = hlist![1];
1678 let h4: HList!(i32,) = hlist![1,];
1679 assert_eq!(h1, h2);
1680 assert_eq!(h3, h4);
1681 }
1682
1683 #[test]
1684 fn test_pattern_matching() {
1685 let hlist_pat!(one1) = hlist!["one"];
1686 assert_eq!(one1, "one");
1687 let hlist_pat!(one2,) = hlist!["one"];
1688 assert_eq!(one2, "one");
1689
1690 let h = hlist![5, 3.2f32, true, "blue"];
1691 let hlist_pat!(five, float, right, s) = h;
1692 assert_eq!(five, 5);
1693 assert_eq!(float, 3.2f32);
1694 assert!(right);
1695 assert_eq!(s, "blue");
1696
1697 let h2 = hlist![13.5f32, "hello", Some(41)];
1698 let hlist_pat![a, b, c,] = h2;
1699 assert_eq!(a, 13.5f32);
1700 assert_eq!(b, "hello");
1701 assert_eq!(c, Some(41));
1702 }
1703
1704 #[test]
1705 fn test_add() {
1706 let h1 = hlist![true, "hi"];
1707 let h2 = hlist![1, 32f32];
1708 let combined = h1 + h2;
1709 assert_eq!(combined, hlist![true, "hi", 1, 32f32])
1710 }
1711
1712 #[test]
1713 fn test_into_reverse() {
1714 let h1 = hlist![true, "hi"];
1715 let h2 = hlist![1, 32f32];
1716 assert_eq!(h1.into_reverse(), hlist!["hi", true]);
1717 assert_eq!(h2.into_reverse(), hlist![32f32, 1]);
1718 }
1719
1720 #[test]
1721 fn test_foldr_consuming() {
1722 let h = hlist![1, false, 42f32];
1723 let folded = h.foldr(
1724 hlist![
1725 |acc, i| i + acc,
1726 |acc, _| if acc > 42f32 { 9000 } else { 0 },
1727 |acc, f| f + acc,
1728 ],
1729 1f32,
1730 );
1731 assert_eq!(folded, 9001)
1732 }
1733
1734 #[test]
1735 fn test_single_func_foldr_consuming() {
1736 let h = hlist![1, 2, 3];
1737 let folded = h.foldr(&|acc, i| i * acc, 1);
1738 assert_eq!(folded, 6)
1739 }
1740
1741 #[test]
1742 fn test_foldr_non_consuming() {
1743 let h = hlist![1, false, 42f32];
1744 let folder = hlist![
1745 |acc, &i| i + acc,
1746 |acc, &_| if acc > 42f32 { 9000 } else { 0 },
1747 |acc, &f| f + acc
1748 ];
1749 let folded = h.to_ref().foldr(folder, 1f32);
1750 assert_eq!(folded, 9001)
1751 }
1752
1753 #[test]
1754 fn test_poly_foldr_consuming() {
1755 trait Dummy {
1756 fn dummy(&self) -> i32 {
1757 1
1758 }
1759 }
1760 impl<T: ?Sized> Dummy for T {}
1761
1762 struct Dummynator;
1763 impl<T: Dummy, I: IntoIterator<Item = T>> Func<(i32, I)> for Dummynator {
1764 type Output = i32;
1765 fn call(args: (i32, I)) -> Self::Output {
1766 let (init, i) = args;
1767 i.into_iter().fold(init, |init, x| init + x.dummy())
1768 }
1769 }
1770
1771 let h = hlist![0..10, 0..=10, &[0, 1, 2], &['a', 'b', 'c']];
1772 assert_eq!(
1773 h.foldr(Poly(Dummynator), 0),
1774 (0..10)
1775 .map(|d| d.dummy())
1776 .chain((0..=10).map(|d| d.dummy()))
1777 .chain([0_i32, 1, 2].iter().map(|d| d.dummy()))
1778 .chain(['a', 'b', 'c'].iter().map(|d| d.dummy()))
1779 .sum()
1780 );
1781 }
1782
1783 #[test]
1784 fn test_foldl_consuming() {
1785 let h = hlist![1, false, 42f32];
1786 let folded = h.foldl(
1787 hlist![
1788 |acc, i| i + acc,
1789 |acc, b: bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
1790 |acc, f| f + acc,
1791 ],
1792 1,
1793 );
1794 assert_eq!(42f32, folded)
1795 }
1796
1797 #[test]
1798 fn test_foldl_non_consuming() {
1799 let h = hlist![1, false, 42f32];
1800 let folded = h.to_ref().foldl(
1801 hlist![
1802 |acc, &i| i + acc,
1803 |acc, b: &bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
1804 |acc, &f| f + acc,
1805 ],
1806 1,
1807 );
1808 assert_eq!(42f32, folded);
1809 assert_eq!((&h.head), &1);
1810 }
1811
1812 #[test]
1813 fn test_poly_foldl_consuming() {
1814 trait Dummy {
1815 fn dummy(&self) -> i32 {
1816 1
1817 }
1818 }
1819 impl<T: ?Sized> Dummy for T {}
1820
1821 struct Dummynator;
1822 impl<T: Dummy, I: IntoIterator<Item = T>> Func<(i32, I)> for Dummynator {
1823 type Output = i32;
1824 fn call(args: (i32, I)) -> Self::Output {
1825 let (acc, i) = args;
1826 i.into_iter().fold(acc, |acc, x| acc + x.dummy())
1827 }
1828 }
1829
1830 let h = hlist![0..10, 0..=10, &[0, 1, 2], &['a', 'b', 'c']];
1831 assert_eq!(
1832 h.foldl(Poly(Dummynator), 0),
1833 (0..10)
1834 .map(|d| d.dummy())
1835 .chain((0..=10).map(|d| d.dummy()))
1836 .chain([0_i32, 1, 2].iter().map(|d| d.dummy()))
1837 .chain(['a', 'b', 'c'].iter().map(|d| d.dummy()))
1838 .sum()
1839 );
1840 }
1841
1842 #[test]
1843 fn test_map_consuming() {
1844 let h = hlist![9000, "joe", 41f32];
1845 let mapped = h.map(hlist![|n| n + 1, |s| s, |f| f + 1f32]);
1846 assert_eq!(mapped, hlist![9001, "joe", 42f32]);
1847 }
1848
1849 #[test]
1850 fn test_poly_map_consuming() {
1851 let h = hlist![9000, "joe", 41f32, "schmoe", 50];
1852 impl Func<i32> for P {
1853 type Output = bool;
1854 fn call(args: i32) -> Self::Output {
1855 args > 100
1856 }
1857 }
1858 impl<'a> Func<&'a str> for P {
1859 type Output = usize;
1860 fn call(args: &'a str) -> Self::Output {
1861 args.len()
1862 }
1863 }
1864 impl Func<f32> for P {
1865 type Output = &'static str;
1866 fn call(_: f32) -> Self::Output {
1867 "dummy"
1868 }
1869 }
1870 struct P;
1871 assert_eq!(h.map(Poly(P)), hlist![true, 3, "dummy", 6, false]);
1872 }
1873
1874 #[test]
1875 fn test_poly_map_non_consuming() {
1876 let h = hlist![9000, "joe", 41f32, "schmoe", 50];
1877 impl<'a> Func<&'a i32> for P {
1878 type Output = bool;
1879 fn call(args: &'a i32) -> Self::Output {
1880 *args > 100
1881 }
1882 }
1883 impl<'a> Func<&'a &'a str> for P {
1884 type Output = usize;
1885 fn call(args: &'a &'a str) -> Self::Output {
1886 args.len()
1887 }
1888 }
1889 impl<'a> Func<&'a f32> for P {
1890 type Output = &'static str;
1891 fn call(_: &'a f32) -> Self::Output {
1892 "dummy"
1893 }
1894 }
1895 struct P;
1896 assert_eq!(h.to_ref().map(Poly(P)), hlist![true, 3, "dummy", 6, false]);
1897 }
1898
1899 #[test]
1900 fn test_map_single_func_consuming() {
1901 let h = hlist![9000, 9001, 9002];
1902 let mapped = h.map(|v| v + 1);
1903 assert_eq!(mapped, hlist![9001, 9002, 9003]);
1904 }
1905
1906 #[test]
1907 fn test_map_single_func_non_consuming() {
1908 let h = hlist![9000, 9001, 9002];
1909 let mapped = h.to_ref().map(|v| v + 1);
1910 assert_eq!(mapped, hlist![9001, 9002, 9003]);
1911 }
1912
1913 #[test]
1914 fn test_map_non_consuming() {
1915 let h = hlist![9000, "joe", 41f32];
1916 let mapped = h.to_ref().map(hlist![|&n| n + 1, |&s| s, |&f| f + 1f32]);
1917 assert_eq!(mapped, hlist![9001, "joe", 42f32]);
1918 }
1919
1920 #[test]
1921 fn test_zip_easy() {
1922 let h1 = hlist![9000, "joe", 41f32];
1923 let h2 = hlist!["joe", 9001, 42f32];
1924 let zipped = h1.zip(h2);
1925 assert_eq!(
1926 zipped,
1927 hlist![(9000, "joe"), ("joe", 9001), (41f32, 42f32),]
1928 );
1929 }
1930
1931 #[test]
1932 fn test_zip_composes() {
1933 let h1 = hlist![1, "1", 1.0];
1934 let h2 = hlist![2, "2", 2.0];
1935 let h3 = hlist![3, "3", 3.0];
1936 let zipped = h1.zip(h2).zip(h3);
1937 assert_eq!(
1938 zipped,
1939 hlist![((1, 2), 3), (("1", "2"), "3"), ((1.0, 2.0), 3.0)],
1940 );
1941 }
1942
1943 #[test]
1944 fn test_sculpt() {
1945 let h = hlist![9000, "joe", 41f32];
1946 let (reshaped, remainder): (HList!(f32, i32), _) = h.sculpt();
1947 assert_eq!(reshaped, hlist![41f32, 9000]);
1948 assert_eq!(remainder, hlist!["joe"])
1949 }
1950
1951 #[test]
1952 fn test_len_const() {
1953 assert_eq!(<HList![usize, &str, f32] as HList>::LEN, 3);
1954 }
1955
1956 #[test]
1957 fn test_single_func_foldl_consuming() {
1958 use std::collections::HashMap;
1959
1960 let h = hlist![
1961 ("one", 1),
1962 ("two", 2),
1963 ("three", 3),
1964 ("four", 4),
1965 ("five", 5),
1966 ];
1967 let r = h.foldl(
1968 |mut acc: HashMap<&'static str, isize>, (k, v)| {
1969 acc.insert(k, v);
1970 acc
1971 },
1972 HashMap::with_capacity(5),
1973 );
1974 let expected: HashMap<_, _> = {
1975 vec![
1976 ("one", 1),
1977 ("two", 2),
1978 ("three", 3),
1979 ("four", 4),
1980 ("five", 5),
1981 ]
1982 .into_iter()
1983 .collect()
1984 };
1985 assert_eq!(r, expected);
1986 }
1987
1988 #[test]
1989 fn test_single_func_foldl_non_consuming() {
1990 let h = hlist![1, 2, 3, 4, 5];
1991 let r: isize = h.to_ref().foldl(|acc, &next| acc + next, 0isize);
1992 assert_eq!(r, 15);
1993 }
1994
1995 #[test]
1996 #[cfg(feature = "alloc")]
1997 fn test_into_vec() {
1998 let h = hlist![1, 2, 3, 4, 5];
1999 let as_vec: Vec<_> = h.into();
2000 assert_eq!(as_vec, vec![1, 2, 3, 4, 5])
2001 }
2002
2003 #[test]
2004 fn test_lift() {
2005 type H = HList![(), usize, f64, (), bool];
2006
2007 // Ensure type inference works as expected first:
2008 let x: H = 1337.lift_into();
2009 assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
2010
2011 let x = H::lift_from(42.0);
2012 assert_eq!(x, hlist![(), 0, 42.0, (), false]);
2013
2014 let x: H = lift_from(true);
2015 assert_eq!(x, hlist![(), 0, 0.0, (), true]);
2016
2017 // Sublists:
2018 let x: H = hlist![(), true].lift_into();
2019 assert_eq!(x, hlist![(), 0, 0.0, (), true]);
2020
2021 let x: H = hlist![3.0, ()].lift_into();
2022 assert_eq!(x, hlist![(), 0, 3.0, (), false]);
2023
2024 let x: H = hlist![(), 1337].lift_into();
2025 assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
2026
2027 let x: H = hlist![(), 1337, 42.0, (), true].lift_into();
2028 assert_eq!(x, hlist![(), 1337, 42.0, (), true]);
2029 }
2030
2031 #[test]
2032 fn test_hcons_extend_hnil() {
2033 let first = hlist![0];
2034 let second = hlist![];
2035
2036 assert_eq!(first.extend(second), hlist![0]);
2037 }
2038
2039 #[test]
2040 fn test_hnil_extend_hcons() {
2041 let first = hlist![];
2042 let second = hlist![0];
2043
2044 assert_eq!(first.extend(second), hlist![0]);
2045 }
2046
2047 #[test]
2048 fn test_hnil_extend_hnil() {
2049 let first = hlist![];
2050 let second = hlist![];
2051
2052 assert_eq!(first.extend(second), hlist![]);
2053 }
2054}