1use crate::hlist::*;
151use crate::indices::*;
152use crate::traits::ToRef;
153#[cfg(feature = "serde")]
154use serde::{Deserialize, Serialize};
155
156use core::fmt;
157use core::marker::PhantomData;
158
159#[diagnostic::on_unimplemented(
199 message = "Cannot derive labelled generic representation for `{Self}`",
200 label = "LabelledGeneric not implemented",
201 note = "The type must have a LabelledGeneric instance to be used with transform_from or transmogrify.",
202 note = "Derive LabelledGeneric using #[derive(LabelledGeneric)] on your struct or enum."
203)]
204pub trait LabelledGeneric {
205 type Repr;
207
208 fn into(self) -> Self::Repr;
210
211 fn from(repr: Self::Repr) -> Self;
214
215 #[inline(always)]
218 fn convert_from<Src>(src: Src) -> Self
219 where
220 Src: LabelledGeneric<Repr = Self::Repr>,
221 Self: Sized,
222 {
223 let repr = <Src as LabelledGeneric>::into(src);
224 <Self as LabelledGeneric>::from(repr)
225 }
226
227 #[deprecated(note = "obsolete, transform_from instead")]
233 fn sculpted_convert_from<A, Indices>(a: A) -> Self
234 where
235 A: LabelledGeneric,
236 Self: Sized,
237 <A as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices>,
239 {
240 <Self as LabelledGeneric>::transform_from(a)
241 }
242
243 #[inline(always)]
251 fn transform_from<Src, Indices>(src: Src) -> Self
252 where
253 Src: LabelledGeneric,
254 Self: Sized,
255 <Src as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices>,
257 {
258 let src_gen = <Src as LabelledGeneric>::into(src);
259 let (self_gen, _): (<Self as LabelledGeneric>::Repr, _) = src_gen.sculpt();
261 <Self as LabelledGeneric>::from(self_gen)
262 }
263}
264
265pub trait IntoLabelledGeneric {
266 type Repr;
268
269 fn into(self) -> Self::Repr;
271}
272
273impl<A> IntoLabelledGeneric for A
274where
275 A: LabelledGeneric,
276{
277 type Repr = <A as LabelledGeneric>::Repr;
278
279 #[inline(always)]
280 fn into(self) -> <Self as IntoLabelledGeneric>::Repr {
281 self.into()
282 }
283}
284
285pub fn from_labelled_generic<Dst, Repr>(repr: Repr) -> Dst
287where
288 Dst: LabelledGeneric<Repr = Repr>,
289{
290 <Dst as LabelledGeneric>::from(repr)
291}
292
293pub fn into_labelled_generic<Src, Repr>(src: Src) -> Repr
295where
296 Src: LabelledGeneric<Repr = Repr>,
297{
298 <Src as LabelledGeneric>::into(src)
299}
300
301pub fn labelled_convert_from<Src, Dst, Repr>(src: Src) -> Dst
304where
305 Src: LabelledGeneric<Repr = Repr>,
306 Dst: LabelledGeneric<Repr = Repr>,
307{
308 <Dst as LabelledGeneric>::convert_from(src)
309}
310
311#[deprecated(note = "obsolete, transform_from instead")]
317pub fn sculpted_convert_from<A, B, Indices>(a: A) -> B
318where
319 A: LabelledGeneric,
320 B: LabelledGeneric,
321 <A as LabelledGeneric>::Repr: Sculptor<<B as LabelledGeneric>::Repr, Indices>,
323{
324 <B as LabelledGeneric>::transform_from(a)
325}
326pub fn transform_from<Src, Dst, Indices>(src: Src) -> Dst
332where
333 Src: LabelledGeneric,
334 Dst: LabelledGeneric,
335 <Src as LabelledGeneric>::Repr: Sculptor<<Dst as LabelledGeneric>::Repr, Indices>,
337{
338 <Dst as LabelledGeneric>::transform_from(src)
339}
340
341pub mod chars {
342 macro_rules! create_enums_for {
355 ($($i: ident)*) => {
356 $(
357 #[allow(non_snake_case, non_camel_case_types)]
358 #[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
359 pub enum $i {}
360 )*
361 }
362 }
363
364 create_enums_for! {
366 a b c d e f g h i j k l m n o p q r s t u v w x y z
368 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
369 _1 _2 _3 _4 _5 _6 _7 _8 _9 _0 __ _uc uc_
370 }
371
372 #[test]
373 fn simple_var_names_are_allowed() {
374 let a = 3;
379 #[allow(clippy::match_single_binding)]
380 match a {
381 a => assert_eq!(a, 3),
382 }
383 }
384}
385
386#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
403#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
404pub struct Field<Name, Type> {
405 name_type_holder: PhantomData<Name>,
406 pub name: &'static str,
407 pub value: Type,
408}
409
410#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
413#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
414pub struct ValueField<Type> {
415 pub name: &'static str,
416 pub value: Type,
417}
418
419impl<Name, Type> fmt::Debug for Field<Name, Type>
420where
421 Type: fmt::Debug,
422{
423 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
424 f.debug_struct("Field")
425 .field("name", &DebugAsDisplay(&self.name))
427 .field("value", &self.value)
428 .finish()
429 }
430}
431
432impl<Type> fmt::Debug for ValueField<Type>
433where
434 Type: fmt::Debug,
435{
436 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
437 f.debug_struct("ValueField")
438 .field("name", &DebugAsDisplay(&self.name))
440 .field("value", &self.value)
441 .finish()
442 }
443}
444
445struct DebugAsDisplay<T>(T);
447
448impl<T: fmt::Display> fmt::Debug for DebugAsDisplay<T> {
449 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450 fmt::Display::fmt(&self.0, f)
451 }
452}
453
454pub fn field_with_name<Label, Value>(name: &'static str, value: Value) -> Field<Label, Value> {
470 Field {
471 name_type_holder: PhantomData,
472 name,
473 value,
474 }
475}
476
477pub trait IntoUnlabelled {
479 type Output;
480
481 fn into_unlabelled(self) -> Self::Output;
504}
505
506impl IntoUnlabelled for HNil {
508 type Output = HNil;
509 fn into_unlabelled(self) -> Self::Output {
510 self
511 }
512}
513
514impl<Label, Value, Tail> IntoUnlabelled for HCons<Field<Label, Value>, Tail>
516where
517 Tail: IntoUnlabelled,
518{
519 type Output = HCons<Value, <Tail as IntoUnlabelled>::Output>;
520
521 fn into_unlabelled(self) -> Self::Output {
522 HCons {
523 head: self.head.value,
524 tail: self.tail.into_unlabelled(),
525 }
526 }
527}
528
529pub trait IntoValueLabelled {
531 type Output;
532
533 fn into_value_labelled(self) -> Self::Output;
568}
569
570impl IntoValueLabelled for HNil {
571 type Output = HNil;
572 fn into_value_labelled(self) -> Self::Output {
573 self
574 }
575}
576
577impl<Label, Value, Tail> IntoValueLabelled for HCons<Field<Label, Value>, Tail>
578where
579 Tail: IntoValueLabelled,
580{
581 type Output = HCons<ValueField<Value>, <Tail as IntoValueLabelled>::Output>;
582
583 fn into_value_labelled(self) -> Self::Output {
584 HCons {
585 head: ValueField {
586 name: self.head.name,
587 value: self.head.value,
588 },
589 tail: self.tail.into_value_labelled(),
590 }
591 }
592}
593
594#[diagnostic::on_unimplemented(
596 message = "Cannot find field with key `{TargetKey}` in `{Self}`",
597 label = "Field not found",
598 note = "The source type does not contain a field with the target key.",
599 note = "Make sure the field name exists in the source struct and matches exactly."
600)]
601pub trait ByNameFieldPlucker<TargetKey, Index> {
602 type TargetValue;
603 type Remainder;
604
605 fn pluck_by_name(self) -> (Field<TargetKey, Self::TargetValue>, Self::Remainder);
607}
608
609impl<K, V, Tail> ByNameFieldPlucker<K, Here> for HCons<Field<K, V>, Tail> {
611 type TargetValue = V;
612 type Remainder = Tail;
613
614 #[inline(always)]
615 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
616 let field = field_with_name(self.head.name, self.head.value);
617 (field, self.tail)
618 }
619}
620
621impl<Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for HCons<Head, Tail>
623where
624 Tail: ByNameFieldPlucker<K, TailIndex>,
625{
626 type TargetValue = <Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue;
627 type Remainder = HCons<Head, <Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>;
628
629 #[inline(always)]
630 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
631 let (target, tail_remainder) =
632 <Tail as ByNameFieldPlucker<K, TailIndex>>::pluck_by_name(self.tail);
633 (
634 target,
635 HCons {
636 head: self.head,
637 tail: tail_remainder,
638 },
639 )
640 }
641}
642
643impl<'a, K, V, Tail: ToRef<'a>> ByNameFieldPlucker<K, Here> for &'a HCons<Field<K, V>, Tail> {
645 type TargetValue = &'a V;
646 type Remainder = <Tail as ToRef<'a>>::Output;
647
648 #[inline(always)]
649 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
650 let field = field_with_name(self.head.name, &self.head.value);
651 (field, self.tail.to_ref())
652 }
653}
654
655impl<'a, Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for &'a HCons<Head, Tail>
657where
658 &'a Tail: ByNameFieldPlucker<K, TailIndex>,
659{
660 type TargetValue = <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue;
661 type Remainder = HCons<&'a Head, <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>;
662
663 #[inline(always)]
664 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
665 let (target, tail_remainder) =
666 <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::pluck_by_name(&self.tail);
667 (
668 target,
669 HCons {
670 head: &self.head,
671 tail: tail_remainder,
672 },
673 )
674 }
675}
676
677#[diagnostic::on_unimplemented(
768 message = "Cannot transmogrify `{Self}` into `{Target}`",
769 label = "Cannot convert this type into the target type",
770 note = "Transmogrify requires that the source and target types have compatible structures.",
771 note = "The source type must have all the fields needed for the target type, possibly in a different order or nested structure.",
772 note = "Check that field names match and types are compatible between the source and target."
773)]
774pub trait Transmogrifier<Target, TransmogrifyIndexIndices> {
775 fn transmogrify(self) -> Target;
779}
780
781impl<Key, SourceValue> Transmogrifier<SourceValue, IdentityTransMog> for Field<Key, SourceValue> {
783 #[inline(always)]
784 fn transmogrify(self) -> SourceValue {
785 self.value
786 }
787}
788
789#[cfg(feature = "alloc")]
791mod _alloc {
792 use super::MappingIndicesWrapper;
793 use super::{Field, Transmogrifier};
794 use alloc::boxed::Box;
795 use alloc::collections::{LinkedList, VecDeque};
796 use alloc::vec::Vec;
797
798 macro_rules! transmogrify_seq {
799 ($container:ident) => {
800 impl<Key, Source, Target, InnerIndices>
803 Transmogrifier<$container<Target>, MappingIndicesWrapper<InnerIndices>>
804 for Field<Key, $container<Source>>
805 where
806 Source: Transmogrifier<Target, InnerIndices>,
807 {
808 fn transmogrify(self) -> $container<Target> {
809 self.value.into_iter().map(|e| e.transmogrify()).collect()
810 }
811 }
812 };
813 }
814
815 transmogrify_seq!(Vec);
816 transmogrify_seq!(LinkedList);
817 transmogrify_seq!(VecDeque);
818
819 impl<Key, Source, Target, InnerIndices>
822 Transmogrifier<Box<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, Box<Source>>
823 where
824 Source: Transmogrifier<Target, InnerIndices>,
825 {
826 fn transmogrify(self) -> Box<Target> {
827 Box::new(self.value.transmogrify())
828 }
829 }
830}
831
832impl<Key, Source, Target, InnerIndices>
835 Transmogrifier<Option<Target>, MappingIndicesWrapper<InnerIndices>>
836 for Field<Key, Option<Source>>
837where
838 Source: Transmogrifier<Target, InnerIndices>,
839{
840 fn transmogrify(self) -> Option<Target> {
841 self.value.map(|e| e.transmogrify())
842 }
843}
844
845impl Transmogrifier<HNil, HNil> for HNil {
847 #[inline(always)]
848 fn transmogrify(self) -> HNil {
849 HNil
850 }
851}
852
853impl<SourceHead, SourceTail> Transmogrifier<HNil, HNil> for HCons<SourceHead, SourceTail> {
855 #[inline(always)]
856 fn transmogrify(self) -> HNil {
857 HNil
858 }
859}
860
861impl<
864 SourceHead,
865 SourceTail,
866 TargetName,
867 TargetHead,
868 TargetTail,
869 TransmogHeadIndex,
870 TransmogTailIndices,
871 > Transmogrifier<HCons<TargetHead, TargetTail>, HCons<TransmogHeadIndex, TransmogTailIndices>>
872 for Field<TargetName, HCons<SourceHead, SourceTail>>
873where
874 HCons<SourceHead, SourceTail>: Transmogrifier<
875 HCons<TargetHead, TargetTail>,
876 HCons<TransmogHeadIndex, TransmogTailIndices>,
877 >,
878{
879 #[inline(always)]
880 fn transmogrify(self) -> HCons<TargetHead, TargetTail> {
881 self.value.transmogrify()
882 }
883}
884
885impl<
889 SourceHead,
890 SourceTail,
891 TargetHeadName,
892 TargetHeadValue,
893 TargetTail,
894 PluckSourceHeadNameIndex,
895 TransMogSourceHeadValueIndices,
896 TransMogTailIndices,
897 >
898 Transmogrifier<
899 HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail>,
900 HCons<
901 DoTransmog<PluckSourceHeadNameIndex, TransMogSourceHeadValueIndices>,
902 TransMogTailIndices,
903 >,
904 > for HCons<SourceHead, SourceTail>
905where
906 HCons<SourceHead, SourceTail>: ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>,
908 Field<
910 TargetHeadName,
911 <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
912 TargetHeadName,
913 PluckSourceHeadNameIndex,
914 >>::TargetValue,
915 >: Transmogrifier<TargetHeadValue, TransMogSourceHeadValueIndices>,
916 <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
919 TargetHeadName,
920 PluckSourceHeadNameIndex,
921 >>::Remainder: Transmogrifier<TargetTail, TransMogTailIndices>,
922{
923 #[inline(always)]
924 fn transmogrify(self) -> HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail> {
925 let (source_field_for_head_target_name, remainder) = self.pluck_by_name();
926 let name = source_field_for_head_target_name.name;
927 let transmogrified_value: TargetHeadValue =
928 source_field_for_head_target_name.transmogrify();
929 let as_field: Field<TargetHeadName, TargetHeadValue> =
930 field_with_name(name, transmogrified_value);
931 HCons {
932 head: as_field,
933 tail: remainder.transmogrify(),
934 }
935 }
936}
937
938impl<Source, Target, TransmogIndices>
939 Transmogrifier<Target, LabelledGenericTransmogIndicesWrapper<TransmogIndices>> for Source
940where
941 Source: LabelledGeneric,
942 Target: LabelledGeneric,
943 <Source as LabelledGeneric>::Repr:
944 Transmogrifier<<Target as LabelledGeneric>::Repr, TransmogIndices>,
945{
946 #[inline(always)]
947 fn transmogrify(self) -> Target {
948 let source_as_repr = self.into();
949 let source_transmogged = source_as_repr.transmogrify();
950 <Target as LabelledGeneric>::from(source_transmogged)
951 }
952}
953
954impl<Source, TargetName, TargetValue, TransmogIndices>
956 Transmogrifier<TargetValue, PluckedLabelledGenericIndicesWrapper<TransmogIndices>>
957 for Field<TargetName, Source>
958where
959 Source: LabelledGeneric,
960 TargetValue: LabelledGeneric,
961 Source: Transmogrifier<TargetValue, TransmogIndices>,
962{
963 #[inline(always)]
964 fn transmogrify(self) -> TargetValue {
965 self.value.transmogrify()
966 }
967}
968
969#[cfg(test)]
970mod tests {
971 use super::chars::*;
972 use super::*;
973 use alloc::collections::{LinkedList, VecDeque};
974 use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
975
976 #[allow(non_camel_case_types)]
978 type abc = (a, b, c);
979 #[allow(non_camel_case_types)]
980 type name = (n, a, m, e);
981 #[allow(non_camel_case_types)]
982 type age = (a, g, e);
983 #[allow(non_camel_case_types)]
984 type is_admin = (i, s, __, a, d, m, i, n);
985 #[allow(non_camel_case_types)]
986 type inner = (i, n, n, e, r);
987
988 #[test]
989 fn test_label_new_building() {
990 let l1 = field!(abc, 3);
991 assert_eq!(l1.value, 3);
992 assert_eq!(l1.name, "abc");
993 let l2 = field!((a, b, c), 3);
994 assert_eq!(l2.value, 3);
995 assert_eq!(l2.name, "abc");
996
997 let l3 = field!(abc, 3, "nope");
999 assert_eq!(l3.value, 3);
1000 assert_eq!(l3.name, "nope");
1001 let l4 = field!((a, b, c), 3, "nope");
1002 assert_eq!(l4.value, 3);
1003 assert_eq!(l4.name, "nope");
1004 }
1005
1006 #[test]
1007 fn test_field_construction() {
1008 let f1 = field!(age, 3);
1009 let f2 = field!((a, g, e), 3);
1010 assert_eq!(f1, f2)
1011 }
1012
1013 #[test]
1014 fn test_field_debug() {
1015 let field = field!(age, 3);
1016 let hlist_pat![value_field] = hlist![field].into_value_labelled();
1017
1018 assert!(format!("{:?}", field).contains("name: age"));
1020 assert!(format!("{:?}", value_field).contains("name: age"));
1021 assert!(format!("{:#?}", field).contains('\n'));
1023 assert!(format!("{:#?}", value_field).contains('\n'));
1024 }
1025
1026 #[test]
1027 fn test_anonymous_record_usage() {
1028 let record = hlist![field!(name, "Joe"), field!((a, g, e), 30)];
1029 let (name, _): (Field<name, _>, _) = record.pluck();
1030 assert_eq!(name.value, "Joe")
1031 }
1032
1033 #[test]
1034 fn test_pluck_by_name() {
1035 let record = hlist![
1036 field!(is_admin, true),
1037 field!(name, "Joe".to_string()),
1038 field!((a, g, e), 30),
1039 ];
1040
1041 let (name, r): (Field<name, _>, _) = record.clone().pluck_by_name();
1042 assert_eq!(name.value, "Joe");
1043 assert_eq!(r, hlist![field!(is_admin, true), field!((a, g, e), 30),]);
1044 }
1045
1046 #[test]
1047 fn test_ref_pluck_by_name() {
1048 let record = &hlist![
1049 field!(is_admin, true),
1050 field!(name, "Joe".to_string()),
1051 field!((a, g, e), 30),
1052 ];
1053
1054 let (name, r): (Field<name, _>, _) = record.pluck_by_name();
1055 assert_eq!(name.value, "Joe");
1056 assert_eq!(r, hlist![&field!(is_admin, true), &field!((a, g, e), 30),]);
1057 }
1058
1059 #[test]
1060 fn test_unlabelling() {
1061 let labelled_hlist = hlist![field!(name, "joe"), field!((a, g, e), 3)];
1062 let unlabelled = labelled_hlist.into_unlabelled();
1063 assert_eq!(unlabelled, hlist!["joe", 3])
1064 }
1065
1066 #[test]
1067 fn test_value_labelling() {
1068 let labelled_hlist = hlist![field!(name, "joe"), field!((a, g, e), 3)];
1069 let value_labelled: HList![ValueField<&str>, ValueField<isize>] =
1070 labelled_hlist.into_value_labelled();
1071 let hlist_pat!(f1, f2) = value_labelled;
1072 assert_eq!(f1.name, "name");
1073 assert_eq!(f2.name, "age");
1074 }
1075
1076 #[test]
1077 fn test_name() {
1078 let labelled = field!(name, "joe");
1079 assert_eq!(labelled.name, "name")
1080 }
1081
1082 #[test]
1083 fn test_transmogrify_hnil_identity() {
1084 let hnil_again: HNil = HNil.transmogrify();
1085 assert_eq!(HNil, hnil_again);
1086 }
1087
1088 #[test]
1089 fn test_transmogrify_hcons_sculpting_super_simple() {
1090 type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1091 type Target = HList![Field<age, i32>];
1092 let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1093 let t_hcons: Target = hcons.transmogrify();
1094 assert_eq!(t_hcons, hlist!(field!(age, 3)));
1095 }
1096
1097 #[test]
1098 fn test_transmogrify_hcons_sculpting_somewhat_simple() {
1099 type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1100 type Target = HList![Field<is_admin, bool>, Field<name, &'static str>];
1101 let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1102 let t_hcons: Target = hcons.transmogrify();
1103 assert_eq!(t_hcons, hlist!(field!(is_admin, true), field!(name, "joe")));
1104 }
1105
1106 #[test]
1107 fn test_transmogrify_hcons_recursive_simple() {
1108 type Source = HList![
1109 Field<name, HList![
1110 Field<inner, f32>,
1111 Field<is_admin, bool>,
1112 ]>,
1113 Field<age, i32>,
1114 Field<is_admin, bool>];
1115 type Target = HList![
1116 Field<is_admin, bool>,
1117 Field<name, HList![
1118 Field<is_admin, bool>,
1119 ]>,
1120 ];
1121 let source: Source = hlist![
1122 field!(name, hlist![field!(inner, 42f32), field!(is_admin, true)]),
1123 field!(age, 32),
1124 field!(is_admin, true)
1125 ];
1126 let target: Target = source.transmogrify();
1127 assert_eq!(
1128 target,
1129 hlist![
1130 field!(is_admin, true),
1131 field!(name, hlist![field!(is_admin, true)]),
1132 ]
1133 )
1134 }
1135
1136 #[test]
1137 fn test_transmogrify_hcons_sculpting_required_simple() {
1138 type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1139 type Target = HList![Field<is_admin, bool>, Field<name, &'static str>, Field<age, i32>];
1140 let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1141 let t_hcons: Target = hcons.transmogrify();
1142 assert_eq!(
1143 t_hcons,
1144 hlist!(field!(is_admin, true), field!(name, "joe"), field!(age, 3))
1145 );
1146 }
1147
1148 #[test]
1149 fn test_transmogrify_identical_transform_labelled_fields() {
1150 type Source = HList![
1151 Field<name, &'static str>,
1152 Field<age, i32>,
1153 Field<is_admin, bool>
1154 ];
1155 type Target = Source;
1156 let source: Source = hlist![field!(name, "joe"), field!(age, 32), field!(is_admin, true)];
1157 let target: Target = source.transmogrify();
1158 assert_eq!(
1159 target,
1160 hlist![field!(name, "joe"), field!(age, 32), field!(is_admin, true)]
1161 )
1162 }
1163
1164 #[test]
1165 fn test_transmogrify_through_containers() {
1166 type SourceOuter<T> = HList![
1167 Field<name, &'static str>,
1168 Field<inner, T>,
1169 ];
1170 type SourceInner = HList![
1171 Field<is_admin, bool>,
1172 Field<age, i32>,
1173 ];
1174 type TargetOuter<T> = HList![
1175 Field<name, &'static str>,
1176 Field<inner, T>,
1177 ];
1178 type TargetInner = HList![
1179 Field<age, i32>,
1180 Field<is_admin, bool>,
1181 ];
1182
1183 fn create_inner() -> (SourceInner, TargetInner) {
1184 let source_inner: SourceInner = hlist![field!(is_admin, true), field!(age, 14)];
1185 let target_inner: TargetInner = hlist![field!(age, 14), field!(is_admin, true)];
1186 (source_inner, target_inner)
1187 }
1188
1189 let (source_inner, target_inner) = create_inner();
1191 let source: SourceOuter<Vec<SourceInner>> =
1192 hlist![field!(name, "Joe"), field!(inner, vec![source_inner])];
1193 let target: TargetOuter<Vec<TargetInner>> = source.transmogrify();
1194 assert_eq!(
1195 target,
1196 hlist![field!(name, "Joe"), field!(inner, vec![target_inner])]
1197 );
1198
1199 let (source_inner, target_inner) = create_inner();
1201 let source_inner = {
1202 let mut list = LinkedList::new();
1203 list.push_front(source_inner);
1204 list
1205 };
1206 let target_inner = {
1207 let mut list = LinkedList::new();
1208 list.push_front(target_inner);
1209 list
1210 };
1211 let source: SourceOuter<LinkedList<SourceInner>> =
1212 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1213 let target: TargetOuter<LinkedList<TargetInner>> = source.transmogrify();
1214 assert_eq!(
1215 target,
1216 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1217 );
1218
1219 let (source_inner, target_inner) = create_inner();
1221 let source_inner = {
1222 let mut list = VecDeque::new();
1223 list.push_front(source_inner);
1224 list
1225 };
1226 let target_inner = {
1227 let mut list = VecDeque::new();
1228 list.push_front(target_inner);
1229 list
1230 };
1231 let source: SourceOuter<VecDeque<SourceInner>> =
1232 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1233 let target: TargetOuter<VecDeque<TargetInner>> = source.transmogrify();
1234 assert_eq!(
1235 target,
1236 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1237 );
1238
1239 let (source_inner, target_inner) = create_inner();
1241 let source_inner = Some(source_inner);
1242 let target_inner = Some(target_inner);
1243 let source: SourceOuter<Option<SourceInner>> =
1244 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1245 let target: TargetOuter<Option<TargetInner>> = source.transmogrify();
1246 assert_eq!(
1247 target,
1248 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1249 );
1250 let source: SourceOuter<Option<SourceInner>> =
1251 hlist![field!(name, "Joe"), field!(inner, None)];
1252 let target: TargetOuter<Option<TargetInner>> = source.transmogrify();
1253 assert_eq!(target, hlist![field!(name, "Joe"), field!(inner, None)]);
1254
1255 let (source_inner, target_inner) = create_inner();
1257 let source_inner = Box::new(source_inner);
1258 let target_inner = Box::new(target_inner);
1259 let source: SourceOuter<Box<SourceInner>> =
1260 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1261 let target: TargetOuter<Box<TargetInner>> = source.transmogrify();
1262 assert_eq!(
1263 target,
1264 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1265 );
1266 }
1267
1268 }