agnes/
partial.rs

1/*!
2Framework for partial function handling (where some functionality is implemented for some but not
3all of the data types of fields in a data structure).
4
5A specific piece of partially-implemented functionality consists of a [Func](trait.Func.html)
6implementation for all data types where the functionality exists, a
7[FuncDefault](trait.FuncDefault.html) implementation for data types where the functionality doesn't
8exist, and [IsImplemented](trait.IsImplemented.html) specification for all data types denoting
9whether to use the available `Func` or the fall-back `FuncDefault`.
10
11This module should be unnecessary once
12[trait specialization](https://github.com/rust-lang/rust/issues/31844) is finalized.
13*/
14use std::marker::PhantomData;
15
16use access::DataIndex;
17use cons::*;
18use fieldlist::*;
19use label::{LVCons, SelfValued, TypedValue, Valued};
20use view::{AssocDataIndexConsOf, DataIndexCons};
21
22/// Marker struct denoting that a [Func](trait.Func.html) is implemented for a particular data type.
23#[derive(Debug, Clone)]
24pub struct Implemented;
25/// Marker struct denoting that a [Func](trait.Func.html) is not implemented for a particular data
26/// type.
27#[derive(Debug, Clone)]
28pub struct Unimplemented;
29
30/// Marker struct for combination of a data type, [Func](trait.Func.html), and whether or not that
31/// combination has an implementation.
32#[derive(Debug, Clone)]
33pub struct Capabilities<DType, Fun, IsImpl> {
34    _marker: PhantomData<(DType, Fun, IsImpl)>,
35}
36
37/// Structure tracking a field (as accessed through a type that implements
38/// [DataIndex](../access/trait.DataIndex.html)) along with its
39/// [Capabilities](struct.Capabilities.html) details.
40#[derive(Debug, Clone)]
41pub struct StorageCapabilities<DType, DI, Fun, IsImpl>
42where
43    DI: DataIndex<DType = DType>,
44{
45    _marker: PhantomData<Capabilities<DType, Fun, IsImpl>>,
46    data: DI,
47}
48impl<'a, DType, DI, Fun, IsImpl> SelfValued for StorageCapabilities<DType, DI, Fun, IsImpl> where
49    DI: DataIndex<DType = DType>
50{
51}
52
53/// A cons-list of [StorageCapabilities](struct.StorageCapabilities.html) structs.
54pub type StorageCapabilitiesCons<Label, DType, DI, Fun, IsImpl, Tail> =
55    LVCons<Label, StorageCapabilities<DType, DI, Fun, IsImpl>, Tail>;
56
57/// Trait denoting whether a particular [Func](trait.Func.html) is implemented for a data type.
58pub trait IsImplemented<Fun> {
59    /// Marker trait (either [Implemented](struct.Implemented.html) or
60    /// [Unimplemented](struct.Unimplemented.html)) specifying the implementation status for this
61    /// function / data type combination.
62    type IsImpl;
63}
64
65/// Trait for applying a partially-implemented function [Func](trait.Func.html) to a cons-list.
66pub trait PartialMap<F> {
67    /// The output of the function, constructed into a cons-list of function results.
68    type Output;
69    /// Apply the function `F` to the value in this element of a cons-list, and recurse.
70    fn map(&self, f: &mut F) -> Self::Output;
71}
72impl<'a, F> PartialMap<F> for Nil {
73    type Output = Nil;
74    fn map(&self, _f: &mut F) -> Nil {
75        Nil
76    }
77}
78impl<'a, Label, DType, DI, Fun, Tail, F> PartialMap<F>
79    for StorageCapabilitiesCons<Label, DType, DI, Fun, Implemented, Tail>
80where
81    Tail: PartialMap<F>,
82    F: Func<DType>,
83    DI: DataIndex<DType = DType>,
84{
85    type Output = FieldPayloadCons<Label, DType, F::Output, Tail::Output>;
86
87    fn map(&self, f: &mut F) -> Self::Output {
88        FieldPayloadCons {
89            head: TypedValue::from(f.call(&self.head.value_ref().data)).into(),
90            tail: self.tail.map(f),
91        }
92    }
93}
94impl<'a, Label, DType, DI, Fun, Tail, F> PartialMap<F>
95    for StorageCapabilitiesCons<Label, DType, DI, Fun, Unimplemented, Tail>
96where
97    Tail: PartialMap<F>,
98    DI: DataIndex<DType = DType>,
99    F: FuncDefault,
100{
101    type Output = FieldPayloadCons<Label, DType, F::Output, Tail::Output>;
102
103    fn map(&self, f: &mut F) -> Self::Output {
104        FieldPayloadCons {
105            head: TypedValue::from(f.call()).into(),
106            tail: self.tail.map(f),
107        }
108    }
109}
110
111/// Implementation of a function for a particular data type.
112pub trait Func<DType> {
113    /// Output of this function.
114    type Output;
115    /// Method to call this function on field data of data type `DType`.
116    fn call<DI>(&mut self, data: &DI) -> Self::Output
117    where
118        DI: DataIndex<DType = DType>;
119}
120
121/// Default function implementation with no valid implementation exists.
122pub trait FuncDefault {
123    /// Output of this function.
124    type Output;
125    /// Method called when no [Func](trait.Func.html) implementation exists.
126    fn call(&mut self) -> Self::Output;
127}
128
129/// Trait that augments a [DataIndexCons](../view/type.DataIndexCons.html) (a cons-list of
130/// field access structs) with partial-function capability information as specified by
131/// [IsImplemented](trait.IsImplemented.html) definitions.
132pub trait DeriveCapabilities<F> {
133    /// The augmented cons-list which implements [PartialMap](trait.PartialMap.html), allowing
134    /// application of partially-implemented functions to a `DataView`.
135    type Output: PartialMap<F>;
136
137    /// Derive the capabilities of this cons-list.
138    fn derive(self) -> Self::Output;
139}
140impl<F> DeriveCapabilities<F> for Nil {
141    type Output = Nil;
142    fn derive(self) -> Nil {
143        Nil
144    }
145}
146impl<Label, DType, DI, Tail, F> DeriveCapabilities<F> for DataIndexCons<Label, DType, DI, Tail>
147where
148    Tail: DeriveCapabilities<F>,
149    DI: DataIndex<DType = DType> + SelfValued,
150    DType: IsImplemented<F>,
151    StorageCapabilitiesCons<
152        Label,
153        DType,
154        DI,
155        F,
156        <DType as IsImplemented<F>>::IsImpl,
157        <Tail as DeriveCapabilities<F>>::Output,
158    >: PartialMap<F>,
159{
160    type Output = StorageCapabilitiesCons<
161        Label,
162        DType,
163        DI,
164        F,
165        <DType as IsImplemented<F>>::IsImpl,
166        <Tail as DeriveCapabilities<F>>::Output,
167    >;
168    fn derive(self) -> Self::Output {
169        LVCons {
170            head: StorageCapabilities {
171                data: self.head.value(),
172                _marker: PhantomData,
173            }
174            .into(),
175            tail: self.tail.derive(),
176        }
177    }
178}
179
180/// Helper type alias that provides the derived capabilities of the
181/// [DataIndexCons](../view/type.DataIndexCons.html) associated with a particular `Labels` /
182/// `Frames` pair.
183pub type DeriveCapabilitiesOf<Labels, Frames, F> =
184    <AssocDataIndexConsOf<Labels, Frames> as DeriveCapabilities<F>>::Output;