Skip to main content

asimov_patterns/programs/
runner.rs

1// This is free and unencumbered software released into the public domain.
2
3//! Language-runtime execution: the runner marker trait and named definitions.
4
5use crate::Execute;
6use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
7use bon::Builder;
8
9/// A language runtime that executes program text and emits its result as text.
10///
11/// The program defines its language and version, input grammar and encoding,
12/// how definitions are exposed to code, and how results are represented.
13/// Executing code can have external side effects; the pattern does not imply
14/// sandboxing, determinism, or rollback after failure.
15///
16/// # Command-line contract
17///
18/// `PROGRAM [OPTIONS] [INPUT-FILE]`
19///
20/// The program file defaults to `-` (stdin); the execution result goes to
21/// stdout. [`RunnerOptions::define`] supplies runtime variables through the
22/// repeatable `--define=VAR=VAL` option. No standard input/output-format
23/// options or output-file operand are defined for this pattern.
24///
25/// `T` is the implementation's result representation. This trait identifies the
26/// language-runtime role, not generic process launching. See [`crate::programs`]
27/// for links to concrete execution behavior and the [runner specification][spec].
28///
29/// [spec]: https://asimov-specs.github.io/program-patterns/#runner
30pub trait Runner<T>: Execute<T> {}
31
32/// Runtime variable definitions and additional arguments for a [`Runner`].
33///
34/// `Default` creates an empty definition map and argument list. The map holds
35/// at most one value per name and is forwarded in key order, not insertion
36/// order. Values are stored without validating the selected runtime's naming
37/// or value rules.
38///
39/// # Examples
40///
41/// ```rust
42/// use asimov_patterns::RunnerOptions;
43///
44/// let options = RunnerOptions::builder()
45///     .define("mode", "preview")
46///     .define("expression", "a=b")
47///     .build();
48///
49/// assert_eq!(options.define.get("expression").map(String::as_str), Some("a=b"));
50/// ```
51#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Builder)]
52#[builder(derive(Debug), on(String, into))]
53pub struct RunnerOptions {
54    /// Additional arguments appended after definitions, including an optional program file.
55    ///
56    /// Each string is one literal argument, without shell expansion. To express
57    /// ordered or repeated `--define` arguments that the map cannot represent,
58    /// put them here and leave those keys out of [`define`](Self::define).
59    /// The program's documented duplicate-definition policy then applies.
60    /// See [`crate::programs`] for option and operand ordering.
61    #[builder(field)]
62    pub other: Vec<String>,
63
64    /// Named runtime values passed as `--define=VAR=VAL` (`-D` in the CLI).
65    ///
66    /// The runner emits one argument per entry in [`BTreeMap`] key order. The
67    /// program splits the argument value at its first `=`: names must be
68    /// nonempty and cannot contain `=`, while values may be empty or contain
69    /// additional `=` characters. These constraints are not checked here.
70    ///
71    /// Replacing a key in this map replaces its previous value before execution;
72    /// it does not send duplicate definitions to the program. Definitions are
73    /// runtime arguments, not environment-variable assignments or shell source.
74    #[builder(field)]
75    pub define: BTreeMap<String, String>,
76}
77
78impl<S: runner_options_builder::State> RunnerOptionsBuilder<S> {
79    /// Appends one literal argument to [`RunnerOptions::other`], preserving order.
80    pub fn other(mut self, flag: impl Into<String>) -> Self {
81        self.other.push(flag.into());
82        self
83    }
84
85    /// Appends a present argument to [`RunnerOptions::other`]; `None` adds nothing.
86    pub fn maybe_other(mut self, flag: Option<impl Into<String>>) -> Self {
87        if let Some(flag) = flag {
88            self.other.push(flag.into());
89        }
90        self
91    }
92
93    /// Inserts a runtime definition, replacing any earlier value for the same key.
94    ///
95    /// Calls for different keys accumulate in [`RunnerOptions::define`], which
96    /// is emitted in key order. Neither the name nor the value is validated.
97    pub fn define(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
98        self.define.insert(key.into(), val.into());
99        self
100    }
101}