Skip to main content

asimov_patterns/programs/
reader.rs

1// This is free and unencumbered software released into the public domain.
2
3//! RDF import: the reader marker trait and source/output format options.
4
5use crate::Execute;
6use alloc::{string::String, vec::Vec};
7use bon::Builder;
8
9/// An importer that maps a document or byte stream into an RDF graph or dataset.
10///
11/// Source data may use an RDF or non-RDF format. The program defines supported
12/// inputs and their mappings, including vocabulary, base-IRI handling, and
13/// identifier generation. This role describes a data-import operation, not an
14/// implementation of Rust's byte-reading traits.
15///
16/// # Command-line contract
17///
18/// `PROGRAM [OPTIONS] [INPUT-FILE [OUTPUT-FILE]]`
19///
20/// Input and output default to stdin and stdout. A single operand selects
21/// input; two select input then output, with `-` denoting a standard stream.
22/// [`ReaderOptions`] defaults to automatic input-format detection and `jsonl`
23/// output. The program must document its detection procedure and fail if it
24/// cannot select a supported input format.
25///
26/// `T` is the implementation's imported-result representation. See
27/// [`crate::programs`] for links to concrete execution behavior and the
28/// [reader specification][spec].
29///
30/// [spec]: https://asimov-specs.github.io/program-patterns/#reader
31pub trait Reader<T>: Execute<T> {}
32
33/// Source and RDF output formats for a [`Reader`], plus additional arguments.
34///
35/// `Default` leaves formats unset and `other` empty, delegating detection and
36/// output defaults to the program. Configuration does not perform detection,
37/// validate format support, or transform the input.
38///
39/// # Examples
40///
41/// ```rust
42/// use asimov_patterns::ReaderOptions;
43///
44/// let options = ReaderOptions::builder()
45///     .input("auto")
46///     .output("jsonl")
47///     .build();
48/// ```
49#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Builder)]
50#[builder(derive(Debug), on(String, into))]
51pub struct ReaderOptions {
52    /// Additional arguments, including optional source and RDF output file operands.
53    ///
54    /// The wrapper appends these after generated format options. Put extension
55    /// options before files; each string is one literal argument. See
56    /// [`crate::programs`] for operand ordering and standard-stream selection.
57    #[builder(field)]
58    pub other: Vec<String>,
59
60    /// Source format passed as `--input=FORMAT` (`-i` in the CLI).
61    ///
62    /// `None` omits the option; the specified default is `auto`, requesting the
63    /// program's documented detection procedure. An explicit concrete format
64    /// takes precedence over detection. This is not an input filename.
65    pub input: Option<String>,
66
67    /// RDF serialization passed as `--output=FORMAT` (`-o` in the CLI).
68    ///
69    /// `None` omits the option; the specified program default is `jsonl`.
70    /// This selects a serialization, not an output file or a source-to-RDF mapping.
71    pub output: Option<String>,
72}
73
74impl<S: reader_options_builder::State> ReaderOptionsBuilder<S> {
75    /// Appends one literal argument to [`ReaderOptions::other`], preserving order.
76    pub fn other(mut self, flag: impl Into<String>) -> Self {
77        self.other.push(flag.into());
78        self
79    }
80
81    /// Appends a present argument to [`ReaderOptions::other`]; `None` adds nothing.
82    pub fn maybe_other(mut self, flag: Option<impl Into<String>>) -> Self {
83        if let Some(flag) = flag {
84            self.other.push(flag.into());
85        }
86        self
87    }
88}