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}