1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Helpers for sanitizing and merging command-line arguments with
//! configuration defaults.
use crate::;
use ArgMatches;
use Serialized;
use Serialize;
use Value;
/// Recursively remove all [`Value::Null`] entries, pruning empty objects.
///
/// - Object fields equal to null are removed.
/// - Nested objects containing no non-null fields are also removed so empty
/// `#[clap(flatten)]` groups do not clobber defaults.
/// - Array elements equal to null are removed, dropping `None` entries in
/// `Vec<_>` but retaining empty arrays to allow deliberate clearing.
///
/// Intended for CLI sanitization so unset [`Option`] fields and untouched
/// flattened structs do not override defaults from files or environment
/// variables.
/// Arrays are never removed, even when emptied; this function only removes
/// [`Option::None`] fields.
///
/// Returns `true` if `value` becomes empty after pruning (that is, it is
/// `Null` or an object with no remaining fields). Arrays never return `true`,
/// even when emptied, to preserve explicit clearing semantics.
/// Serialize a CLI struct to JSON, removing fields set to `None`.
///
/// # Examples
///
/// ```rust
/// use ortho_config::value_without_nones;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Args { count: Option<u32> }
///
/// let v = value_without_nones(&Args { count: None })
/// .expect("expected serialization to succeed");
/// assert_eq!(v, serde_json::json!({}));
/// ```
///
/// # Errors
///
/// Returns any [`serde_json::Error`] encountered during serialization.
/// Serialize `value` to JSON, pruning `None` fields and mapping errors to
/// [`crate::OrthoError`].
///
/// # Examples
///
/// ```rust
/// use ortho_config::sanitize_value;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Args { count: Option<u32> }
/// let v = sanitize_value(&Args { count: None })
/// .expect("expected sanitization to succeed");
/// assert_eq!(v, serde_json::json!({}));
/// ```
///
/// # Errors
///
/// Returns an [`crate::OrthoError`] if JSON serialization fails.
/// Produce a Figment provider from `value` with `None` fields removed.
///
/// This helper wraps [`sanitize_value`] and avoids repeating the
/// `Serialized::defaults` pattern when layering providers.
///
/// # Examples
///
/// ```rust
/// use figment::Figment;
/// use ortho_config::sanitized_provider;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Args { count: Option<u32> }
///
/// let provider = sanitized_provider(&Args { count: None })
/// .expect("expected provider creation to succeed");
/// let value: serde_json::Value = Figment::from(provider)
/// .extract()
/// .expect("expected extraction to succeed");
/// assert_eq!(value, serde_json::json!({}));
/// ```
///
/// # Errors
///
/// Returns an [`crate::OrthoError`] if JSON serialization fails.
/// Trait for extracting CLI values whilst treating clap defaults as absent.
///
/// Types implementing this trait can distinguish between values explicitly
/// provided on the command line and values filled in by clap's `default_value_t`
/// or similar mechanisms. Fields marked with `#[ortho_config(cli_default_as_absent)]`
/// are only included in the extracted JSON when `value_source()` returns
/// [`clap::parser::ValueSource::CommandLine`].
///
/// This allows file and environment configuration to take precedence over CLI
/// defaults while still honouring explicit CLI overrides.
///
/// # Examples
///
/// ```rust,ignore
/// use clap::{ArgMatches, Parser};
/// use ortho_config::{CliValueExtractor, OrthoConfig, OrthoResult};
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Parser, Deserialize, Serialize, OrthoConfig, Default)]
/// #[ortho_config(prefix = "APP_")]
/// struct MyCommand {
/// #[arg(long, default_value_t = String::from("!"))]
/// #[ortho_config(cli_default_as_absent)]
/// punctuation: String,
/// }
///
/// // When parsed without --punctuation flag, extract_user_provided returns {}
/// // When parsed with --punctuation "?", extract_user_provided returns {"punctuation": "?"}
/// ```