Skip to main content

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