cgp_field/impls/
cast.rs

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