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}