Skip to main content

asimov_patterns/programs/
emitter.rs

1// This is free and unencumbered software released into the public domain.
2
3//! Input-free RDF generation: the emitter marker trait and options.
4
5use crate::Execute;
6use alloc::{string::String, vec::Vec};
7use bon::Builder;
8
9/// A value generator that produces RDF without consuming a payload input.
10///
11/// Arguments, configuration, the environment, or external sources determine
12/// the generated values. Generation may be finite or continuous and need not
13/// be deterministic. A finite emitter can succeed with an empty RDF result.
14///
15/// # Command-line contract
16///
17/// `PROGRAM [OPTIONS]`
18///
19/// There are no standard positional operands, and the program must not wait
20/// for stdin. RDF is written to stdout in the format selected by
21/// [`EmitterOptions::output`] (`jsonl` by default).
22///
23/// Implementations document termination conditions and how `T` exposes output.
24/// See [`crate::programs`] for shared conventions and links to concrete execution
25/// behavior, and the
26/// [emitter specification][spec] for the external contract.
27///
28/// [spec]: https://asimov-specs.github.io/program-patterns/#emitter
29pub trait Emitter<T>: Execute<T> {}
30
31/// Output-format selection and additional arguments for an [`Emitter`].
32///
33/// `Default` requests the program's defaults by leaving `output` unset and
34/// `other` empty. These options do not define the generated values, bound the
35/// execution time, or validate the selected program's capabilities.
36///
37/// # Examples
38///
39/// ```rust
40/// use asimov_patterns::EmitterOptions;
41///
42/// let options = EmitterOptions::builder()
43///     .output("jsonl")
44///     .build();
45/// ```
46#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Builder)]
47#[builder(derive(Debug), on(String, into))]
48pub struct EmitterOptions {
49    /// Additional arguments appended after the generated output-format option.
50    ///
51    /// Each string is one literal argument, without shell expansion. The
52    /// standard pattern has no positional operands; extensions require support
53    /// from the selected program. See [`crate::programs`].
54    #[builder(field)]
55    pub other: Vec<String>,
56
57    /// RDF serialization passed as `--output=FORMAT` (`-o` in the CLI).
58    ///
59    /// `None` omits the option; the specified program default is `jsonl`.
60    /// This does not select a file, capture policy, or RDF mapping profile.
61    pub output: Option<String>,
62}
63
64impl<S: emitter_options_builder::State> EmitterOptionsBuilder<S> {
65    /// Appends one literal argument to [`EmitterOptions::other`], preserving order.
66    pub fn other(mut self, flag: impl Into<String>) -> Self {
67        self.other.push(flag.into());
68        self
69    }
70
71    /// Appends a present argument to [`EmitterOptions::other`]; `None` adds nothing.
72    pub fn maybe_other(mut self, flag: Option<impl Into<String>>) -> Self {
73        if let Some(flag) = flag {
74            self.other.push(flag.into());
75        }
76        self
77    }
78}