cargo_dist/config/v1/
layer.rs

1//! Utils for merging things
2
3use serde::{Deserialize, Serialize};
4
5/// Trait for merging a new layer of config
6pub trait ApplyLayer
7where
8    Self: Sized,
9{
10    /// The much more Option-ridden version of this config
11    /// that can be repeatedly layerd with options
12    type Layer;
13
14    /// Merges this value with another layer of itself, preferring the new layer
15    fn apply_layer(&mut self, layer: Self::Layer);
16
17    /// Merges this value with another layer of itself, preferring the new layer
18    ///
19    /// (asymmetric case where the rhs is an Option but we're just A Value)
20    fn apply_val_layer(&mut self, layer: Option<Self::Layer>) {
21        if let Some(val) = layer {
22            self.apply_layer(val);
23        }
24    }
25}
26
27/// Extension trait to provide apply_bool_layer
28pub trait ApplySelfLayerExt {
29    /// inner type
30    type Inner;
31    /// Merge an `Option<Layer>` with an `Option<BoolOr<Layer>>`
32    ///
33    /// There are 3 cases for the rhs (layer):
34    ///
35    /// * Some(Val): override; recursively apply_layer
36    /// * Some(false): manually disabled; set lhs to None
37    /// * Some(true) / None: redundant; do nothing
38    ///
39    /// There are 2 cases for the lhs (self):
40    ///
41    /// * Some: still live, can be overriden/merged
42    /// * None: permanently disabled, rhs will be ignored
43    fn apply_opt_layer(&mut self, layer: Option<Self::Inner>);
44}
45
46impl<T> ApplySelfLayerExt for Option<T>
47where
48    T: ApplyLayer<Layer = T>,
49{
50    type Inner = T;
51    /// Merges this value with another layer of itself, preferring the new layer
52    ///
53    /// (asymteric case where the rhs is an Option but we're just A Value)
54    fn apply_opt_layer(&mut self, layer: Option<Self::Inner>) {
55        if let Some(val) = layer {
56            if let Some(this) = self {
57                this.apply_layer(val);
58            } else {
59                *self = Some(val);
60            }
61        }
62    }
63}
64
65/// Extension trait to provide apply_bool_layer
66pub trait ApplyBoolLayerExt {
67    /// inner type
68    type Inner;
69    /// Merge an `Option<Layer>` with an `Option<BoolOr<Layer>>`
70    ///
71    /// There are 3 cases for the rhs (layer):
72    ///
73    /// * Some(Val): override; recursively apply_layer
74    /// * Some(false): manually disabled; set lhs to None
75    /// * Some(true) / None: redundant; do nothing
76    ///
77    /// There are 2 cases for the lhs (self):
78    ///
79    /// * Some: still live, can be overriden/merged
80    /// * None: permanently disabled, rhs will be ignored
81    fn apply_bool_layer(&mut self, layer: Option<BoolOr<Self::Inner>>);
82}
83
84impl<T> ApplyBoolLayerExt for Option<T>
85where
86    T: ApplyLayer + Default,
87{
88    type Inner = T::Layer;
89
90    /// Apply a layer that can either be a boolean, or a Layer Value (most likely an object).
91    ///
92    /// Possible cases (lhs is the resultant config, rhs is the incoming layer):
93    /// lhs == Some && rhs == true  = nothing happens
94    /// lhs == Some && rhs == false = lhs gets set to None
95    /// lhs == Some && rhs == value = layer gets applied to lhs
96    /// lhs == None && rhs == true  = lhs gets set to layer default
97    /// lhs == None && rhs == false = nothing happens
98    /// lhs == None && rhs == value = lhs gets set to layer default with layer applied
99    /// rhs = nothing               = we do nothing
100    fn apply_bool_layer(&mut self, layer: Option<BoolOr<Self::Inner>>) {
101        match layer {
102            Some(BoolOr::Val(val)) => {
103                if let Some(this) = self {
104                    this.apply_layer(val);
105                } else {
106                    let mut t = T::default();
107                    t.apply_layer(val);
108                    *self = Some(t);
109                }
110            }
111            Some(BoolOr::Bool(false)) => {
112                // Disable this setting
113                *self = None;
114            }
115            Some(BoolOr::Bool(true)) => {
116                // Enable if self was previously set to None
117                if self.is_none() {
118                    *self = Some(T::default());
119                }
120            }
121            None => {}
122        }
123    }
124}
125
126/// Extension trait to provide apply_val
127pub trait ApplyValExt
128where
129    Self: Sized,
130{
131    /// Merges a `T` with an `Option<T>`
132    ///
133    /// Overwrites the lhs if the rhs is Some
134    fn apply_val(&mut self, layer: Option<Self>);
135}
136impl<T> ApplyValExt for T {
137    fn apply_val(&mut self, layer: Option<Self>) {
138        if let Some(val) = layer {
139            *self = val;
140        }
141    }
142}
143
144/// Extension trait to provide apply_opt
145pub trait ApplyOptExt
146where
147    Self: Sized,
148{
149    /// Merges an `Option<T>` with an `Option<T>`
150    ///
151    /// Overwrites the lhs if the rhs is Some
152    fn apply_opt(&mut self, layer: Self);
153}
154impl<T> ApplyOptExt for Option<T> {
155    fn apply_opt(&mut self, layer: Self) {
156        if let Some(val) = layer {
157            *self = Some(val);
158        }
159    }
160}
161
162/// A value or just a boolean
163///
164/// This allows us to have a simple yes/no version of a config while still
165/// allowing for a more advanced version to exist.
166#[derive(Serialize, Deserialize, Debug, Clone)]
167#[serde(untagged)]
168pub enum BoolOr<T> {
169    /// They gave the simple bool
170    Bool(bool),
171    /// They gave a more interesting value
172    Val(T),
173}