Skip to main content

cgp_field/traits/
transform_map.rs

1use core::marker::PhantomData;
2
3use crate::impls::IsNothing;
4use crate::traits::{HasFields, MapType, PartialData, UpdateField};
5use crate::types::{Cons, Field, Nil};
6
7/// Natural transformation from `M1::Map<T>` to `M2::Map<T>`
8pub trait TransformMap<M1: MapType, M2: MapType, T> {
9    fn transform_mapped(value: M1::Map<T>) -> M2::Map<T>;
10}
11
12pub trait TransformMapFields<Transform, TargetMap> {
13    type Output;
14
15    fn transform_map_fields(self) -> Self::Output;
16}
17
18impl<ContextA, ContextB, Transform, TargetMap, Output> TransformMapFields<Transform, TargetMap>
19    for ContextA
20where
21    ContextA: PartialData<Target = ContextB>,
22    ContextB: HasFields,
23    ContextB::Fields: TransformMapFieldsImpl<ContextA, Transform, TargetMap, Output = Output>,
24{
25    type Output = Output;
26
27    fn transform_map_fields(self) -> Self::Output {
28        ContextB::Fields::transform_map_fields(self)
29    }
30}
31
32trait TransformMapFieldsImpl<Context, Transform, TargetMap> {
33    type Output;
34
35    fn transform_map_fields(context: Context) -> Self::Output;
36}
37
38impl<Context, Transform, TargetMap> TransformMapFieldsImpl<Context, Transform, TargetMap> for Nil {
39    type Output = Context;
40
41    fn transform_map_fields(context: Context) -> Self::Output {
42        context
43    }
44}
45
46impl<Tag, Value, Tail, ContextA, ContextB, ContextC, ContextD, Transform, TargetMap, SourceMap>
47    TransformMapFieldsImpl<ContextA, Transform, TargetMap> for Cons<Field<Tag, Value>, Tail>
48where
49    TargetMap: MapType,
50    SourceMap: MapType,
51    Tail: TransformMapFieldsImpl<ContextA, Transform, TargetMap, Output = ContextB>,
52    ContextB: UpdateField<Tag, IsNothing, Value = Value, Mapper = SourceMap, Output = ContextC>,
53    ContextC: UpdateField<Tag, TargetMap, Value = Value, Output = ContextD>,
54    Transform: TransformMap<SourceMap, TargetMap, Value>,
55{
56    type Output = ContextD;
57
58    fn transform_map_fields(context_a: ContextA) -> Self::Output {
59        let context_b = Tail::transform_map_fields(context_a);
60
61        let (value_a, context_c) = context_b.update_field(PhantomData, ());
62        let value_b = Transform::transform_mapped(value_a);
63        let (_, context_d) = context_c.update_field(PhantomData, value_b);
64
65        context_d
66    }
67}