1use crate::coproduct::Coproduct;
151use crate::hlist::*;
152use crate::indices::*;
153use crate::traits::ToRef;
154use chars::*;
155#[cfg(feature = "serde")]
156use serde::{Deserialize, Serialize};
157
158use core::fmt;
159use core::marker::PhantomData;
160
161#[diagnostic::on_unimplemented(
201 message = "Cannot derive labelled generic representation for `{Self}`",
202 label = "LabelledGeneric not implemented",
203 note = "The type must have a LabelledGeneric instance to be used with transform_from or transmogrify.",
204 note = "Derive LabelledGeneric using #[derive(LabelledGeneric)] on your struct or enum."
205)]
206pub trait LabelledGeneric {
207 type Repr;
209
210 fn into(self) -> Self::Repr;
212
213 fn from(repr: Self::Repr) -> Self;
216
217 #[inline(always)]
220 fn convert_from<Src>(src: Src) -> Self
221 where
222 Src: LabelledGeneric<Repr = Self::Repr>,
223 Self: Sized,
224 {
225 let repr = <Src as LabelledGeneric>::into(src);
226 <Self as LabelledGeneric>::from(repr)
227 }
228
229 #[deprecated(note = "obsolete, transform_from instead")]
235 fn sculpted_convert_from<A, Indices>(a: A) -> Self
236 where
237 A: LabelledGeneric,
238 Self: Sized,
239 <A as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices>,
241 {
242 <Self as LabelledGeneric>::transform_from(a)
243 }
244
245 #[inline(always)]
253 fn transform_from<Src, Indices>(src: Src) -> Self
254 where
255 Src: LabelledGeneric,
256 Self: Sized,
257 <Src as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices>,
259 {
260 let src_gen = <Src as LabelledGeneric>::into(src);
261 let (self_gen, _): (<Self as LabelledGeneric>::Repr, _) = src_gen.sculpt();
263 <Self as LabelledGeneric>::from(self_gen)
264 }
265}
266
267pub trait IntoLabelledGeneric {
268 type Repr;
270
271 fn into(self) -> Self::Repr;
273}
274
275impl<A> IntoLabelledGeneric for A
276where
277 A: LabelledGeneric,
278{
279 type Repr = <A as LabelledGeneric>::Repr;
280
281 #[inline(always)]
282 fn into(self) -> <Self as IntoLabelledGeneric>::Repr {
283 self.into()
284 }
285}
286
287type NoneLabel = (N, o, n, e);
288type SomeLabel = (S, o, m, e);
289type OkLabel = (O, k);
290type ErrLabel = (E, r, r);
291type FalseLabel = (f, a, l, s, e);
292type TrueLabel = (t, r, u, e);
293type TupleField0 = (__, _0);
294type UnitVariant<Name> = Field<Name, HNil>;
295type UnaryTupleVariant<Name, T> = Field<Name, crate::HList!(Field<TupleField0, T>)>;
296type LabelledOptionRepr<T> =
297 crate::Coprod!(UnitVariant<NoneLabel>, UnaryTupleVariant<SomeLabel, T>);
298type LabelledResultRepr<T, E> =
299 crate::Coprod!(UnaryTupleVariant<OkLabel, T>, UnaryTupleVariant<ErrLabel, E>);
300type LabelledBoolRepr = crate::Coprod!(UnitVariant<FalseLabel>, UnitVariant<TrueLabel>);
301
302#[inline(always)]
303fn labelled_tuple_field_0<T>(value: T) -> Field<TupleField0, T> {
304 crate::field!(TupleField0, value, "_0")
305}
306
307#[inline(always)]
308fn labelled_unit_variant<Name>(name: &'static str) -> UnitVariant<Name> {
309 crate::field!(Name, crate::hlist![], name)
310}
311
312#[inline(always)]
313fn labelled_unary_tuple_variant<Name, T>(
314 name: &'static str,
315 value: T,
316) -> UnaryTupleVariant<Name, T> {
317 crate::field!(Name, crate::hlist![labelled_tuple_field_0(value)], name)
318}
319
320impl<T> LabelledGeneric for Option<T> {
321 type Repr = LabelledOptionRepr<T>;
322
323 #[inline(always)]
324 fn into(self) -> Self::Repr {
325 match self {
326 None => Coproduct::Inl(labelled_unit_variant::<NoneLabel>("None")),
327 Some(value) => Coproduct::Inr(Coproduct::Inl(labelled_unary_tuple_variant::<
328 SomeLabel,
329 _,
330 >("Some", value))),
331 }
332 }
333
334 #[inline(always)]
335 fn from(repr: Self::Repr) -> Self {
336 match repr {
337 Coproduct::Inl(Field {
338 value: crate::hlist_pat![],
339 ..
340 }) => None,
341 Coproduct::Inr(Coproduct::Inl(Field {
342 value: crate::hlist_pat![Field { value, .. }],
343 ..
344 })) => Some(value),
345 Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
346 }
347 }
348}
349
350impl<T, E> LabelledGeneric for Result<T, E> {
351 type Repr = LabelledResultRepr<T, E>;
352
353 #[inline(always)]
354 fn into(self) -> Self::Repr {
355 match self {
356 Ok(value) => Coproduct::Inl(labelled_unary_tuple_variant::<OkLabel, _>("Ok", value)),
357 Err(value) => Coproduct::Inr(Coproduct::Inl(
358 labelled_unary_tuple_variant::<ErrLabel, _>("Err", value),
359 )),
360 }
361 }
362
363 #[inline(always)]
364 fn from(repr: Self::Repr) -> Self {
365 match repr {
366 Coproduct::Inl(Field {
367 value: crate::hlist_pat![Field { value, .. }],
368 ..
369 }) => Ok(value),
370 Coproduct::Inr(Coproduct::Inl(Field {
371 value: crate::hlist_pat![Field { value, .. }],
372 ..
373 })) => Err(value),
374 Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
375 }
376 }
377}
378
379impl LabelledGeneric for bool {
380 type Repr = LabelledBoolRepr;
381
382 #[inline(always)]
383 fn into(self) -> Self::Repr {
384 match self {
385 false => Coproduct::Inl(labelled_unit_variant::<FalseLabel>("false")),
386 true => Coproduct::Inr(Coproduct::Inl(labelled_unit_variant::<TrueLabel>("true"))),
387 }
388 }
389
390 #[inline(always)]
391 fn from(repr: Self::Repr) -> Self {
392 match repr {
393 Coproduct::Inl(Field {
394 value: crate::hlist_pat![],
395 ..
396 }) => false,
397 Coproduct::Inr(Coproduct::Inl(Field {
398 value: crate::hlist_pat![],
399 ..
400 })) => true,
401 Coproduct::Inr(Coproduct::Inr(cnil)) => match cnil {},
402 }
403 }
404}
405
406pub fn from_labelled_generic<Dst, Repr>(repr: Repr) -> Dst
408where
409 Dst: LabelledGeneric<Repr = Repr>,
410{
411 <Dst as LabelledGeneric>::from(repr)
412}
413
414pub fn into_labelled_generic<Src, Repr>(src: Src) -> Repr
416where
417 Src: LabelledGeneric<Repr = Repr>,
418{
419 <Src as LabelledGeneric>::into(src)
420}
421
422pub fn labelled_convert_from<Src, Dst, Repr>(src: Src) -> Dst
425where
426 Src: LabelledGeneric<Repr = Repr>,
427 Dst: LabelledGeneric<Repr = Repr>,
428{
429 <Dst as LabelledGeneric>::convert_from(src)
430}
431
432#[deprecated(note = "obsolete, transform_from instead")]
438pub fn sculpted_convert_from<A, B, Indices>(a: A) -> B
439where
440 A: LabelledGeneric,
441 B: LabelledGeneric,
442 <A as LabelledGeneric>::Repr: Sculptor<<B as LabelledGeneric>::Repr, Indices>,
444{
445 <B as LabelledGeneric>::transform_from(a)
446}
447pub fn transform_from<Src, Dst, Indices>(src: Src) -> Dst
453where
454 Src: LabelledGeneric,
455 Dst: LabelledGeneric,
456 <Src as LabelledGeneric>::Repr: Sculptor<<Dst as LabelledGeneric>::Repr, Indices>,
458{
459 <Dst as LabelledGeneric>::transform_from(src)
460}
461
462pub mod chars {
463 macro_rules! create_enums_for {
476 ($($i: ident)*) => {
477 $(
478 #[allow(non_snake_case, non_camel_case_types)]
479 #[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
480 pub enum $i {}
481 )*
482 }
483 }
484
485 create_enums_for! {
487 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
489 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
490 _1 _2 _3 _4 _5 _6 _7 _8 _9 _0 __ _uc uc_
491 }
492
493 #[test]
494 fn simple_var_names_are_allowed() {
495 let a = 3;
500 #[allow(clippy::match_single_binding)]
501 match a {
502 a => assert_eq!(a, 3),
503 }
504 }
505}
506
507#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
524#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
525pub struct Field<Name, Type> {
526 name_type_holder: PhantomData<Name>,
527 pub name: &'static str,
528 pub value: Type,
529}
530
531#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
534#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
535pub struct ValueField<Type> {
536 pub name: &'static str,
537 pub value: Type,
538}
539
540impl<Name, Type> fmt::Debug for Field<Name, Type>
541where
542 Type: fmt::Debug,
543{
544 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545 f.debug_struct("Field")
546 .field("name", &DebugAsDisplay(&self.name))
548 .field("value", &self.value)
549 .finish()
550 }
551}
552
553impl<Type> fmt::Debug for ValueField<Type>
554where
555 Type: fmt::Debug,
556{
557 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558 f.debug_struct("ValueField")
559 .field("name", &DebugAsDisplay(&self.name))
561 .field("value", &self.value)
562 .finish()
563 }
564}
565
566struct DebugAsDisplay<T>(T);
568
569impl<T: fmt::Display> fmt::Debug for DebugAsDisplay<T> {
570 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571 fmt::Display::fmt(&self.0, f)
572 }
573}
574
575pub fn field_with_name<Label, Value>(name: &'static str, value: Value) -> Field<Label, Value> {
591 Field {
592 name_type_holder: PhantomData,
593 name,
594 value,
595 }
596}
597
598pub trait IntoUnlabelled {
600 type Output;
601
602 fn into_unlabelled(self) -> Self::Output;
625}
626
627impl IntoUnlabelled for HNil {
629 type Output = HNil;
630 fn into_unlabelled(self) -> Self::Output {
631 self
632 }
633}
634
635impl<Label, Value, Tail> IntoUnlabelled for HCons<Field<Label, Value>, Tail>
637where
638 Tail: IntoUnlabelled,
639{
640 type Output = HCons<Value, <Tail as IntoUnlabelled>::Output>;
641
642 fn into_unlabelled(self) -> Self::Output {
643 HCons {
644 head: self.head.value,
645 tail: self.tail.into_unlabelled(),
646 }
647 }
648}
649
650pub trait IntoValueLabelled {
652 type Output;
653
654 fn into_value_labelled(self) -> Self::Output;
689}
690
691impl IntoValueLabelled for HNil {
692 type Output = HNil;
693 fn into_value_labelled(self) -> Self::Output {
694 self
695 }
696}
697
698impl<Label, Value, Tail> IntoValueLabelled for HCons<Field<Label, Value>, Tail>
699where
700 Tail: IntoValueLabelled,
701{
702 type Output = HCons<ValueField<Value>, <Tail as IntoValueLabelled>::Output>;
703
704 fn into_value_labelled(self) -> Self::Output {
705 HCons {
706 head: ValueField {
707 name: self.head.name,
708 value: self.head.value,
709 },
710 tail: self.tail.into_value_labelled(),
711 }
712 }
713}
714
715#[diagnostic::on_unimplemented(
717 message = "Cannot find field with key `{TargetKey}` in `{Self}`",
718 label = "Field not found",
719 note = "The source type does not contain a field with the target key.",
720 note = "Make sure the field name exists in the source struct and matches exactly."
721)]
722pub trait ByNameFieldPlucker<TargetKey, Index> {
723 type TargetValue;
724 type Remainder;
725
726 fn pluck_by_name(self) -> (Field<TargetKey, Self::TargetValue>, Self::Remainder);
728}
729
730impl<K, V, Tail> ByNameFieldPlucker<K, Here> for HCons<Field<K, V>, Tail> {
732 type TargetValue = V;
733 type Remainder = Tail;
734
735 #[inline(always)]
736 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
737 let field = field_with_name(self.head.name, self.head.value);
738 (field, self.tail)
739 }
740}
741
742impl<Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for HCons<Head, Tail>
744where
745 Tail: ByNameFieldPlucker<K, TailIndex>,
746{
747 type TargetValue = <Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue;
748 type Remainder = HCons<Head, <Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>;
749
750 #[inline(always)]
751 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
752 let (target, tail_remainder) =
753 <Tail as ByNameFieldPlucker<K, TailIndex>>::pluck_by_name(self.tail);
754 (
755 target,
756 HCons {
757 head: self.head,
758 tail: tail_remainder,
759 },
760 )
761 }
762}
763
764impl<'a, K, V, Tail: ToRef<'a>> ByNameFieldPlucker<K, Here> for &'a HCons<Field<K, V>, Tail> {
766 type TargetValue = &'a V;
767 type Remainder = <Tail as ToRef<'a>>::Output;
768
769 #[inline(always)]
770 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
771 let field = field_with_name(self.head.name, &self.head.value);
772 (field, self.tail.to_ref())
773 }
774}
775
776impl<'a, Head, Tail, K, TailIndex> ByNameFieldPlucker<K, There<TailIndex>> for &'a HCons<Head, Tail>
778where
779 &'a Tail: ByNameFieldPlucker<K, TailIndex>,
780{
781 type TargetValue = <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::TargetValue;
782 type Remainder = HCons<&'a Head, <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::Remainder>;
783
784 #[inline(always)]
785 fn pluck_by_name(self) -> (Field<K, Self::TargetValue>, Self::Remainder) {
786 let (target, tail_remainder) =
787 <&'a Tail as ByNameFieldPlucker<K, TailIndex>>::pluck_by_name(&self.tail);
788 (
789 target,
790 HCons {
791 head: &self.head,
792 tail: tail_remainder,
793 },
794 )
795 }
796}
797
798#[diagnostic::on_unimplemented(
889 message = "Cannot transmogrify `{Self}` into `{Target}`",
890 label = "Cannot convert this type into the target type",
891 note = "Transmogrify requires that the source and target types have compatible structures.",
892 note = "The source type must have all the fields needed for the target type, possibly in a different order or nested structure.",
893 note = "Check that field names match and types are compatible between the source and target."
894)]
895pub trait Transmogrifier<Target, TransmogrifyIndexIndices> {
896 fn transmogrify(self) -> Target;
900}
901
902impl<Key, SourceValue> Transmogrifier<SourceValue, IdentityTransMog> for Field<Key, SourceValue> {
904 #[inline(always)]
905 fn transmogrify(self) -> SourceValue {
906 self.value
907 }
908}
909
910#[cfg(feature = "alloc")]
912mod _alloc {
913 use super::MappingIndicesWrapper;
914 use super::{Field, Transmogrifier};
915 use alloc::boxed::Box;
916 use alloc::collections::{LinkedList, VecDeque};
917 use alloc::vec::Vec;
918
919 macro_rules! transmogrify_seq {
920 ($container:ident) => {
921 impl<Key, Source, Target, InnerIndices>
924 Transmogrifier<$container<Target>, MappingIndicesWrapper<InnerIndices>>
925 for Field<Key, $container<Source>>
926 where
927 Source: Transmogrifier<Target, InnerIndices>,
928 {
929 fn transmogrify(self) -> $container<Target> {
930 self.value.into_iter().map(|e| e.transmogrify()).collect()
931 }
932 }
933 };
934 }
935
936 transmogrify_seq!(Vec);
937 transmogrify_seq!(LinkedList);
938 transmogrify_seq!(VecDeque);
939
940 impl<Key, Source, Target, InnerIndices>
943 Transmogrifier<Box<Target>, MappingIndicesWrapper<InnerIndices>> for Field<Key, Box<Source>>
944 where
945 Source: Transmogrifier<Target, InnerIndices>,
946 {
947 fn transmogrify(self) -> Box<Target> {
948 Box::new(self.value.transmogrify())
949 }
950 }
951}
952
953impl<Key, Source, Target, InnerIndices>
956 Transmogrifier<Option<Target>, MappingIndicesWrapper<InnerIndices>>
957 for Field<Key, Option<Source>>
958where
959 Source: Transmogrifier<Target, InnerIndices>,
960{
961 fn transmogrify(self) -> Option<Target> {
962 self.value.map(|e| e.transmogrify())
963 }
964}
965
966impl Transmogrifier<HNil, HNil> for HNil {
968 #[inline(always)]
969 fn transmogrify(self) -> HNil {
970 HNil
971 }
972}
973
974impl<SourceHead, SourceTail> Transmogrifier<HNil, HNil> for HCons<SourceHead, SourceTail> {
976 #[inline(always)]
977 fn transmogrify(self) -> HNil {
978 HNil
979 }
980}
981
982impl<
985 SourceHead,
986 SourceTail,
987 TargetName,
988 TargetHead,
989 TargetTail,
990 TransmogHeadIndex,
991 TransmogTailIndices,
992 > Transmogrifier<HCons<TargetHead, TargetTail>, HCons<TransmogHeadIndex, TransmogTailIndices>>
993 for Field<TargetName, HCons<SourceHead, SourceTail>>
994where
995 HCons<SourceHead, SourceTail>: Transmogrifier<
996 HCons<TargetHead, TargetTail>,
997 HCons<TransmogHeadIndex, TransmogTailIndices>,
998 >,
999{
1000 #[inline(always)]
1001 fn transmogrify(self) -> HCons<TargetHead, TargetTail> {
1002 self.value.transmogrify()
1003 }
1004}
1005
1006impl<
1010 SourceHead,
1011 SourceTail,
1012 TargetHeadName,
1013 TargetHeadValue,
1014 TargetTail,
1015 PluckSourceHeadNameIndex,
1016 TransMogSourceHeadValueIndices,
1017 TransMogTailIndices,
1018 >
1019 Transmogrifier<
1020 HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail>,
1021 HCons<
1022 DoTransmog<PluckSourceHeadNameIndex, TransMogSourceHeadValueIndices>,
1023 TransMogTailIndices,
1024 >,
1025 > for HCons<SourceHead, SourceTail>
1026where
1027 HCons<SourceHead, SourceTail>: ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>,
1029 Field<
1031 TargetHeadName,
1032 <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
1033 TargetHeadName,
1034 PluckSourceHeadNameIndex,
1035 >>::TargetValue,
1036 >: Transmogrifier<TargetHeadValue, TransMogSourceHeadValueIndices>,
1037 <HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
1040 TargetHeadName,
1041 PluckSourceHeadNameIndex,
1042 >>::Remainder: Transmogrifier<TargetTail, TransMogTailIndices>,
1043{
1044 #[inline(always)]
1045 fn transmogrify(self) -> HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail> {
1046 let (source_field_for_head_target_name, remainder) = self.pluck_by_name();
1047 let name = source_field_for_head_target_name.name;
1048 let transmogrified_value: TargetHeadValue =
1049 source_field_for_head_target_name.transmogrify();
1050 let as_field: Field<TargetHeadName, TargetHeadValue> =
1051 field_with_name(name, transmogrified_value);
1052 HCons {
1053 head: as_field,
1054 tail: remainder.transmogrify(),
1055 }
1056 }
1057}
1058
1059impl<Source, Target, TransmogIndices>
1060 Transmogrifier<Target, LabelledGenericTransmogIndicesWrapper<TransmogIndices>> for Source
1061where
1062 Source: LabelledGeneric,
1063 Target: LabelledGeneric,
1064 <Source as LabelledGeneric>::Repr:
1065 Transmogrifier<<Target as LabelledGeneric>::Repr, TransmogIndices>,
1066{
1067 #[inline(always)]
1068 fn transmogrify(self) -> Target {
1069 let source_as_repr = self.into();
1070 let source_transmogged = source_as_repr.transmogrify();
1071 <Target as LabelledGeneric>::from(source_transmogged)
1072 }
1073}
1074
1075impl<Source, TargetName, TargetValue, TransmogIndices>
1077 Transmogrifier<TargetValue, PluckedLabelledGenericIndicesWrapper<TransmogIndices>>
1078 for Field<TargetName, Source>
1079where
1080 Source: LabelledGeneric,
1081 TargetValue: LabelledGeneric,
1082 Source: Transmogrifier<TargetValue, TransmogIndices>,
1083{
1084 #[inline(always)]
1085 fn transmogrify(self) -> TargetValue {
1086 self.value.transmogrify()
1087 }
1088}
1089
1090#[cfg(test)]
1091mod tests {
1092 use super::*;
1093 use alloc::collections::{LinkedList, VecDeque};
1094 use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
1095
1096 #[allow(non_camel_case_types)]
1098 type abc = (a, b, c);
1099 #[allow(non_camel_case_types)]
1100 type name = (n, a, m, e);
1101 #[allow(non_camel_case_types)]
1102 type age = (a, g, e);
1103 #[allow(non_camel_case_types)]
1104 type is_admin = (i, s, __, a, d, m, i, n);
1105 #[allow(non_camel_case_types)]
1106 type inner = (i, n, n, e, r);
1107
1108 #[test]
1109 fn test_label_new_building() {
1110 let l1 = field!(abc, 3);
1111 assert_eq!(l1.value, 3);
1112 assert_eq!(l1.name, "abc");
1113 let l2 = field!((a, b, c), 3);
1114 assert_eq!(l2.value, 3);
1115 assert_eq!(l2.name, "abc");
1116
1117 let l3 = field!(abc, 3, "nope");
1119 assert_eq!(l3.value, 3);
1120 assert_eq!(l3.name, "nope");
1121 let l4 = field!((a, b, c), 3, "nope");
1122 assert_eq!(l4.value, 3);
1123 assert_eq!(l4.name, "nope");
1124 }
1125
1126 #[test]
1127 fn test_field_construction() {
1128 let f1 = field!(age, 3);
1129 let f2 = field!((a, g, e), 3);
1130 assert_eq!(f1, f2)
1131 }
1132
1133 #[test]
1134 fn test_field_debug() {
1135 let field = field!(age, 3);
1136 let hlist_pat![value_field] = hlist![field].into_value_labelled();
1137
1138 assert!(format!("{:?}", field).contains("name: age"));
1140 assert!(format!("{:?}", value_field).contains("name: age"));
1141 assert!(format!("{:#?}", field).contains('\n'));
1143 assert!(format!("{:#?}", value_field).contains('\n'));
1144 }
1145
1146 #[test]
1147 fn test_anonymous_record_usage() {
1148 let record = hlist![field!(name, "Joe"), field!((a, g, e), 30)];
1149 let (name, _): (Field<name, _>, _) = record.pluck();
1150 assert_eq!(name.value, "Joe")
1151 }
1152
1153 #[test]
1154 fn test_pluck_by_name() {
1155 let record = hlist![
1156 field!(is_admin, true),
1157 field!(name, "Joe".to_string()),
1158 field!((a, g, e), 30),
1159 ];
1160
1161 let (name, r): (Field<name, _>, _) = record.clone().pluck_by_name();
1162 assert_eq!(name.value, "Joe");
1163 assert_eq!(r, hlist![field!(is_admin, true), field!((a, g, e), 30),]);
1164 }
1165
1166 #[test]
1167 fn test_ref_pluck_by_name() {
1168 let record = &hlist![
1169 field!(is_admin, true),
1170 field!(name, "Joe".to_string()),
1171 field!((a, g, e), 30),
1172 ];
1173
1174 let (name, r): (Field<name, _>, _) = record.pluck_by_name();
1175 assert_eq!(name.value, "Joe");
1176 assert_eq!(r, hlist![&field!(is_admin, true), &field!((a, g, e), 30),]);
1177 }
1178
1179 #[test]
1180 fn test_unlabelling() {
1181 let labelled_hlist = hlist![field!(name, "joe"), field!((a, g, e), 3)];
1182 let unlabelled = labelled_hlist.into_unlabelled();
1183 assert_eq!(unlabelled, hlist!["joe", 3])
1184 }
1185
1186 #[test]
1187 fn test_value_labelling() {
1188 let labelled_hlist = hlist![field!(name, "joe"), field!((a, g, e), 3)];
1189 let value_labelled: HList![ValueField<&str>, ValueField<isize>] =
1190 labelled_hlist.into_value_labelled();
1191 let hlist_pat!(f1, f2) = value_labelled;
1192 assert_eq!(f1.name, "name");
1193 assert_eq!(f2.name, "age");
1194 }
1195
1196 #[test]
1197 fn test_name() {
1198 let labelled = field!(name, "joe");
1199 assert_eq!(labelled.name, "name")
1200 }
1201
1202 #[test]
1203 fn test_transmogrify_hnil_identity() {
1204 let hnil_again: HNil = HNil.transmogrify();
1205 assert_eq!(HNil, hnil_again);
1206 }
1207
1208 #[test]
1209 fn test_transmogrify_hcons_sculpting_super_simple() {
1210 type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1211 type Target = HList![Field<age, i32>];
1212 let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1213 let t_hcons: Target = hcons.transmogrify();
1214 assert_eq!(t_hcons, hlist!(field!(age, 3)));
1215 }
1216
1217 #[test]
1218 fn test_transmogrify_hcons_sculpting_somewhat_simple() {
1219 type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1220 type Target = HList![Field<is_admin, bool>, Field<name, &'static str>];
1221 let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1222 let t_hcons: Target = hcons.transmogrify();
1223 assert_eq!(t_hcons, hlist!(field!(is_admin, true), field!(name, "joe")));
1224 }
1225
1226 #[test]
1227 fn test_transmogrify_hcons_recursive_simple() {
1228 type Source = HList![
1229 Field<name, HList![
1230 Field<inner, f32>,
1231 Field<is_admin, bool>,
1232 ]>,
1233 Field<age, i32>,
1234 Field<is_admin, bool>];
1235 type Target = HList![
1236 Field<is_admin, bool>,
1237 Field<name, HList![
1238 Field<is_admin, bool>,
1239 ]>,
1240 ];
1241 let source: Source = hlist![
1242 field!(name, hlist![field!(inner, 42f32), field!(is_admin, true)]),
1243 field!(age, 32),
1244 field!(is_admin, true)
1245 ];
1246 let target: Target = source.transmogrify();
1247 assert_eq!(
1248 target,
1249 hlist![
1250 field!(is_admin, true),
1251 field!(name, hlist![field!(is_admin, true)]),
1252 ]
1253 )
1254 }
1255
1256 #[test]
1257 fn test_transmogrify_hcons_sculpting_required_simple() {
1258 type Source = HList![Field<name, &'static str>, Field<age, i32>, Field<is_admin, bool>];
1259 type Target = HList![Field<is_admin, bool>, Field<name, &'static str>, Field<age, i32>];
1260 let hcons: Source = hlist!(field!(name, "joe"), field!(age, 3), field!(is_admin, true));
1261 let t_hcons: Target = hcons.transmogrify();
1262 assert_eq!(
1263 t_hcons,
1264 hlist!(field!(is_admin, true), field!(name, "joe"), field!(age, 3))
1265 );
1266 }
1267
1268 #[test]
1269 fn test_transmogrify_identical_transform_labelled_fields() {
1270 type Source = HList![
1271 Field<name, &'static str>,
1272 Field<age, i32>,
1273 Field<is_admin, bool>
1274 ];
1275 type Target = Source;
1276 let source: Source = hlist![field!(name, "joe"), field!(age, 32), field!(is_admin, true)];
1277 let target: Target = source.transmogrify();
1278 assert_eq!(
1279 target,
1280 hlist![field!(name, "joe"), field!(age, 32), field!(is_admin, true)]
1281 )
1282 }
1283
1284 #[test]
1285 fn test_transmogrify_through_containers() {
1286 type SourceOuter<T> = HList![
1287 Field<name, &'static str>,
1288 Field<inner, T>,
1289 ];
1290 type SourceInner = HList![
1291 Field<is_admin, bool>,
1292 Field<age, i32>,
1293 ];
1294 type TargetOuter<T> = HList![
1295 Field<name, &'static str>,
1296 Field<inner, T>,
1297 ];
1298 type TargetInner = HList![
1299 Field<age, i32>,
1300 Field<is_admin, bool>,
1301 ];
1302
1303 fn create_inner() -> (SourceInner, TargetInner) {
1304 let source_inner: SourceInner = hlist![field!(is_admin, true), field!(age, 14)];
1305 let target_inner: TargetInner = hlist![field!(age, 14), field!(is_admin, true)];
1306 (source_inner, target_inner)
1307 }
1308
1309 let (source_inner, target_inner) = create_inner();
1311 let source: SourceOuter<Vec<SourceInner>> =
1312 hlist![field!(name, "Joe"), field!(inner, vec![source_inner])];
1313 let target: TargetOuter<Vec<TargetInner>> = source.transmogrify();
1314 assert_eq!(
1315 target,
1316 hlist![field!(name, "Joe"), field!(inner, vec![target_inner])]
1317 );
1318
1319 let (source_inner, target_inner) = create_inner();
1321 let source_inner = {
1322 let mut list = LinkedList::new();
1323 list.push_front(source_inner);
1324 list
1325 };
1326 let target_inner = {
1327 let mut list = LinkedList::new();
1328 list.push_front(target_inner);
1329 list
1330 };
1331 let source: SourceOuter<LinkedList<SourceInner>> =
1332 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1333 let target: TargetOuter<LinkedList<TargetInner>> = source.transmogrify();
1334 assert_eq!(
1335 target,
1336 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1337 );
1338
1339 let (source_inner, target_inner) = create_inner();
1341 let source_inner = {
1342 let mut list = VecDeque::new();
1343 list.push_front(source_inner);
1344 list
1345 };
1346 let target_inner = {
1347 let mut list = VecDeque::new();
1348 list.push_front(target_inner);
1349 list
1350 };
1351 let source: SourceOuter<VecDeque<SourceInner>> =
1352 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1353 let target: TargetOuter<VecDeque<TargetInner>> = source.transmogrify();
1354 assert_eq!(
1355 target,
1356 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1357 );
1358
1359 let (source_inner, target_inner) = create_inner();
1361 let source_inner = Some(source_inner);
1362 let target_inner = Some(target_inner);
1363 let source: SourceOuter<Option<SourceInner>> =
1364 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1365 let target: TargetOuter<Option<TargetInner>> = source.transmogrify();
1366 assert_eq!(
1367 target,
1368 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1369 );
1370 let source: SourceOuter<Option<SourceInner>> =
1371 hlist![field!(name, "Joe"), field!(inner, None)];
1372 let target: TargetOuter<Option<TargetInner>> = source.transmogrify();
1373 assert_eq!(target, hlist![field!(name, "Joe"), field!(inner, None)]);
1374
1375 let (source_inner, target_inner) = create_inner();
1377 let source_inner = Box::new(source_inner);
1378 let target_inner = Box::new(target_inner);
1379 let source: SourceOuter<Box<SourceInner>> =
1380 hlist![field!(name, "Joe"), field!(inner, source_inner)];
1381 let target: TargetOuter<Box<TargetInner>> = source.transmogrify();
1382 assert_eq!(
1383 target,
1384 hlist![field!(name, "Joe"), field!(inner, target_inner)]
1385 );
1386 }
1387
1388 }