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}