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
973#[diagnostic::on_unimplemented(
974    message = "Cannot sculpt `{Self}` into the target HList shape",
975    label = "Sculpture failed",
976    note = "The source HList must contain all the types needed for the target HList.",
977    note = "Make sure all required types are present in the source, possibly in a different order."
978)]
979pub trait Sculptor<Target, Indices> {
980    type Remainder;
981
982    /// Consumes the current HList and returns an HList with the requested shape.
983    ///
984    /// Please see the [inherent method] for more information.
985    ///
986    /// The only difference between that inherent method and this
987    /// trait method is the location of the type parameters.
988    /// (here, they are on the trait rather than the method)
989    ///
990    /// [inherent method]: struct.HCons.html#method.sculpt
991    fn sculpt(self) -> (Target, Self::Remainder);
992}
993
994/// Implementation for when the target is an empty HList (HNil)
995///
996/// Index type is HNil because we don't need an index for finding HNil
997impl<Source> Sculptor<HNil, HNil> for Source {
998    type Remainder = Source;
999
1000    #[inline(always)]
1001    fn sculpt(self) -> (HNil, Self::Remainder) {
1002        (HNil, self)
1003    }
1004}
1005
1006/// Implementation for when we have a non-empty HCons target
1007///
1008/// Indices is HCons<IndexHead, IndexTail> here because the compiler is being asked to figure out the
1009/// Index for Plucking the first item of type THead out of Self and the rest (IndexTail) is for the
1010/// Plucker's remainder induce.
1011impl<THead, TTail, SHead, STail, IndexHead, IndexTail>
1012    Sculptor<HCons<THead, TTail>, HCons<IndexHead, IndexTail>> for HCons<SHead, STail>
1013where
1014    HCons<SHead, STail>: Plucker<THead, IndexHead>,
1015    <HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder: Sculptor<TTail, IndexTail>,
1016{
1017    type Remainder = <<HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder as Sculptor<
1018        TTail,
1019        IndexTail,
1020    >>::Remainder;
1021
1022    #[inline(always)]
1023    fn sculpt(self) -> (HCons<THead, TTail>, Self::Remainder) {
1024        let (p, r): (
1025            THead,
1026            <HCons<SHead, STail> as Plucker<THead, IndexHead>>::Remainder,
1027        ) = self.pluck();
1028        let (tail, tail_remainder): (TTail, Self::Remainder) = r.sculpt();
1029        (HCons { head: p, tail }, tail_remainder)
1030    }
1031}
1032
1033impl IntoReverse for HNil {
1034    type Output = HNil;
1035    fn into_reverse(self) -> Self::Output {
1036        self
1037    }
1038}
1039
1040impl<H, Tail> IntoReverse for HCons<H, Tail>
1041where
1042    Tail: IntoReverse,
1043    <Tail as IntoReverse>::Output: Add<HCons<H, HNil>>,
1044{
1045    type Output = <<Tail as IntoReverse>::Output as Add<HCons<H, HNil>>>::Output;
1046
1047    fn into_reverse(self) -> Self::Output {
1048        self.tail.into_reverse()
1049            + HCons {
1050                head: self.head,
1051                tail: HNil,
1052            }
1053    }
1054}
1055
1056impl<P, H, Tail> HMappable<Poly<P>> for HCons<H, Tail>
1057where
1058    P: Func<H>,
1059    Tail: HMappable<Poly<P>>,
1060{
1061    type Output = HCons<<P as Func<H>>::Output, <Tail as HMappable<Poly<P>>>::Output>;
1062    fn map(self, poly: Poly<P>) -> Self::Output {
1063        HCons {
1064            head: P::call(self.head),
1065            tail: self.tail.map(poly),
1066        }
1067    }
1068}
1069
1070/// Trait for mapping over an HList
1071///
1072/// This trait is part of the implementation of the inherent method
1073/// [`HCons::map`]. Please see that method for more information.
1074///
1075/// You only need to import this trait when working with generic
1076/// HLists or Mappers of unknown type. If the type of everything is known,
1077/// then `list.map(f)` should "just work" even without the trait.
1078///
1079/// [`HCons::map`]: struct.HCons.html#method.map
1080pub trait HMappable<Mapper> {
1081    type Output;
1082
1083    /// Apply a function to each element of an HList.
1084    ///
1085    /// Please see the [inherent method] for more information.
1086    ///
1087    /// The only difference between that inherent method and this
1088    /// trait method is the location of the type parameters.
1089    /// (here, they are on the trait rather than the method)
1090    ///
1091    /// [inherent method]: struct.HCons.html#method.map
1092    fn map(self, mapper: Mapper) -> Self::Output;
1093}
1094
1095impl<F> HMappable<F> for HNil {
1096    type Output = HNil;
1097
1098    fn map(self, _: F) -> Self::Output {
1099        HNil
1100    }
1101}
1102
1103impl<F, R, H, Tail> HMappable<F> for HCons<H, Tail>
1104where
1105    F: Fn(H) -> R,
1106    Tail: HMappable<F>,
1107{
1108    type Output = HCons<R, <Tail as HMappable<F>>::Output>;
1109
1110    fn map(self, f: F) -> Self::Output {
1111        let HCons { head, tail } = self;
1112        HCons {
1113            head: f(head),
1114            tail: tail.map(f),
1115        }
1116    }
1117}
1118
1119impl<F, R, MapperTail, H, Tail> HMappable<HCons<F, MapperTail>> for HCons<H, Tail>
1120where
1121    F: FnOnce(H) -> R,
1122    Tail: HMappable<MapperTail>,
1123{
1124    type Output = HCons<R, <Tail as HMappable<MapperTail>>::Output>;
1125
1126    fn map(self, mapper: HCons<F, MapperTail>) -> Self::Output {
1127        let HCons { head, tail } = self;
1128        HCons {
1129            head: (mapper.head)(head),
1130            tail: tail.map(mapper.tail),
1131        }
1132    }
1133}
1134
1135/// Trait for zipping HLists
1136///
1137/// This trait is part of the implementation of the inherent method
1138/// [`HCons::zip`]. Please see that method for more information.
1139///
1140/// You only need to import this trait when working with generic
1141/// HLists of unknown type. If the type of everything is known,
1142/// then `list.zip(list2)` should "just work" even without the trait.
1143///
1144/// [`HCons::zip`]: struct.HCons.html#method.zip
1145pub trait HZippable<Other> {
1146    type Zipped: HList;
1147
1148    /// Zip this HList with another one.
1149    ///
1150    /// Please see the [inherent method] for more information.
1151    ///
1152    /// [inherent method]: struct.HCons.html#method.zip
1153    fn zip(self, other: Other) -> Self::Zipped;
1154}
1155
1156impl HZippable<HNil> for HNil {
1157    type Zipped = HNil;
1158    fn zip(self, _other: HNil) -> Self::Zipped {
1159        HNil
1160    }
1161}
1162
1163impl<H1, T1, H2, T2> HZippable<HCons<H2, T2>> for HCons<H1, T1>
1164where
1165    T1: HZippable<T2>,
1166{
1167    type Zipped = HCons<(H1, H2), T1::Zipped>;
1168    fn zip(self, other: HCons<H2, T2>) -> Self::Zipped {
1169        HCons {
1170            head: (self.head, other.head),
1171            tail: self.tail.zip(other.tail),
1172        }
1173    }
1174}
1175
1176/// Trait for performing a right fold over an HList
1177///
1178/// This trait is part of the implementation of the inherent method
1179/// [`HCons::foldr`]. Please see that method for more information.
1180///
1181/// You only need to import this trait when working with generic
1182/// HLists or Folders of unknown type. If the type of everything is known,
1183/// then `list.foldr(f, init)` should "just work" even without the trait.
1184///
1185/// [`HCons::foldr`]: struct.HCons.html#method.foldr
1186pub trait HFoldRightable<Folder, Init> {
1187    type Output;
1188
1189    /// Perform a right fold over an HList.
1190    ///
1191    /// Please see the [inherent method] for more information.
1192    ///
1193    /// The only difference between that inherent method and this
1194    /// trait method is the location of the type parameters.
1195    /// (here, they are on the trait rather than the method)
1196    ///
1197    /// [inherent method]: struct.HCons.html#method.foldr
1198    fn foldr(self, folder: Folder, i: Init) -> Self::Output;
1199}
1200
1201impl<F, Init> HFoldRightable<F, Init> for HNil {
1202    type Output = Init;
1203
1204    fn foldr(self, _: F, i: Init) -> Self::Output {
1205        i
1206    }
1207}
1208
1209impl<F, FolderHeadR, FolderTail, H, Tail, Init> HFoldRightable<HCons<F, FolderTail>, Init>
1210    for HCons<H, Tail>
1211where
1212    Tail: HFoldRightable<FolderTail, Init>,
1213    F: FnOnce(<Tail as HFoldRightable<FolderTail, Init>>::Output, H) -> FolderHeadR,
1214{
1215    type Output = FolderHeadR;
1216
1217    fn foldr(self, folder: HCons<F, FolderTail>, init: Init) -> Self::Output {
1218        let folded_tail = self.tail.foldr(folder.tail, init);
1219        (folder.head)(folded_tail, self.head)
1220    }
1221}
1222
1223impl<F, R, H, Tail, Init> HFoldRightable<F, Init> for HCons<H, Tail>
1224where
1225    Tail: foldr_owned::HFoldRightableOwned<F, Init>,
1226    F: Fn(<Tail as HFoldRightable<F, Init>>::Output, H) -> R,
1227{
1228    type Output = R;
1229
1230    fn foldr(self, folder: F, init: Init) -> Self::Output {
1231        foldr_owned::HFoldRightableOwned::real_foldr(self, folder, init).0
1232    }
1233}
1234
1235/// [`HFoldRightable`] inner mechanics for folding with a folder that needs to be owned.
1236pub mod foldr_owned {
1237    use super::{HCons, HFoldRightable, HNil};
1238
1239    /// A real `foldr` for the folder that must be owned to fold.
1240    ///
1241    /// Due to `HList` being a recursive struct and not linear array,
1242    /// the only way to fold it is recursive.
1243    ///
1244    /// However, there are differences in the `foldl` and `foldr` traversing
1245    /// the `HList`:
1246    ///
1247    /// 1. `foldl` calls `folder(head)` and then passes the ownership
1248    ///    of the folder to the next recursive call.
1249    /// 2. `foldr` passes the ownership of the folder to the next recursive call,
1250    ///    and then tries to call `folder(head)`; but the ownership is already gone!
1251    pub trait HFoldRightableOwned<Folder, Init>: HFoldRightable<Folder, Init> {
1252        fn real_foldr(self, folder: Folder, init: Init) -> (Self::Output, Folder);
1253    }
1254
1255    impl<F, Init> HFoldRightableOwned<F, Init> for HNil {
1256        fn real_foldr(self, f: F, i: Init) -> (Self::Output, F) {
1257            (i, f)
1258        }
1259    }
1260
1261    impl<F, H, Tail, Init> HFoldRightableOwned<F, Init> for HCons<H, Tail>
1262    where
1263        Self: HFoldRightable<F, Init>,
1264        Tail: HFoldRightableOwned<F, Init>,
1265        F: Fn(<Tail as HFoldRightable<F, Init>>::Output, H) -> Self::Output,
1266    {
1267        fn real_foldr(self, folder: F, init: Init) -> (Self::Output, F) {
1268            let (folded_tail, folder) = self.tail.real_foldr(folder, init);
1269            ((folder)(folded_tail, self.head), folder)
1270        }
1271    }
1272}
1273
1274impl<P, R, H, Tail, Init> HFoldRightable<Poly<P>, Init> for HCons<H, Tail>
1275where
1276    Tail: HFoldRightable<Poly<P>, Init>,
1277    P: Func<(<Tail as HFoldRightable<Poly<P>, Init>>::Output, H), Output = R>,
1278{
1279    type Output = R;
1280
1281    fn foldr(self, poly: Poly<P>, init: Init) -> Self::Output {
1282        let HCons { head, tail } = self;
1283        let folded_tail = tail.foldr(poly, init);
1284        P::call((folded_tail, head))
1285    }
1286}
1287
1288impl<'a> ToRef<'a> for HNil {
1289    type Output = HNil;
1290
1291    #[inline(always)]
1292    fn to_ref(&'a self) -> Self::Output {
1293        HNil
1294    }
1295}
1296
1297impl<'a, H, Tail> ToRef<'a> for HCons<H, Tail>
1298where
1299    H: 'a,
1300    Tail: ToRef<'a>,
1301{
1302    type Output = HCons<&'a H, <Tail as ToRef<'a>>::Output>;
1303
1304    #[inline(always)]
1305    fn to_ref(&'a self) -> Self::Output {
1306        HCons {
1307            head: &self.head,
1308            tail: self.tail.to_ref(),
1309        }
1310    }
1311}
1312
1313impl<'a> ToMut<'a> for HNil {
1314    type Output = HNil;
1315
1316    #[inline(always)]
1317    fn to_mut(&'a mut self) -> Self::Output {
1318        HNil
1319    }
1320}
1321
1322impl<'a, H, Tail> ToMut<'a> for HCons<H, Tail>
1323where
1324    H: 'a,
1325    Tail: ToMut<'a>,
1326{
1327    type Output = HCons<&'a mut H, <Tail as ToMut<'a>>::Output>;
1328
1329    #[inline(always)]
1330    fn to_mut(&'a mut self) -> Self::Output {
1331        HCons {
1332            head: &mut self.head,
1333            tail: self.tail.to_mut(),
1334        }
1335    }
1336}
1337
1338/// Trait for performing a left fold over an HList
1339///
1340/// This trait is part of the implementation of the inherent method
1341/// [`HCons::foldl`]. Please see that method for more information.
1342///
1343/// You only need to import this trait when working with generic
1344/// HLists or Mappers of unknown type. If the type of everything is known,
1345/// then `list.foldl(f, acc)` should "just work" even without the trait.
1346///
1347/// [`HCons::foldl`]: struct.HCons.html#method.foldl
1348pub trait HFoldLeftable<Folder, Acc> {
1349    type Output;
1350
1351    /// Perform a left fold over an HList.
1352    ///
1353    /// Please see the [inherent method] for more information.
1354    ///
1355    /// The only difference between that inherent method and this
1356    /// trait method is the location of the type parameters.
1357    /// (here, they are on the trait rather than the method)
1358    ///
1359    /// [inherent method]: struct.HCons.html#method.foldl
1360    fn foldl(self, folder: Folder, acc: Acc) -> Self::Output;
1361}
1362
1363impl<F, Acc> HFoldLeftable<F, Acc> for HNil {
1364    type Output = Acc;
1365
1366    fn foldl(self, _: F, acc: Acc) -> Self::Output {
1367        acc
1368    }
1369}
1370
1371impl<F, R, FTail, H, Tail, Acc> HFoldLeftable<HCons<F, FTail>, Acc> for HCons<H, Tail>
1372where
1373    Tail: HFoldLeftable<FTail, R>,
1374    F: FnOnce(Acc, H) -> R,
1375{
1376    type Output = <Tail as HFoldLeftable<FTail, R>>::Output;
1377
1378    fn foldl(self, folder: HCons<F, FTail>, acc: Acc) -> Self::Output {
1379        let HCons { head, tail } = self;
1380        tail.foldl(folder.tail, (folder.head)(acc, head))
1381    }
1382}
1383
1384impl<P, R, H, Tail, Acc> HFoldLeftable<Poly<P>, Acc> for HCons<H, Tail>
1385where
1386    Tail: HFoldLeftable<Poly<P>, R>,
1387    P: Func<(Acc, H), Output = R>,
1388{
1389    type Output = <Tail as HFoldLeftable<Poly<P>, R>>::Output;
1390
1391    fn foldl(self, poly: Poly<P>, acc: Acc) -> Self::Output {
1392        let HCons { head, tail } = self;
1393        let r = P::call((acc, head));
1394        tail.foldl(poly, r)
1395    }
1396}
1397
1398/// Implementation for folding over an HList using a single function that
1399/// can handle all cases
1400///
1401/// ```
1402/// # fn main() {
1403/// use frunk_core::hlist;
1404///
1405/// let h = hlist![1, 2, 3, 4, 5];
1406///
1407/// let r: isize = h.foldl(|acc, next| acc + next, 0);
1408/// assert_eq!(r, 15);
1409/// # }
1410/// ```
1411impl<F, H, Tail, Acc> HFoldLeftable<F, Acc> for HCons<H, Tail>
1412where
1413    Tail: HFoldLeftable<F, Acc>,
1414    F: Fn(Acc, H) -> Acc,
1415{
1416    type Output = <Tail as HFoldLeftable<F, Acc>>::Output;
1417
1418    fn foldl(self, f: F, acc: Acc) -> Self::Output {
1419        let HCons { head, tail } = self;
1420        let acc = f(acc, head);
1421        tail.foldl(f, acc)
1422    }
1423}
1424
1425/// Trait for transforming an HList into a nested tuple.
1426///
1427/// This trait is part of the implementation of the inherent method
1428/// [`HCons::into_tuple2`]. Please see that method for more information.
1429///
1430/// This operation is not useful in generic contexts, so it is unlikely
1431/// that you should ever need to import this trait. Do not worry;
1432/// if you have an HList of known type, then `list.into_tuple2()`
1433/// should "just work," even without the trait.
1434///
1435/// [`HCons::into_tuple2`]: struct.HCons.html#method.into_tuple2
1436pub trait IntoTuple2 {
1437    /// The 0 element in the output tuple
1438    type HeadType;
1439
1440    /// The 1 element in the output tuple
1441    type TailOutput;
1442
1443    /// Turns an HList into nested Tuple2s, which are less troublesome to pattern match
1444    /// and have a nicer type signature.
1445    ///
1446    /// Please see the [inherent method] for more information.
1447    ///
1448    /// [inherent method]: struct.HCons.html#method.into_tuple2
1449    fn into_tuple2(self) -> (Self::HeadType, Self::TailOutput);
1450}
1451
1452impl<T1, T2> IntoTuple2 for HCons<T1, HCons<T2, HNil>> {
1453    type HeadType = T1;
1454    type TailOutput = T2;
1455
1456    fn into_tuple2(self) -> (Self::HeadType, Self::TailOutput) {
1457        (self.head, self.tail.head)
1458    }
1459}
1460
1461impl<T, Tail> IntoTuple2 for HCons<T, Tail>
1462where
1463    Tail: IntoTuple2,
1464{
1465    type HeadType = T;
1466    type TailOutput = (
1467        <Tail as IntoTuple2>::HeadType,
1468        <Tail as IntoTuple2>::TailOutput,
1469    );
1470
1471    fn into_tuple2(self) -> (Self::HeadType, Self::TailOutput) {
1472        (self.head, self.tail.into_tuple2())
1473    }
1474}
1475
1476#[cfg(feature = "alloc")]
1477#[allow(clippy::from_over_into)]
1478impl<H, Tail> Into<Vec<H>> for HCons<H, Tail>
1479where
1480    Tail: Into<Vec<H>> + HList,
1481{
1482    fn into(self) -> Vec<H> {
1483        let h = self.head;
1484        let t = self.tail;
1485        let mut v = Vec::with_capacity(<Self as HList>::LEN);
1486        v.push(h);
1487        let mut t_vec: Vec<H> = t.into();
1488        v.append(&mut t_vec);
1489        v
1490    }
1491}
1492
1493#[cfg(feature = "alloc")]
1494#[allow(clippy::from_over_into)]
1495impl<T> Into<Vec<T>> for HNil {
1496    fn into(self) -> Vec<T> {
1497        Vec::with_capacity(0)
1498    }
1499}
1500
1501impl Default for HNil {
1502    fn default() -> Self {
1503        HNil
1504    }
1505}
1506
1507impl<T: Default, Tail: Default + HList> Default for HCons<T, Tail> {
1508    fn default() -> Self {
1509        h_cons(T::default(), Tail::default())
1510    }
1511}
1512
1513/// Indexed type conversions of `T -> Self` with index `I`.
1514/// This is a generalized version of `From` which for example allows the caller
1515/// to use default values for parts of `Self` and thus "fill in the blanks".
1516///
1517/// `LiftFrom` is the reciprocal of `LiftInto`.
1518///
1519/// ```
1520/// # fn main() {
1521/// use frunk::lift_from;
1522/// use frunk::prelude::*;
1523/// use frunk_core::{HList, hlist};
1524///
1525/// type H = HList![(), usize, f64, (), bool];
1526///
1527/// let x = H::lift_from(42.0);
1528/// assert_eq!(x, hlist![(), 0, 42.0, (), false]);
1529///
1530/// let x: H = lift_from(true);
1531/// assert_eq!(x, hlist![(), 0, 0.0, (), true]);
1532/// # }
1533/// ```
1534pub trait LiftFrom<T, I> {
1535    /// Performs the indexed conversion.
1536    fn lift_from(part: T) -> Self;
1537}
1538
1539/// Free function version of `LiftFrom::lift_from`.
1540pub fn lift_from<I, T, PF: LiftFrom<T, I>>(part: T) -> PF {
1541    PF::lift_from(part)
1542}
1543
1544/// An indexed conversion that consumes `self`, and produces a `T`. To produce
1545/// `T`, the index `I` may be used to for example "fill in the blanks".
1546/// `LiftInto` is the reciprocal of `LiftFrom`.
1547///
1548/// ```
1549/// # fn main() {
1550/// use frunk::prelude::*;
1551/// use frunk_core::{HList, hlist};
1552///
1553/// type H = HList![(), usize, f64, (), bool];
1554///
1555/// // Type inference works as expected:
1556/// let x: H = 1337.lift_into();
1557/// assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
1558///
1559/// // Sublists:
1560/// let x: H = hlist![(), true].lift_into();
1561/// assert_eq!(x, hlist![(), 0, 0.0, (), true]);
1562///
1563/// let x: H = hlist![3.0, ()].lift_into();
1564/// assert_eq!(x, hlist![(), 0, 3.0, (), false]);
1565///
1566/// let x: H = hlist![(), 1337].lift_into();
1567/// assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
1568///
1569/// let x: H = hlist![(), 1337, 42.0, (), true].lift_into();
1570/// assert_eq!(x, hlist![(), 1337, 42.0, (), true]);
1571/// # }
1572/// ```
1573pub trait LiftInto<T, I> {
1574    /// Performs the indexed conversion.
1575    fn lift_into(self) -> T;
1576}
1577
1578impl<T, U, I> LiftInto<U, I> for T
1579where
1580    U: LiftFrom<T, I>,
1581{
1582    fn lift_into(self) -> U {
1583        LiftFrom::lift_from(self)
1584    }
1585}
1586
1587impl<T, Tail> LiftFrom<T, Here> for HCons<T, Tail>
1588where
1589    Tail: Default + HList,
1590{
1591    fn lift_from(part: T) -> Self {
1592        h_cons(part, Tail::default())
1593    }
1594}
1595
1596impl<Head, Tail, ValAtIx, TailIx> LiftFrom<ValAtIx, There<TailIx>> for HCons<Head, Tail>
1597where
1598    Head: Default,
1599    Tail: HList + LiftFrom<ValAtIx, TailIx>,
1600{
1601    fn lift_from(part: ValAtIx) -> Self {
1602        h_cons(Head::default(), Tail::lift_from(part))
1603    }
1604}
1605
1606impl<Prefix, Suffix> LiftFrom<Prefix, Suffixed<Suffix>> for <Prefix as Add<Suffix>>::Output
1607where
1608    Prefix: HList + Add<Suffix>,
1609    Suffix: Default,
1610{
1611    fn lift_from(part: Prefix) -> Self {
1612        part + Suffix::default()
1613    }
1614}
1615
1616#[cfg(test)]
1617mod tests {
1618    use super::*;
1619
1620    use alloc::string::ToString;
1621    use alloc::vec;
1622
1623    #[test]
1624    fn test_hcons() {
1625        let hlist1 = h_cons(1, HNil);
1626        let (h, _) = hlist1.pop();
1627        assert_eq!(h, 1);
1628
1629        let hlist2 = h_cons("hello", h_cons(1, HNil));
1630        let (h2, tail2) = hlist2.pop();
1631        let (h1, _) = tail2.pop();
1632        assert_eq!(h2, "hello");
1633        assert_eq!(h1, 1);
1634    }
1635
1636    struct HasHList<T: HList>(T);
1637
1638    #[test]
1639    fn test_contained_list() {
1640        let c = HasHList(h_cons(1, HNil));
1641        let retrieved = c.0;
1642        assert_eq!(retrieved.len(), 1);
1643        let new_list = h_cons(2, retrieved);
1644        assert_eq!(new_list.len(), 2);
1645    }
1646
1647    #[test]
1648    fn test_pluck() {
1649        let h = hlist![1, "hello".to_string(), true, 42f32];
1650        let (t, r): (f32, _) = h.clone().pluck();
1651        assert_eq!(t, 42f32);
1652        assert_eq!(r, hlist![1, "hello".to_string(), true]);
1653    }
1654
1655    #[test]
1656    fn test_ref_pluck() {
1657        let h = &hlist![1, "hello".to_string(), true, 42f32];
1658        let (t, r): (&f32, _) = h.pluck();
1659        assert_eq!(t, &42f32);
1660        assert_eq!(r, hlist![&1, &"hello".to_string(), &true]);
1661    }
1662
1663    #[test]
1664    fn test_hlist_macro() {
1665        assert_eq!(hlist![], HNil);
1666        let h: HList!(i32, &str, i32) = hlist![1, "2", 3];
1667        let (h1, tail1) = h.pop();
1668        assert_eq!(h1, 1);
1669        assert_eq!(tail1, hlist!["2", 3]);
1670        let (h2, tail2) = tail1.pop();
1671        assert_eq!(h2, "2");
1672        assert_eq!(tail2, hlist![3]);
1673        let (h3, tail3) = tail2.pop();
1674        assert_eq!(h3, 3);
1675        assert_eq!(tail3, HNil);
1676    }
1677
1678    #[test]
1679    #[allow(non_snake_case)]
1680    fn test_Hlist_macro() {
1681        let h1: HList!(i32, &str, i32) = hlist![1, "2", 3];
1682        let h2: HList!(i32, &str, i32,) = hlist![1, "2", 3];
1683        let h3: HList!(i32) = hlist![1];
1684        let h4: HList!(i32,) = hlist![1,];
1685        assert_eq!(h1, h2);
1686        assert_eq!(h3, h4);
1687    }
1688
1689    #[test]
1690    fn test_pattern_matching() {
1691        let hlist_pat!(one1) = hlist!["one"];
1692        assert_eq!(one1, "one");
1693        let hlist_pat!(one2,) = hlist!["one"];
1694        assert_eq!(one2, "one");
1695
1696        let h = hlist![5, 3.2f32, true, "blue"];
1697        let hlist_pat!(five, float, right, s) = h;
1698        assert_eq!(five, 5);
1699        assert_eq!(float, 3.2f32);
1700        assert!(right);
1701        assert_eq!(s, "blue");
1702
1703        let h2 = hlist![13.5f32, "hello", Some(41)];
1704        let hlist_pat![a, b, c,] = h2;
1705        assert_eq!(a, 13.5f32);
1706        assert_eq!(b, "hello");
1707        assert_eq!(c, Some(41));
1708    }
1709
1710    #[test]
1711    fn test_add() {
1712        let h1 = hlist![true, "hi"];
1713        let h2 = hlist![1, 32f32];
1714        let combined = h1 + h2;
1715        assert_eq!(combined, hlist![true, "hi", 1, 32f32])
1716    }
1717
1718    #[test]
1719    fn test_into_reverse() {
1720        let h1 = hlist![true, "hi"];
1721        let h2 = hlist![1, 32f32];
1722        assert_eq!(h1.into_reverse(), hlist!["hi", true]);
1723        assert_eq!(h2.into_reverse(), hlist![32f32, 1]);
1724    }
1725
1726    #[test]
1727    fn test_foldr_consuming() {
1728        let h = hlist![1, false, 42f32];
1729        let folded = h.foldr(
1730            hlist![
1731                |acc, i| i + acc,
1732                |acc, _| if acc > 42f32 { 9000 } else { 0 },
1733                |acc, f| f + acc,
1734            ],
1735            1f32,
1736        );
1737        assert_eq!(folded, 9001)
1738    }
1739
1740    #[test]
1741    fn test_single_func_foldr_consuming() {
1742        let h = hlist![1, 2, 3];
1743        let folded = h.foldr(&|acc, i| i * acc, 1);
1744        assert_eq!(folded, 6)
1745    }
1746
1747    #[test]
1748    fn test_foldr_non_consuming() {
1749        let h = hlist![1, false, 42f32];
1750        let folder = hlist![
1751            |acc, &i| i + acc,
1752            |acc, &_| if acc > 42f32 { 9000 } else { 0 },
1753            |acc, &f| f + acc
1754        ];
1755        let folded = h.to_ref().foldr(folder, 1f32);
1756        assert_eq!(folded, 9001)
1757    }
1758
1759    #[test]
1760    fn test_poly_foldr_consuming() {
1761        trait Dummy {
1762            fn dummy(&self) -> i32 {
1763                1
1764            }
1765        }
1766        impl<T: ?Sized> Dummy for T {}
1767
1768        struct Dummynator;
1769        impl<T: Dummy, I: IntoIterator<Item = T>> Func<(i32, I)> for Dummynator {
1770            type Output = i32;
1771            fn call(args: (i32, I)) -> Self::Output {
1772                let (init, i) = args;
1773                i.into_iter().fold(init, |init, x| init + x.dummy())
1774            }
1775        }
1776
1777        let h = hlist![0..10, 0..=10, &[0, 1, 2], &['a', 'b', 'c']];
1778        assert_eq!(
1779            h.foldr(Poly(Dummynator), 0),
1780            (0..10)
1781                .map(|d| d.dummy())
1782                .chain((0..=10).map(|d| d.dummy()))
1783                .chain([0_i32, 1, 2].iter().map(|d| d.dummy()))
1784                .chain(['a', 'b', 'c'].iter().map(|d| d.dummy()))
1785                .sum()
1786        );
1787    }
1788
1789    #[test]
1790    fn test_foldl_consuming() {
1791        let h = hlist![1, false, 42f32];
1792        let folded = h.foldl(
1793            hlist![
1794                |acc, i| i + acc,
1795                |acc, b: bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
1796                |acc, f| f + acc,
1797            ],
1798            1,
1799        );
1800        assert_eq!(42f32, folded)
1801    }
1802
1803    #[test]
1804    fn test_foldl_non_consuming() {
1805        let h = hlist![1, false, 42f32];
1806        let folded = h.to_ref().foldl(
1807            hlist![
1808                |acc, &i| i + acc,
1809                |acc, b: &bool| if !b && acc > 42 { 9000f32 } else { 0f32 },
1810                |acc, &f| f + acc,
1811            ],
1812            1,
1813        );
1814        assert_eq!(42f32, folded);
1815        assert_eq!((&h.head), &1);
1816    }
1817
1818    #[test]
1819    fn test_poly_foldl_consuming() {
1820        trait Dummy {
1821            fn dummy(&self) -> i32 {
1822                1
1823            }
1824        }
1825        impl<T: ?Sized> Dummy for T {}
1826
1827        struct Dummynator;
1828        impl<T: Dummy, I: IntoIterator<Item = T>> Func<(i32, I)> for Dummynator {
1829            type Output = i32;
1830            fn call(args: (i32, I)) -> Self::Output {
1831                let (acc, i) = args;
1832                i.into_iter().fold(acc, |acc, x| acc + x.dummy())
1833            }
1834        }
1835
1836        let h = hlist![0..10, 0..=10, &[0, 1, 2], &['a', 'b', 'c']];
1837        assert_eq!(
1838            h.foldl(Poly(Dummynator), 0),
1839            (0..10)
1840                .map(|d| d.dummy())
1841                .chain((0..=10).map(|d| d.dummy()))
1842                .chain([0_i32, 1, 2].iter().map(|d| d.dummy()))
1843                .chain(['a', 'b', 'c'].iter().map(|d| d.dummy()))
1844                .sum()
1845        );
1846    }
1847
1848    #[test]
1849    fn test_map_consuming() {
1850        let h = hlist![9000, "joe", 41f32];
1851        let mapped = h.map(hlist![|n| n + 1, |s| s, |f| f + 1f32]);
1852        assert_eq!(mapped, hlist![9001, "joe", 42f32]);
1853    }
1854
1855    #[test]
1856    fn test_poly_map_consuming() {
1857        let h = hlist![9000, "joe", 41f32, "schmoe", 50];
1858        impl Func<i32> for P {
1859            type Output = bool;
1860            fn call(args: i32) -> Self::Output {
1861                args > 100
1862            }
1863        }
1864        impl<'a> Func<&'a str> for P {
1865            type Output = usize;
1866            fn call(args: &'a str) -> Self::Output {
1867                args.len()
1868            }
1869        }
1870        impl Func<f32> for P {
1871            type Output = &'static str;
1872            fn call(_: f32) -> Self::Output {
1873                "dummy"
1874            }
1875        }
1876        struct P;
1877        assert_eq!(h.map(Poly(P)), hlist![true, 3, "dummy", 6, false]);
1878    }
1879
1880    #[test]
1881    fn test_poly_map_non_consuming() {
1882        let h = hlist![9000, "joe", 41f32, "schmoe", 50];
1883        impl<'a> Func<&'a i32> for P {
1884            type Output = bool;
1885            fn call(args: &'a i32) -> Self::Output {
1886                *args > 100
1887            }
1888        }
1889        impl<'a> Func<&'a &'a str> for P {
1890            type Output = usize;
1891            fn call(args: &'a &'a str) -> Self::Output {
1892                args.len()
1893            }
1894        }
1895        impl<'a> Func<&'a f32> for P {
1896            type Output = &'static str;
1897            fn call(_: &'a f32) -> Self::Output {
1898                "dummy"
1899            }
1900        }
1901        struct P;
1902        assert_eq!(h.to_ref().map(Poly(P)), hlist![true, 3, "dummy", 6, false]);
1903    }
1904
1905    #[test]
1906    fn test_map_single_func_consuming() {
1907        let h = hlist![9000, 9001, 9002];
1908        let mapped = h.map(|v| v + 1);
1909        assert_eq!(mapped, hlist![9001, 9002, 9003]);
1910    }
1911
1912    #[test]
1913    fn test_map_single_func_non_consuming() {
1914        let h = hlist![9000, 9001, 9002];
1915        let mapped = h.to_ref().map(|v| v + 1);
1916        assert_eq!(mapped, hlist![9001, 9002, 9003]);
1917    }
1918
1919    #[test]
1920    fn test_map_non_consuming() {
1921        let h = hlist![9000, "joe", 41f32];
1922        let mapped = h.to_ref().map(hlist![|&n| n + 1, |&s| s, |&f| f + 1f32]);
1923        assert_eq!(mapped, hlist![9001, "joe", 42f32]);
1924    }
1925
1926    #[test]
1927    fn test_zip_easy() {
1928        let h1 = hlist![9000, "joe", 41f32];
1929        let h2 = hlist!["joe", 9001, 42f32];
1930        let zipped = h1.zip(h2);
1931        assert_eq!(
1932            zipped,
1933            hlist![(9000, "joe"), ("joe", 9001), (41f32, 42f32),]
1934        );
1935    }
1936
1937    #[test]
1938    fn test_zip_composes() {
1939        let h1 = hlist![1, "1", 1.0];
1940        let h2 = hlist![2, "2", 2.0];
1941        let h3 = hlist![3, "3", 3.0];
1942        let zipped = h1.zip(h2).zip(h3);
1943        assert_eq!(
1944            zipped,
1945            hlist![((1, 2), 3), (("1", "2"), "3"), ((1.0, 2.0), 3.0)],
1946        );
1947    }
1948
1949    #[test]
1950    fn test_sculpt() {
1951        let h = hlist![9000, "joe", 41f32];
1952        let (reshaped, remainder): (HList!(f32, i32), _) = h.sculpt();
1953        assert_eq!(reshaped, hlist![41f32, 9000]);
1954        assert_eq!(remainder, hlist!["joe"])
1955    }
1956
1957    #[test]
1958    fn test_len_const() {
1959        assert_eq!(<HList![usize, &str, f32] as HList>::LEN, 3);
1960    }
1961
1962    #[test]
1963    fn test_single_func_foldl_consuming() {
1964        use std::collections::HashMap;
1965
1966        let h = hlist![
1967            ("one", 1),
1968            ("two", 2),
1969            ("three", 3),
1970            ("four", 4),
1971            ("five", 5),
1972        ];
1973        let r = h.foldl(
1974            |mut acc: HashMap<&'static str, isize>, (k, v)| {
1975                acc.insert(k, v);
1976                acc
1977            },
1978            HashMap::with_capacity(5),
1979        );
1980        let expected: HashMap<_, _> = {
1981            vec![
1982                ("one", 1),
1983                ("two", 2),
1984                ("three", 3),
1985                ("four", 4),
1986                ("five", 5),
1987            ]
1988            .into_iter()
1989            .collect()
1990        };
1991        assert_eq!(r, expected);
1992    }
1993
1994    #[test]
1995    fn test_single_func_foldl_non_consuming() {
1996        let h = hlist![1, 2, 3, 4, 5];
1997        let r: isize = h.to_ref().foldl(|acc, &next| acc + next, 0isize);
1998        assert_eq!(r, 15);
1999    }
2000
2001    #[test]
2002    #[cfg(feature = "alloc")]
2003    fn test_into_vec() {
2004        let h = hlist![1, 2, 3, 4, 5];
2005        let as_vec: Vec<_> = h.into();
2006        assert_eq!(as_vec, vec![1, 2, 3, 4, 5])
2007    }
2008
2009    #[test]
2010    fn test_lift() {
2011        type H = HList![(), usize, f64, (), bool];
2012
2013        // Ensure type inference works as expected first:
2014        let x: H = 1337.lift_into();
2015        assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
2016
2017        let x = H::lift_from(42.0);
2018        assert_eq!(x, hlist![(), 0, 42.0, (), false]);
2019
2020        let x: H = lift_from(true);
2021        assert_eq!(x, hlist![(), 0, 0.0, (), true]);
2022
2023        // Sublists:
2024        let x: H = hlist![(), true].lift_into();
2025        assert_eq!(x, hlist![(), 0, 0.0, (), true]);
2026
2027        let x: H = hlist![3.0, ()].lift_into();
2028        assert_eq!(x, hlist![(), 0, 3.0, (), false]);
2029
2030        let x: H = hlist![(), 1337].lift_into();
2031        assert_eq!(x, hlist![(), 1337, 0.0, (), false]);
2032
2033        let x: H = hlist![(), 1337, 42.0, (), true].lift_into();
2034        assert_eq!(x, hlist![(), 1337, 42.0, (), true]);
2035    }
2036
2037    #[test]
2038    fn test_hcons_extend_hnil() {
2039        let first = hlist![0];
2040        let second = hlist![];
2041
2042        assert_eq!(first.extend(second), hlist![0]);
2043    }
2044
2045    #[test]
2046    fn test_hnil_extend_hcons() {
2047        let first = hlist![];
2048        let second = hlist![0];
2049
2050        assert_eq!(first.extend(second), hlist![0]);
2051    }
2052
2053    #[test]
2054    fn test_hnil_extend_hnil() {
2055        let first = hlist![];
2056        let second = hlist![];
2057
2058        assert_eq!(first.extend(second), hlist![]);
2059    }
2060}