Skip to main content

compose_lens/model/
resource.rs

1//! Top-level volumes, configs, secrets, and service grants.
2
3use super::{BooleanValue, FieldReference, KeyValueEntry, Labels, Located};
4use crate::source::SourceSpan;
5
6/// The authored lifecycle form for a top-level resource.
7///
8/// Compose historically allowed `external: { name: ... }`.  It is deliberately
9/// distinct from the modern sibling `name` field so callers can diagnose an
10/// ambiguous document instead of silently selecting one spelling.
11#[derive(Debug, Clone, PartialEq, Eq)]
12#[non_exhaustive]
13pub enum ResourceExternal {
14    /// Modern boolean or deferred-expression syntax.
15    Boolean(Located<BooleanValue>),
16    /// Deprecated mapping syntax retaining its independently authored name.
17    NameMapping(Box<ExternalNameMapping>),
18}
19
20impl ResourceExternal {
21    /// Returns the boolean/expression form when it was authored.
22    #[must_use]
23    pub const fn boolean(&self) -> Option<&Located<BooleanValue>> {
24        let Self::Boolean(value) = self else {
25            return None;
26        };
27        Some(value)
28    }
29
30    /// Returns the deprecated external-name mapping when it was authored.
31    #[must_use]
32    pub const fn name_mapping(&self) -> Option<&ExternalNameMapping> {
33        let Self::NameMapping(value) = self else {
34            return None;
35        };
36        Some(value)
37    }
38
39    /// Whether this form explicitly selects external lifecycle.
40    #[must_use]
41    pub fn is_explicitly_external(&self) -> bool {
42        matches!(self, Self::NameMapping(_))
43            || matches!(self, Self::Boolean(value) if matches!(value.value(), BooleanValue::Literal(true)))
44    }
45}
46
47/// The deprecated Compose `external: { name: ... }` mapping.
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct ExternalNameMapping {
50    span: SourceSpan,
51    name: Option<Located<String>>,
52    extension_fields: Vec<FieldReference>,
53    unknown_fields: Vec<FieldReference>,
54}
55
56impl ExternalNameMapping {
57    pub(crate) fn new(span: SourceSpan) -> Self {
58        Self {
59            span,
60            name: None,
61            extension_fields: Vec::new(),
62            unknown_fields: Vec::new(),
63        }
64    }
65    pub(crate) fn set_name(&mut self, value: Located<String>) {
66        self.name = Some(value);
67    }
68    pub(crate) fn push_extension(&mut self, value: FieldReference) {
69        self.extension_fields.push(value);
70    }
71    pub(crate) fn push_unknown(&mut self, value: FieldReference) {
72        self.unknown_fields.push(value);
73    }
74
75    /// Returns the complete deprecated mapping span.
76    #[must_use]
77    pub const fn span(&self) -> SourceSpan {
78        self.span
79    }
80    /// Returns the deprecated external resource name when it is a YAML string.
81    #[must_use]
82    pub const fn name(&self) -> Option<&Located<String>> {
83        self.name.as_ref()
84    }
85    /// Returns retained `x-` fields in the deprecated mapping.
86    #[must_use]
87    pub fn extension_fields(&self) -> &[FieldReference] {
88        &self.extension_fields
89    }
90    /// Returns unrecognized or malformed fields in the deprecated mapping.
91    #[must_use]
92    pub fn unknown_fields(&self) -> &[FieldReference] {
93        &self.unknown_fields
94    }
95}
96
97/// A typed top-level volume definition.
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub struct VolumeDefinition {
100    name: Located<String>,
101    span: SourceSpan,
102    driver: Option<Located<String>>,
103    driver_opts: Vec<KeyValueEntry>,
104    external: Option<ResourceExternal>,
105    labels: Option<Labels>,
106    custom_name: Option<Located<String>>,
107    extension_fields: Vec<FieldReference>,
108    unknown_fields: Vec<FieldReference>,
109}
110
111impl VolumeDefinition {
112    pub(crate) fn new(name: Located<String>, span: SourceSpan) -> Self {
113        Self {
114            name,
115            span,
116            driver: None,
117            driver_opts: Vec::new(),
118            external: None,
119            labels: None,
120            custom_name: None,
121            extension_fields: Vec::new(),
122            unknown_fields: Vec::new(),
123        }
124    }
125    pub(crate) fn set_driver(&mut self, value: Located<String>) {
126        self.driver = Some(value);
127    }
128    pub(crate) fn set_driver_opts(&mut self, value: Vec<KeyValueEntry>) {
129        self.driver_opts = value;
130    }
131    pub(crate) fn set_external(&mut self, value: ResourceExternal) {
132        self.external = Some(value);
133    }
134    pub(crate) fn set_labels(&mut self, value: Labels) {
135        self.labels = Some(value);
136    }
137    pub(crate) fn set_custom_name(&mut self, value: Located<String>) {
138        self.custom_name = Some(value);
139    }
140    pub(crate) fn push_extension(&mut self, value: FieldReference) {
141        self.extension_fields.push(value);
142    }
143    pub(crate) fn push_unknown(&mut self, value: FieldReference) {
144        self.unknown_fields.push(value);
145    }
146
147    /// Returns the model identifier.
148    #[must_use]
149    pub const fn name(&self) -> &Located<String> {
150        &self.name
151    }
152    /// Returns the complete definition span.
153    #[must_use]
154    pub const fn span(&self) -> SourceSpan {
155        self.span
156    }
157    /// Returns the volume driver.
158    #[must_use]
159    pub const fn driver(&self) -> Option<&Located<String>> {
160        self.driver.as_ref()
161    }
162    /// Returns driver options.
163    #[must_use]
164    pub fn driver_opts(&self) -> &[KeyValueEntry] {
165        &self.driver_opts
166    }
167    /// Returns the complete authored external-lifecycle setting.
168    #[must_use]
169    pub const fn external(&self) -> Option<&ResourceExternal> {
170        self.external.as_ref()
171    }
172    /// Returns labels with their syntax form retained.
173    #[must_use]
174    pub const fn labels(&self) -> Option<&Labels> {
175        self.labels.as_ref()
176    }
177    /// Returns the platform-level custom name.
178    #[must_use]
179    pub const fn custom_name(&self) -> Option<&Located<String>> {
180        self.custom_name.as_ref()
181    }
182    /// Returns retained `x-` fields.
183    #[must_use]
184    pub fn extension_fields(&self) -> &[FieldReference] {
185        &self.extension_fields
186    }
187    /// Returns unrecognized fields.
188    #[must_use]
189    pub fn unknown_fields(&self) -> &[FieldReference] {
190        &self.unknown_fields
191    }
192}
193
194/// A typed top-level config definition.
195#[derive(Debug, Clone, PartialEq, Eq)]
196pub struct ConfigDefinition {
197    name: Located<String>,
198    span: SourceSpan,
199    file: Option<Located<String>>,
200    environment: Option<Located<String>>,
201    content: Option<Located<String>>,
202    external: Option<ResourceExternal>,
203    labels: Option<Labels>,
204    template_driver: Option<Located<String>>,
205    custom_name: Option<Located<String>>,
206    extension_fields: Vec<FieldReference>,
207    unknown_fields: Vec<FieldReference>,
208}
209
210impl ConfigDefinition {
211    pub(crate) fn new(name: Located<String>, span: SourceSpan) -> Self {
212        Self {
213            name,
214            span,
215            file: None,
216            environment: None,
217            content: None,
218            external: None,
219            labels: None,
220            template_driver: None,
221            custom_name: None,
222            extension_fields: Vec::new(),
223            unknown_fields: Vec::new(),
224        }
225    }
226    pub(crate) fn set_file(&mut self, value: Located<String>) {
227        self.file = Some(value);
228    }
229    pub(crate) fn set_environment(&mut self, value: Located<String>) {
230        self.environment = Some(value);
231    }
232    pub(crate) fn set_content(&mut self, value: Located<String>) {
233        self.content = Some(value);
234    }
235    pub(crate) fn set_external(&mut self, value: ResourceExternal) {
236        self.external = Some(value);
237    }
238    pub(crate) fn set_custom_name(&mut self, value: Located<String>) {
239        self.custom_name = Some(value);
240    }
241    pub(crate) fn set_labels(&mut self, value: Labels) {
242        self.labels = Some(value);
243    }
244    pub(crate) fn set_template_driver(&mut self, value: Located<String>) {
245        self.template_driver = Some(value);
246    }
247    pub(crate) fn push_extension(&mut self, value: FieldReference) {
248        self.extension_fields.push(value);
249    }
250    pub(crate) fn push_unknown(&mut self, value: FieldReference) {
251        self.unknown_fields.push(value);
252    }
253
254    /// Returns the model identifier.
255    #[must_use]
256    pub const fn name(&self) -> &Located<String> {
257        &self.name
258    }
259    /// Returns the complete definition span.
260    #[must_use]
261    pub const fn span(&self) -> SourceSpan {
262        self.span
263    }
264    /// Returns the source file path.
265    #[must_use]
266    pub const fn file(&self) -> Option<&Located<String>> {
267        self.file.as_ref()
268    }
269    /// Returns the host environment-variable source name.
270    #[must_use]
271    pub const fn environment(&self) -> Option<&Located<String>> {
272        self.environment.as_ref()
273    }
274    /// Returns inline config content.
275    #[must_use]
276    pub const fn content(&self) -> Option<&Located<String>> {
277        self.content.as_ref()
278    }
279    /// Returns the complete authored external-lifecycle setting.
280    #[must_use]
281    pub const fn external(&self) -> Option<&ResourceExternal> {
282        self.external.as_ref()
283    }
284    /// Returns the platform-level custom name.
285    #[must_use]
286    pub const fn custom_name(&self) -> Option<&Located<String>> {
287        self.custom_name.as_ref()
288    }
289    /// Returns labels with their syntax form retained.
290    #[must_use]
291    pub const fn labels(&self) -> Option<&Labels> {
292        self.labels.as_ref()
293    }
294    /// Returns the opaque config template driver without invoking it.
295    #[must_use]
296    pub const fn template_driver(&self) -> Option<&Located<String>> {
297        self.template_driver.as_ref()
298    }
299    /// Returns retained `x-` fields.
300    #[must_use]
301    pub fn extension_fields(&self) -> &[FieldReference] {
302        &self.extension_fields
303    }
304    /// Returns unrecognized fields.
305    #[must_use]
306    pub fn unknown_fields(&self) -> &[FieldReference] {
307        &self.unknown_fields
308    }
309}
310
311/// A typed top-level secret definition.
312#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct SecretDefinition {
314    name: Located<String>,
315    span: SourceSpan,
316    file: Option<Located<String>>,
317    environment: Option<Located<String>>,
318    driver: Option<Located<String>>,
319    driver_opts: Vec<KeyValueEntry>,
320    labels: Option<Labels>,
321    template_driver: Option<Located<String>>,
322    external: Option<ResourceExternal>,
323    custom_name: Option<Located<String>>,
324    extension_fields: Vec<FieldReference>,
325    unknown_fields: Vec<FieldReference>,
326}
327
328impl SecretDefinition {
329    pub(crate) fn new(name: Located<String>, span: SourceSpan) -> Self {
330        Self {
331            name,
332            span,
333            file: None,
334            environment: None,
335            driver: None,
336            driver_opts: Vec::new(),
337            labels: None,
338            template_driver: None,
339            external: None,
340            custom_name: None,
341            extension_fields: Vec::new(),
342            unknown_fields: Vec::new(),
343        }
344    }
345    pub(crate) fn set_file(&mut self, value: Located<String>) {
346        self.file = Some(value);
347    }
348    pub(crate) fn set_environment(&mut self, value: Located<String>) {
349        self.environment = Some(value);
350    }
351    pub(crate) fn set_driver(&mut self, value: Located<String>) {
352        self.driver = Some(value);
353    }
354    pub(crate) fn set_driver_opts(&mut self, value: Vec<KeyValueEntry>) {
355        self.driver_opts = value;
356    }
357    pub(crate) fn set_labels(&mut self, value: Labels) {
358        self.labels = Some(value);
359    }
360    pub(crate) fn set_template_driver(&mut self, value: Located<String>) {
361        self.template_driver = Some(value);
362    }
363    pub(crate) fn set_external(&mut self, value: ResourceExternal) {
364        self.external = Some(value);
365    }
366    pub(crate) fn set_custom_name(&mut self, value: Located<String>) {
367        self.custom_name = Some(value);
368    }
369    pub(crate) fn push_extension(&mut self, value: FieldReference) {
370        self.extension_fields.push(value);
371    }
372    pub(crate) fn push_unknown(&mut self, value: FieldReference) {
373        self.unknown_fields.push(value);
374    }
375
376    /// Returns the model identifier.
377    #[must_use]
378    pub const fn name(&self) -> &Located<String> {
379        &self.name
380    }
381    /// Returns the complete definition span.
382    #[must_use]
383    pub const fn span(&self) -> SourceSpan {
384        self.span
385    }
386    /// Returns the source file path.
387    #[must_use]
388    pub const fn file(&self) -> Option<&Located<String>> {
389        self.file.as_ref()
390    }
391    /// Returns the host environment-variable source name.
392    #[must_use]
393    pub const fn environment(&self) -> Option<&Located<String>> {
394        self.environment.as_ref()
395    }
396    /// Returns the external-lifecycle setting.
397    /// Returns the opaque secret driver without looking it up.
398    #[must_use]
399    pub const fn driver(&self) -> Option<&Located<String>> {
400        self.driver.as_ref()
401    }
402    /// Returns ordered driver options with string/number scalar fidelity.
403    #[must_use]
404    pub fn driver_opts(&self) -> &[KeyValueEntry] {
405        &self.driver_opts
406    }
407    /// Returns labels with their syntax form retained.
408    #[must_use]
409    pub const fn labels(&self) -> Option<&Labels> {
410        self.labels.as_ref()
411    }
412    /// Returns the opaque secret template driver without invoking it.
413    #[must_use]
414    pub const fn template_driver(&self) -> Option<&Located<String>> {
415        self.template_driver.as_ref()
416    }
417    /// Returns the complete authored external-lifecycle setting.
418    #[must_use]
419    pub const fn external(&self) -> Option<&ResourceExternal> {
420        self.external.as_ref()
421    }
422    /// Returns the platform-level custom name.
423    #[must_use]
424    pub const fn custom_name(&self) -> Option<&Located<String>> {
425        self.custom_name.as_ref()
426    }
427    /// Returns retained `x-` fields.
428    #[must_use]
429    pub fn extension_fields(&self) -> &[FieldReference] {
430        &self.extension_fields
431    }
432    /// Returns unrecognized fields.
433    #[must_use]
434    pub fn unknown_fields(&self) -> &[FieldReference] {
435        &self.unknown_fields
436    }
437}
438
439/// Long syntax shared by service config and secret grants.
440#[derive(Debug, Clone, PartialEq, Eq)]
441pub struct LongGrant {
442    span: SourceSpan,
443    source: Option<Located<String>>,
444    target: Option<Located<String>>,
445    uid: Option<Located<String>>,
446    gid: Option<Located<String>>,
447    mode: Option<Located<String>>,
448    extension_fields: Vec<FieldReference>,
449    unknown_fields: Vec<FieldReference>,
450}
451
452impl LongGrant {
453    pub(crate) fn new(span: SourceSpan) -> Self {
454        Self {
455            span,
456            source: None,
457            target: None,
458            uid: None,
459            gid: None,
460            mode: None,
461            extension_fields: Vec::new(),
462            unknown_fields: Vec::new(),
463        }
464    }
465    pub(crate) fn set_source(&mut self, value: Located<String>) {
466        self.source = Some(value);
467    }
468    pub(crate) fn set_target(&mut self, value: Located<String>) {
469        self.target = Some(value);
470    }
471    pub(crate) fn set_uid(&mut self, value: Located<String>) {
472        self.uid = Some(value);
473    }
474    pub(crate) fn set_gid(&mut self, value: Located<String>) {
475        self.gid = Some(value);
476    }
477    pub(crate) fn set_mode(&mut self, value: Located<String>) {
478        self.mode = Some(value);
479    }
480    pub(crate) fn push_extension(&mut self, value: FieldReference) {
481        self.extension_fields.push(value);
482    }
483    pub(crate) fn push_unknown(&mut self, value: FieldReference) {
484        self.unknown_fields.push(value);
485    }
486
487    /// Returns the complete mapping span.
488    #[must_use]
489    pub const fn span(&self) -> SourceSpan {
490        self.span
491    }
492    /// Returns the referenced resource name.
493    #[must_use]
494    pub const fn source(&self) -> Option<&Located<String>> {
495        self.source.as_ref()
496    }
497    /// Returns the container target.
498    #[must_use]
499    pub const fn target(&self) -> Option<&Located<String>> {
500        self.target.as_ref()
501    }
502    /// Returns the requested user ID spelling.
503    #[must_use]
504    pub const fn uid(&self) -> Option<&Located<String>> {
505        self.uid.as_ref()
506    }
507    /// Returns the requested group ID spelling.
508    #[must_use]
509    pub const fn gid(&self) -> Option<&Located<String>> {
510        self.gid.as_ref()
511    }
512    /// Returns the requested permission-mode spelling.
513    #[must_use]
514    pub const fn mode(&self) -> Option<&Located<String>> {
515        self.mode.as_ref()
516    }
517    /// Returns retained `x-` fields.
518    #[must_use]
519    pub fn extension_fields(&self) -> &[FieldReference] {
520        &self.extension_fields
521    }
522    /// Returns unrecognized fields.
523    #[must_use]
524    pub fn unknown_fields(&self) -> &[FieldReference] {
525        &self.unknown_fields
526    }
527}
528
529/// A service config grant with its syntax form retained.
530#[derive(Debug, Clone, PartialEq, Eq)]
531pub enum ConfigGrant {
532    /// Config-name short syntax.
533    Short(Located<String>),
534    /// Mapping-based long syntax.
535    Long(Box<LongGrant>),
536}
537
538/// A service secret grant with its syntax form retained.
539#[derive(Debug, Clone, PartialEq, Eq)]
540pub enum SecretGrant {
541    /// Secret-name short syntax.
542    Short(Located<String>),
543    /// Mapping-based long syntax.
544    Long(Box<LongGrant>),
545}