Skip to main content

asimov_patterns/programs/
fetcher.rs

1// This is free and unencumbered software released into the public domain.
2
3//! URL-to-RDF retrieval: the fetcher marker trait and options.
4
5use crate::Execute;
6use alloc::{string::String, vec::Vec};
7use bon::Builder;
8
9/// A URL protocol client that retrieves one resource and represents it as RDF.
10///
11/// The program defines supported URL schemes and the mapping from retrieved
12/// content to RDF. A single resource may produce many RDF statements. Returning
13/// arbitrary response bytes alone does not fulfill the RDF output contract.
14///
15/// # Command-line contract
16///
17/// `PROGRAM [OPTIONS] INPUT-URL`
18///
19/// One absolute URL is required as a single argument; it is not a stdin
20/// payload or an implicitly converted local pathname. RDF is written to stdout
21/// using [`FetcherOptions::output`] (`jsonl` by default). The program validates
22/// the URL and rejects unsupported schemes.
23///
24/// `T` is the implementation's result representation. Retrieval, redirects,
25/// authentication, caching, and resource-to-RDF mapping belong to the program.
26/// See [`crate::programs`] for links to concrete execution behavior and the
27/// [fetcher specification][spec].
28///
29/// [spec]: https://asimov-specs.github.io/program-patterns/#fetcher
30pub trait Fetcher<T>: Execute<T> {}
31
32/// Output-format selection and additional arguments for a [`Fetcher`].
33///
34/// The URL is supplied separately by the implementation's invocation API.
35/// `Default` leaves `output` unset and `other` empty; format support and URL
36/// validity are not checked by this configuration type.
37///
38/// # Examples
39///
40/// ```rust
41/// use asimov_patterns::FetcherOptions;
42///
43/// let options = FetcherOptions::builder()
44///     .output("jsonl")
45///     .build();
46/// ```
47#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Builder)]
48#[builder(derive(Debug), on(String, into))]
49pub struct FetcherOptions {
50    /// Additional arguments placed after generated options and before the URL.
51    ///
52    /// Each string is one literal argument, without shell expansion. The runner
53    /// supplies the URL separately; do not duplicate it here. 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 names a serialization, not a file or a raw-response retrieval mode.
61    pub output: Option<String>,
62}
63
64impl<S: fetcher_options_builder::State> FetcherOptionsBuilder<S> {
65    /// Appends one literal argument to [`FetcherOptions::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 [`FetcherOptions::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}