cgp_field/impls/
cast.rs

1use core::marker::PhantomData;
2
3use crate::{
4    Either, ExtractField, Field, FinalizeExtract, FromVariant, HasExtractor, HasFields, Void,
5};
6
7pub trait CanUpcast<Target> {
8    fn upcast(self, _tag: PhantomData<Target>) -> Target;
9}
10
11pub trait CanDowncast<Target> {
12    type Remainder;
13
14    fn downcast(self, _tag: PhantomData<Target>) -> Result<Target, Self::Remainder>;
15}
16
17pub trait CanDowncastFields<Target> {
18    type Remainder;
19
20    fn downcast_fields(self, _tag: PhantomData<Target>) -> Result<Target, Self::Remainder>;
21}
22
23impl<Context, Source, Target, Remainder> CanUpcast<Target> for Context
24where
25    Context: HasFields + HasExtractor<Extractor = Source>,
26    Context::Fields: FieldsExtractor<Source, Target, Remainder = Remainder>,
27    Remainder: FinalizeExtract,
28{
29    fn upcast(self, _tag: PhantomData<Target>) -> Target {
30        match Context::Fields::extract_from(self.to_extractor()) {
31            Ok(target) => target,
32            Err(remainder) => remainder.finalize_extract(),
33        }
34    }
35}
36
37impl<Context, Source, Target, Remainder> CanDowncast<Target> for Context
38where
39    Context: HasExtractor<Extractor = Source>,
40    Target: HasFields,
41    Target::Fields: FieldsExtractor<Source, Target, Remainder = Remainder>,
42{
43    type Remainder = Remainder;
44
45    fn downcast(self, _tag: PhantomData<Target>) -> Result<Target, Self::Remainder> {
46        Target::Fields::extract_from(self.to_extractor())
47    }
48}
49
50impl<Source, Target, Remainder> CanDowncastFields<Target> for Source
51where
52    Target: HasFields,
53    Target::Fields: FieldsExtractor<Source, Target, Remainder = Remainder>,
54{
55    type Remainder = Remainder;
56
57    fn downcast_fields(self, _tag: PhantomData<Target>) -> Result<Target, Self::Remainder> {
58        Target::Fields::extract_from(self)
59    }
60}
61
62pub trait FieldsExtractor<Source, Target> {
63    type Remainder;
64
65    fn extract_from(source: Source) -> Result<Target, Self::Remainder>;
66}
67
68impl<Source, Target, Tag, Value, RestFields, Remainder> FieldsExtractor<Source, Target>
69    for Either<Field<Tag, Value>, RestFields>
70where
71    Source: ExtractField<Tag, Value = Value>,
72    Target: FromVariant<Tag, Value = Value>,
73    RestFields: FieldsExtractor<Source::Remainder, Target, Remainder = Remainder>,
74{
75    type Remainder = Remainder;
76
77    fn extract_from(source: Source) -> Result<Target, Remainder> {
78        match source.extract_field(PhantomData) {
79            Ok(field) => Ok(Target::from_variant(PhantomData, field)),
80            Err(remainder) => RestFields::extract_from(remainder),
81        }
82    }
83}
84
85impl<Source, Target> FieldsExtractor<Source, Target> for Void {
86    type Remainder = Source;
87
88    fn extract_from(source: Source) -> Result<Target, Source> {
89        Err(source)
90    }
91}