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))]
48#[cfg_attr(feature = "clap", derive(clap::Args))]
49pub struct EmitterOptions {
50    /// Additional arguments appended after the generated output-format option.
51    ///
52    /// Each string is one literal argument, without shell expansion. The
53    /// standard pattern has no positional operands; extensions require support
54    /// from the selected program. See [`crate::programs`].
55    #[builder(field)]
56    pub other: Vec<String>,
57
58    /// RDF serialization passed as `--output=FORMAT` (`-o` in the CLI).
59    ///
60    /// `None` omits the option; the specified program default is `jsonl`.
61    /// This does not select a file, capture policy, or RDF mapping profile.
62    pub output: Option<String>,
63}
64
65impl<S: emitter_options_builder::State> EmitterOptionsBuilder<S> {
66    /// Appends one literal argument to [`EmitterOptions::other`], preserving order.
67    pub fn other(mut self, flag: impl Into<String>) -> Self {
68        self.other.push(flag.into());
69        self
70    }
71
72    /// Appends a present argument to [`EmitterOptions::other`]; `None` adds nothing.
73    pub fn maybe_other(mut self, flag: Option<impl Into<String>>) -> Self {
74        if let Some(flag) = flag {
75            self.other.push(flag.into());
76        }
77        self
78    }
79}