1use serde::ser::SerializeStruct as _;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4use crate::{ContractProvenance, Guard, GuardDnf, ResourceRef, ValueKind, ValuesPath, YamlPath};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10pub struct SplitSegmentUse {
11 pub separator: String,
13 pub last: bool,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
19pub enum MergeLayerTransform {
20 Identity,
22 NilScrubbed,
24 ParsedMap,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
30pub struct MergeLayer {
31 pub path: ValuesPath,
33 pub transform: MergeLayerTransform,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct MergeLayersUse {
43 layers: Vec<MergeLayer>,
44 position: usize,
45 own_transform: MergeLayerTransform,
46 via_binding: bool,
54}
55
56impl MergeLayersUse {
57 #[must_use]
59 pub fn new(layers: Vec<MergeLayer>, position: usize, via_binding: bool) -> Option<Self> {
60 let own_transform = layers
61 .iter()
62 .enumerate()
63 .find_map(|(index, layer)| (index == position).then_some(layer.transform))?;
64 Some(Self {
65 layers,
66 position,
67 own_transform,
68 via_binding,
69 })
70 }
71
72 #[must_use]
74 pub fn layers(&self) -> &[MergeLayer] {
75 &self.layers
76 }
77
78 #[must_use]
80 pub fn position(&self) -> usize {
81 self.position
82 }
83
84 #[must_use]
86 pub fn own_path_is(&self, path: &ValuesPath) -> bool {
87 self.layers
88 .iter()
89 .enumerate()
90 .any(|(index, layer)| index == self.position && &layer.path == path)
91 }
92
93 #[must_use]
95 pub fn shadowed_by(&self) -> impl ExactSizeIterator<Item = &MergeLayer> {
96 self.layers.iter().take(self.position)
97 }
98
99 #[must_use]
101 pub fn own_transform(&self) -> MergeLayerTransform {
102 self.own_transform
103 }
104
105 #[must_use]
107 pub fn has_transformed_layer(&self) -> bool {
108 self.layers
109 .iter()
110 .any(|layer| layer.transform != MergeLayerTransform::Identity)
111 }
112
113 #[must_use]
115 pub fn via_binding(&self) -> bool {
116 self.via_binding
117 }
118
119 #[must_use]
121 pub fn into_via_binding(mut self) -> Self {
122 self.via_binding = true;
123 self
124 }
125}
126
127impl Serialize for MergeLayersUse {
128 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
129 where
130 S: Serializer,
131 {
132 let paths = self
133 .layers
134 .iter()
135 .map(|layer| &layer.path)
136 .collect::<Vec<_>>();
137 let transforms = self
138 .layers
139 .iter()
140 .map(|layer| layer.transform)
141 .collect::<Vec<_>>();
142 let mut state = serializer.serialize_struct("MergeLayersUse", 4)?;
143 state.serialize_field("layers", &paths)?;
144 state.serialize_field("position", &self.position)?;
145 state.serialize_field("transforms", &transforms)?;
146 state.serialize_field("via_binding", &self.via_binding)?;
147 state.end()
148 }
149}
150
151impl<'de> Deserialize<'de> for MergeLayersUse {
152 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153 where
154 D: Deserializer<'de>,
155 {
156 #[derive(Deserialize)]
157 struct WireMergeLayersUse {
158 layers: Vec<ValuesPath>,
159 position: usize,
160 transforms: Vec<MergeLayerTransform>,
161 via_binding: bool,
162 }
163
164 let wire = WireMergeLayersUse::deserialize(deserializer)?;
165 if wire.layers.len() != wire.transforms.len() {
166 return Err(serde::de::Error::custom(
167 "merge layer paths and transforms must have equal lengths",
168 ));
169 }
170 let layers = wire
171 .layers
172 .into_iter()
173 .zip(wire.transforms)
174 .map(|(path, transform)| MergeLayer { path, transform })
175 .collect();
176 Self::new(layers, wire.position, wire.via_binding)
177 .ok_or_else(|| serde::de::Error::custom("merge layer position is out of bounds"))
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
183pub struct ContractUse {
184 pub source_expr: ValuesPath,
186 pub path: YamlPath,
188 pub kind: ValueKind,
190 pub condition: GuardDnf,
192 pub resource: Option<ResourceRef>,
194 #[serde(default, skip_serializing_if = "Vec::is_empty")]
196 pub provenance: Vec<ContractProvenance>,
197 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
200 pub stringified: bool,
201 #[serde(default, skip_serializing_if = "std::collections::BTreeSet::is_empty")]
206 pub template_supplied_member_keys: std::collections::BTreeSet<String>,
207 #[serde(default, skip_serializing_if = "Option::is_none")]
210 pub split_segment: Option<SplitSegmentUse>,
211 #[serde(default, skip_serializing_if = "Option::is_none")]
213 pub merge_layers: Option<MergeLayersUse>,
214 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
217 pub range_key: bool,
218 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
223 pub nil_omitting: bool,
224 #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
230 pub omitted_members: std::collections::BTreeMap<String, Vec<Guard>>,
231 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
237 pub digest: bool,
238 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
243 pub merge_operand: bool,
244}
245
246impl ContractUse {
247 #[must_use]
249 pub fn new(
250 source_expr: ValuesPath,
251 path: YamlPath,
252 kind: ValueKind,
253 guards: Vec<Guard>,
254 resource: Option<ResourceRef>,
255 ) -> Self {
256 Self::with_provenances(source_expr, path, kind, guards, resource, None)
257 }
258
259 pub fn with_provenances(
261 source_expr: ValuesPath,
262 path: YamlPath,
263 kind: ValueKind,
264 guards: Vec<Guard>,
265 resource: Option<ResourceRef>,
266 provenance: impl IntoIterator<Item = ContractProvenance>,
267 ) -> Self {
268 let condition = GuardDnf::from_guards(guards);
269 Self::with_condition_and_provenances(
270 source_expr,
271 path,
272 kind,
273 condition,
274 resource,
275 provenance,
276 )
277 }
278
279 pub fn with_condition_and_provenances(
281 source_expr: ValuesPath,
282 path: YamlPath,
283 kind: ValueKind,
284 condition: GuardDnf,
285 resource: Option<ResourceRef>,
286 provenance: impl IntoIterator<Item = ContractProvenance>,
287 ) -> Self {
288 Self {
289 source_expr,
290 path,
291 kind,
292 condition,
293 resource,
294 provenance: provenance.into_iter().collect(),
295 stringified: false,
296 template_supplied_member_keys: std::collections::BTreeSet::new(),
297 split_segment: None,
298 merge_layers: None,
299 range_key: false,
300 nil_omitting: false,
301 omitted_members: std::collections::BTreeMap::new(),
302 digest: false,
303 merge_operand: false,
304 }
305 }
306
307 pub fn canonicalize(&mut self) {
309 self.provenance.sort();
310 self.provenance.dedup();
311 }
312
313 #[must_use]
315 pub fn single_guard_conjunction(&self) -> Vec<Guard> {
316 self.condition
317 .single_guard_conjunction()
318 .unwrap_or_default()
319 }
320
321 pub fn map_value_paths<F>(&mut self, map: &mut F)
323 where
324 F: FnMut(ValuesPath) -> ValuesPath,
325 {
326 let Self {
327 source_expr,
328 path: _,
329 kind: _,
330 condition,
331 resource: _,
332 provenance: _,
333 stringified: _,
334 template_supplied_member_keys: _,
335 split_segment: _,
336 merge_layers,
337 range_key: _,
338 nil_omitting: _,
339 omitted_members,
340 digest: _,
341 merge_operand: _,
342 } = self;
343 *source_expr = map(source_expr.clone());
344 condition.map_value_paths(map);
345 if let Some(merge) = merge_layers {
346 for layer in &mut merge.layers {
347 layer.path = map(layer.path.clone());
348 }
349 }
350 for retain_guards in omitted_members.values_mut() {
351 for guard in retain_guards {
352 *guard = guard.clone().map_value_paths(map);
353 }
354 }
355 }
356}