1use std::{collections::BTreeMap, fmt, iter, mem, sync::Arc};
4
5pub use secrecy::{ExposeSecret, SecretString};
6
7use crate::metadata::BasicTypes;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11#[non_exhaustive]
12pub enum FileFormat {
13 Json,
15 Yaml,
17 Dotenv,
19}
20
21impl fmt::Display for FileFormat {
22 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23 formatter.write_str(match self {
24 Self::Json => "JSON",
25 Self::Yaml => "YAML",
26 Self::Dotenv => ".env",
27 })
28 }
29}
30
31#[derive(Debug, Default)]
33#[non_exhaustive]
34pub enum ValueOrigin {
35 #[default]
37 Unknown,
38 EnvVars,
40 Fallbacks,
42 File {
44 name: String,
46 format: FileFormat,
48 },
49 Path {
51 source: Arc<Self>,
53 path: String,
55 },
56 Synthetic {
58 source: Arc<Self>,
60 transform: String,
62 },
63}
64
65impl fmt::Display for ValueOrigin {
66 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::Unknown => formatter.write_str("unknown"),
69 Self::EnvVars => formatter.write_str("env variables"),
70 Self::Fallbacks => formatter.write_str("fallbacks"),
71 Self::File { name, format } => {
72 write!(formatter, "{format} file '{name}'")
73 }
74 Self::Path { source, path } => {
75 if matches!(source.as_ref(), ValueOrigin::EnvVars) {
76 write!(formatter, "env variable '{path}'")
77 } else {
78 write!(formatter, "{source} -> path '{path}'")
79 }
80 }
81 Self::Synthetic { source, transform } => {
82 write!(formatter, "{source} -> {transform}")
83 }
84 }
85 }
86}
87
88#[derive(Clone)]
90pub enum StrValue {
91 Plain(String),
93 Secret(SecretString),
95}
96
97impl StrValue {
98 pub fn expose(&self) -> &str {
100 match self {
101 Self::Plain(s) => s,
102 Self::Secret(s) => s.expose_secret(),
103 }
104 }
105
106 pub(crate) fn is_secret(&self) -> bool {
107 matches!(self, Self::Secret(_))
108 }
109
110 pub(crate) fn make_secret(&mut self) {
111 match self {
112 Self::Plain(s) => {
113 *self = Self::Secret(mem::take(s).into());
114 }
115 Self::Secret(_) => { }
116 }
117 }
118}
119
120impl fmt::Debug for StrValue {
121 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self {
123 Self::Plain(s) => fmt::Debug::fmt(s, formatter),
124 Self::Secret(_) => formatter.write_str("[REDACTED]"),
125 }
126 }
127}
128
129impl fmt::Display for StrValue {
130 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
131 formatter.write_str(match self {
132 Self::Plain(s) => s,
133 Self::Secret(_) => "[REDACTED]",
134 })
135 }
136}
137
138#[derive(Clone, Default)]
140pub enum Value {
141 #[default]
143 Null,
144 Bool(bool),
146 Number(serde_json::Number),
148 String(StrValue),
150 Array(Vec<WithOrigin>),
152 Object(Map),
154}
155
156impl fmt::Debug for Value {
157 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
158 match self {
159 Self::Null => formatter.write_str("null"),
160 Self::Bool(value) => fmt::Display::fmt(value, formatter),
161 Self::Number(value) => fmt::Display::fmt(value, formatter),
162 Self::String(value) => fmt::Debug::fmt(value, formatter),
163 Self::Array(array) => formatter.debug_list().entries(array).finish(),
164 Self::Object(map) => formatter.debug_map().entries(map).finish(),
165 }
166 }
167}
168
169impl From<bool> for Value {
170 fn from(value: bool) -> Self {
171 Self::Bool(value)
172 }
173}
174
175impl PartialEq<bool> for Value {
176 fn eq(&self, other: &bool) -> bool {
177 match self {
178 Self::Bool(val) => val == other,
179 _ => false,
180 }
181 }
182}
183
184impl From<serde_json::Number> for Value {
185 fn from(value: serde_json::Number) -> Self {
186 Self::Number(value)
187 }
188}
189
190impl PartialEq<serde_json::Number> for Value {
191 fn eq(&self, other: &serde_json::Number) -> bool {
192 match self {
193 Self::Number(num) => num == other,
194 _ => false,
195 }
196 }
197}
198
199macro_rules! impl_traits_for_number {
200 ($num:ty) => {
201 impl From<$num> for Value {
202 fn from(value: $num) -> Self {
203 Self::Number(value.into())
204 }
205 }
206
207 impl PartialEq<$num> for Value {
208 fn eq(&self, other: &$num) -> bool {
209 match self {
210 Self::Number(num) => *num == (*other).into(),
211 _ => false,
212 }
213 }
214 }
215 };
216}
217
218impl_traits_for_number!(u64);
219impl_traits_for_number!(i64);
220
221impl From<String> for Value {
222 fn from(value: String) -> Self {
223 Self::String(StrValue::Plain(value))
224 }
225}
226
227impl From<Vec<WithOrigin>> for Value {
228 fn from(array: Vec<WithOrigin>) -> Self {
229 Self::Array(array)
230 }
231}
232
233impl From<Map> for Value {
234 fn from(map: Map) -> Self {
235 Self::Object(map)
236 }
237}
238
239impl Value {
240 pub(crate) fn is_supported_by(&self, types: BasicTypes) -> bool {
241 match self {
242 Self::Null => true,
243 Self::Bool(_) => types.contains(BasicTypes::BOOL),
244 Self::Number(number) if number.is_u64() || number.is_i64() => {
245 types.contains(BasicTypes::INTEGER)
246 }
247 Self::Number(_) => types.contains(BasicTypes::FLOAT),
248 Self::String(_) => {
249 types.contains(BasicTypes::STRING)
252 || types.contains(BasicTypes::INTEGER)
253 || types.contains(BasicTypes::BOOL)
254 }
255 Self::Array(_) => types.contains(BasicTypes::ARRAY),
256 Self::Object(_) => types.contains(BasicTypes::OBJECT),
257 }
258 }
259
260 pub fn as_plain_str(&self) -> Option<&str> {
262 match self {
263 Self::String(StrValue::Plain(s)) => Some(s),
264 _ => None,
265 }
266 }
267
268 pub fn as_object(&self) -> Option<&Map> {
270 match self {
271 Self::Object(map) => Some(map),
272 _ => None,
273 }
274 }
275}
276
277pub type Map<V = Value> = BTreeMap<String, WithOrigin<V>>;
279
280#[derive(Debug, Clone, Default)]
282pub struct WithOrigin<T = Value> {
283 pub inner: T,
285 pub origin: Arc<ValueOrigin>,
287}
288
289impl<T> WithOrigin<T> {
290 pub fn new(inner: T, origin: Arc<ValueOrigin>) -> Self {
292 Self { inner, origin }
293 }
294
295 pub(crate) fn set_origin_if_unset(mut self, origin: &Arc<ValueOrigin>) -> Self {
296 if matches!(self.origin.as_ref(), ValueOrigin::Unknown) {
297 self.origin = origin.clone();
298 }
299 self
300 }
301
302 pub(crate) fn map<U>(self, map_fn: impl FnOnce(T) -> U) -> WithOrigin<U> {
303 WithOrigin {
304 inner: map_fn(self.inner),
305 origin: self.origin,
306 }
307 }
308}
309
310impl WithOrigin {
311 pub(crate) fn get(&self, pointer: Pointer<'_>) -> Option<&Self> {
312 pointer
313 .segments()
314 .try_fold(self, |ptr, segment| match &ptr.inner {
315 Value::Object(map) => map.get(segment),
316 Value::Array(array) => array.get(segment.parse::<usize>().ok()?),
317 _ => None,
318 })
319 }
320
321 pub fn pointer(&self, pointer: &str) -> Option<&Self> {
323 self.get(Pointer(pointer))
324 }
325
326 pub(crate) fn get_mut(&mut self, pointer: Pointer) -> Option<&mut Self> {
327 pointer
328 .segments()
329 .try_fold(self, |ptr, segment| match &mut ptr.inner {
330 Value::Object(map) => map.get_mut(segment),
331 Value::Array(array) => array.get_mut(segment.parse::<usize>().ok()?),
332 _ => None,
333 })
334 }
335
336 pub(crate) fn ensure_object(
338 &mut self,
339 at: Pointer<'_>,
340 mut create_origin: impl FnMut(Pointer<'_>) -> Arc<ValueOrigin>,
341 ) -> &mut Map {
342 for ancestor_path in at.with_ancestors() {
343 self.ensure_object_step(ancestor_path, &mut create_origin);
344 }
345
346 let Value::Object(map) = &mut self.get_mut(at).unwrap().inner else {
347 unreachable!(); };
349 map
350 }
351
352 fn ensure_object_step(
353 &mut self,
354 at: Pointer<'_>,
355 mut create_origin: impl FnMut(Pointer<'_>) -> Arc<ValueOrigin>,
356 ) {
357 let Some((parent, last_segment)) = at.split_last() else {
358 return;
360 };
361
362 let parent = &mut self.get_mut(parent).unwrap().inner;
364 if !matches!(parent, Value::Object(_)) {
365 *parent = Value::Object(Map::new());
366 }
367 let Value::Object(parent_object) = parent else {
368 unreachable!();
369 };
370
371 if !parent_object.contains_key(last_segment) {
372 parent_object.insert(
373 last_segment.to_owned(),
374 WithOrigin {
375 inner: Value::Object(Map::new()),
376 origin: create_origin(at),
377 },
378 );
379 }
380 }
381
382 pub(crate) fn deep_merge(&mut self, overrides: Self) {
385 match (&mut self.inner, overrides.inner) {
386 (Value::Object(this), Value::Object(other)) => {
387 Self::deep_merge_into_map(this, other);
388 }
389 (this, value) => {
390 *this = value;
391 self.origin = overrides.origin;
392 }
393 }
394 }
395
396 fn deep_merge_into_map(dest: &mut Map, source: Map) {
397 for (key, value) in source {
398 if let Some(existing_value) = dest.get_mut(&key) {
399 existing_value.deep_merge(value);
400 } else {
401 dest.insert(key, value);
402 }
403 }
404 }
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
409pub(crate) struct Pointer<'a>(pub &'a str);
410
411impl fmt::Display for Pointer<'_> {
412 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
413 formatter.write_str(self.0)
414 }
415}
416
417impl<'a> Pointer<'a> {
418 pub(crate) fn segments(self) -> impl Iterator<Item = &'a str> {
419 self.0
420 .split('.')
421 .take(if self.0.is_empty() { 0 } else { usize::MAX })
422 }
423
424 pub(crate) fn split_last(self) -> Option<(Self, &'a str)> {
425 if self.0.is_empty() {
426 None
427 } else if let Some((parent, last_segment)) = self.0.rsplit_once('.') {
428 Some((Self(parent), last_segment))
429 } else {
430 Some((Self(""), self.0))
431 }
432 }
433
434 pub(crate) fn with_ancestors(self) -> impl Iterator<Item = Self> {
436 let mut current = self.0;
437 iter::from_fn(move || {
438 if current.is_empty() {
439 None
440 } else if let Some((_, tail)) = current.split_once('.') {
441 current = tail;
442 Some(Self(&self.0[..self.0.len() - tail.len() - 1]))
443 } else {
444 current = "";
445 Some(self)
446 }
447 })
448 }
449
450 pub(crate) fn join(self, suffix: &str) -> String {
451 if suffix.is_empty() {
452 self.0.to_owned()
453 } else if self.0.is_empty() {
454 suffix.to_owned()
455 } else {
456 format!("{}.{suffix}", self.0)
457 }
458 }
459
460 pub(crate) fn join_path(mut self, suffix: Pointer<'_>) -> Option<String> {
462 let prefix_dots = suffix.0.bytes().take_while(|&ch| ch == b'.').count();
463 for _ in 0..prefix_dots.saturating_sub(1) {
464 (self, _) = self.split_last()?;
465 }
466 Some(self.join(&suffix.0[prefix_dots..]))
467 }
468}
469
470#[cfg(test)]
471mod tests {
472 use super::*;
473
474 #[test]
475 fn splitting_pointer() {
476 let pointer = Pointer("");
477 assert_eq!(pointer.split_last(), None);
478 assert_eq!(pointer.segments().collect::<Vec<_>>(), [] as [&str; 0]);
479 assert_eq!(pointer.with_ancestors().collect::<Vec<_>>(), []);
480
481 let pointer = Pointer("test");
482 assert_eq!(pointer.split_last(), Some((Pointer(""), "test")));
483 assert_eq!(pointer.segments().collect::<Vec<_>>(), ["test"]);
484 assert_eq!(
485 pointer.with_ancestors().collect::<Vec<_>>(),
486 [Pointer("test")]
487 );
488
489 let pointer = Pointer("test.value");
490 assert_eq!(pointer.split_last(), Some((Pointer("test"), "value")));
491 assert_eq!(pointer.segments().collect::<Vec<_>>(), ["test", "value"]);
492 assert_eq!(
493 pointer.with_ancestors().collect::<Vec<_>>(),
494 [Pointer("test"), Pointer("test.value")]
495 );
496 }
497
498 #[test]
499 fn joining_pointers() {
500 let pointer = Pointer("");
501 let joined = pointer.join("test");
502 assert_eq!(joined, "test");
503
504 let pointer = Pointer("test");
505 let joined = pointer.join("");
506 assert_eq!(joined, "test");
507
508 let pointer = Pointer("test");
509 let joined = pointer.join("other");
510 assert_eq!(joined, "test.other");
511 }
512
513 #[test]
514 fn joining_pointer_paths() {
515 let pointer = Pointer("");
516 let joined = pointer.join_path(Pointer("test")).unwrap();
517 assert_eq!(joined, "test");
518
519 let pointer = Pointer("");
520 let joined = pointer.join_path(Pointer(".test")).unwrap();
521 assert_eq!(joined, "test");
522
523 let pointer = Pointer("");
524 let joined = pointer.join_path(Pointer(".test.value")).unwrap();
525 assert_eq!(joined, "test.value");
526
527 let pointer = Pointer("map");
528 let joined = pointer.join_path(Pointer(".test.value")).unwrap();
529 assert_eq!(joined, "map.test.value");
530
531 let pointer = Pointer("map");
532 let joined = pointer.join_path(Pointer("..test.value")).unwrap();
533 assert_eq!(joined, "test.value");
534
535 let pointer = Pointer("map.key");
536 let joined = pointer.join_path(Pointer("..test.value")).unwrap();
537 assert_eq!(joined, "map.test.value");
538
539 let pointer = Pointer("map.key");
540 let joined = pointer.join_path(Pointer("...test.value")).unwrap();
541 assert_eq!(joined, "test.value");
542 }
543}