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}