Skip to main content

sim_run_loaders/
source.rs

1//! Loader-defined library source kinds and payload helpers.
2//!
3//! The kernel carries open source kinds as `(kind, payload)` data. This module
4//! defines the source kinds understood by the standard loader family and keeps
5//! their payload grammar with the loaders that interpret it.
6
7use std::path::{Path, PathBuf};
8
9#[cfg(unix)]
10use std::{
11    ffi::OsString,
12    os::unix::ffi::{OsStrExt, OsStringExt},
13};
14
15use sim_kernel::{CatalogSource, Datum, Error, LibSource, LibSourceSpec, Result, Symbol};
16
17/// Loader-defined kind for local filesystem paths.
18pub const PATH_SOURCE_KIND: &str = "path";
19/// Loader-defined kind for remote URLs.
20pub const URL_SOURCE_KIND: &str = "url";
21/// Loader-defined kind for in-memory artifact bytes.
22pub const BYTES_SOURCE_KIND: &str = "bytes";
23/// Loader-defined kind for content-addressed library artifacts.
24pub const CONTENT_ADDRESS_SOURCE_KIND: &str = "content-address";
25
26/// Returns the local path source kind symbol.
27pub fn path_source_kind() -> Symbol {
28    Symbol::new(PATH_SOURCE_KIND)
29}
30
31/// Returns the URL source kind symbol.
32pub fn url_source_kind() -> Symbol {
33    Symbol::new(URL_SOURCE_KIND)
34}
35
36/// Returns the bytes source kind symbol.
37pub fn bytes_source_kind() -> Symbol {
38    Symbol::new(BYTES_SOURCE_KIND)
39}
40
41/// Returns the content-addressed source kind symbol.
42pub fn content_address_source_kind() -> Symbol {
43    Symbol::new(CONTENT_ADDRESS_SOURCE_KIND)
44}
45
46/// Builds a live kernel source for a local path.
47pub fn path_source(path: impl Into<PathBuf>) -> LibSource {
48    LibSource::open(path_source_kind(), path_payload(path.into()))
49}
50
51/// Builds a boot-recordable kernel source spec for a local path.
52pub fn path_source_spec(path: impl Into<PathBuf>) -> LibSourceSpec {
53    LibSourceSpec::open(path_source_kind(), path_payload(path.into()))
54}
55
56/// Builds a catalog source for a local path.
57pub fn catalog_path_source(path: impl Into<PathBuf>) -> CatalogSource {
58    CatalogSource::open(path_source_kind(), path_payload(path.into()))
59}
60
61/// Builds a live kernel source for a URL.
62pub fn url_source(url: impl Into<String>) -> LibSource {
63    LibSource::open(url_source_kind(), Datum::String(url.into()))
64}
65
66/// Builds a boot-recordable kernel source spec for a URL.
67pub fn url_source_spec(url: impl Into<String>) -> LibSourceSpec {
68    LibSourceSpec::open(url_source_kind(), Datum::String(url.into()))
69}
70
71/// Builds a catalog source for a URL.
72pub fn catalog_url_source(url: impl Into<String>) -> CatalogSource {
73    CatalogSource::open(url_source_kind(), Datum::String(url.into()))
74}
75
76/// Builds a live kernel source for in-memory artifact bytes.
77pub fn bytes_source(bytes: impl Into<Vec<u8>>) -> LibSource {
78    LibSource::open(bytes_source_kind(), Datum::Bytes(bytes.into()))
79}
80
81/// Builds a boot-recordable kernel source spec for in-memory artifact bytes.
82pub fn bytes_source_spec(bytes: impl Into<Vec<u8>>) -> LibSourceSpec {
83    LibSourceSpec::open(bytes_source_kind(), Datum::Bytes(bytes.into()))
84}
85
86/// Builds a catalog source for in-memory artifact bytes.
87pub fn catalog_bytes_source(bytes: impl Into<Vec<u8>>) -> CatalogSource {
88    CatalogSource::open(bytes_source_kind(), Datum::Bytes(bytes.into()))
89}
90
91/// Builds a live kernel source for a content-addressed artifact payload.
92pub fn content_address_source(payload: Datum) -> LibSource {
93    LibSource::open(content_address_source_kind(), payload)
94}
95
96/// Builds a boot-recordable kernel source spec for content-addressed artifacts.
97pub fn content_address_source_spec(payload: Datum) -> LibSourceSpec {
98    LibSourceSpec::open(content_address_source_kind(), payload)
99}
100
101/// Builds a catalog source for content-addressed artifacts.
102pub fn catalog_content_address_source(payload: Datum) -> CatalogSource {
103    CatalogSource::open(content_address_source_kind(), payload)
104}
105
106/// Returns whether a live source has the local path kind.
107pub fn is_path_source(source: &LibSource) -> bool {
108    open_payload(source, &path_source_kind()).is_some()
109}
110
111/// Returns whether a live source has the URL kind.
112pub fn is_url_source(source: &LibSource) -> bool {
113    open_payload(source, &url_source_kind()).is_some()
114}
115
116/// Returns whether a live source has the bytes kind.
117pub fn is_bytes_source(source: &LibSource) -> bool {
118    open_payload(source, &bytes_source_kind()).is_some()
119}
120
121/// Decodes a local path payload from a live source.
122pub fn path_from_source(source: &LibSource) -> Result<Option<PathBuf>> {
123    open_payload(source, &path_source_kind())
124        .map(path_from_payload)
125        .transpose()
126}
127
128/// Decodes a URL payload from a live source.
129pub fn url_from_source(source: &LibSource) -> Result<Option<String>> {
130    open_payload(source, &url_source_kind())
131        .map(url_from_payload)
132        .transpose()
133}
134
135/// Decodes an in-memory byte payload from a live source.
136pub fn bytes_from_source(source: &LibSource) -> Result<Option<Vec<u8>>> {
137    open_payload(source, &bytes_source_kind())
138        .map(bytes_from_payload)
139        .transpose()
140}
141
142/// Decodes the opaque content-address payload from a live source.
143pub fn content_address_payload(source: &LibSource) -> Option<&Datum> {
144    open_payload(source, &content_address_source_kind())
145}
146
147/// Encodes a local path as a loader-defined payload.
148pub fn path_payload(path: impl AsRef<Path>) -> Datum {
149    #[cfg(unix)]
150    {
151        Datum::Bytes(path.as_ref().as_os_str().as_bytes().to_vec())
152    }
153
154    #[cfg(not(unix))]
155    {
156        Datum::String(path.as_ref().to_string_lossy().into_owned())
157    }
158}
159
160/// Decodes a local path from a loader-defined payload.
161pub fn path_from_payload(payload: &Datum) -> Result<PathBuf> {
162    match payload {
163        Datum::String(path) => Ok(PathBuf::from(path)),
164        #[cfg(unix)]
165        Datum::Bytes(bytes) => Ok(PathBuf::from(OsString::from_vec(bytes.clone()))),
166        #[cfg(not(unix))]
167        Datum::Bytes(_) => Err(Error::HostError(
168            "path source byte payloads are only supported on unix".to_owned(),
169        )),
170        other => Err(Error::TypeMismatch {
171            expected: "path source string or bytes",
172            found: datum_kind(other),
173        }),
174    }
175}
176
177/// Decodes a URL from a loader-defined payload.
178pub fn url_from_payload(payload: &Datum) -> Result<String> {
179    string_payload(payload)
180}
181
182/// Decodes in-memory artifact bytes from a loader-defined payload.
183pub fn bytes_from_payload(payload: &Datum) -> Result<Vec<u8>> {
184    bytes_payload(payload)
185}
186
187fn open_payload<'a>(source: &'a LibSource, expected_kind: &Symbol) -> Option<&'a Datum> {
188    match source {
189        LibSource::Open { kind, payload } if kind == expected_kind => Some(payload),
190        _ => None,
191    }
192}
193
194fn string_payload(payload: &Datum) -> Result<String> {
195    match payload {
196        Datum::String(value) => Ok(value.clone()),
197        other => Err(Error::TypeMismatch {
198            expected: "source string",
199            found: datum_kind(other),
200        }),
201    }
202}
203
204fn bytes_payload(payload: &Datum) -> Result<Vec<u8>> {
205    match payload {
206        Datum::Bytes(value) => Ok(value.clone()),
207        other => Err(Error::TypeMismatch {
208            expected: "source bytes",
209            found: datum_kind(other),
210        }),
211    }
212}
213
214fn datum_kind(datum: &Datum) -> &'static str {
215    match datum {
216        Datum::Nil => "datum nil",
217        Datum::Bool(_) => "datum bool",
218        Datum::Number(_) => "datum number",
219        Datum::Symbol(_) => "datum symbol",
220        Datum::String(_) => "datum string",
221        Datum::Bytes(_) => "datum bytes",
222        Datum::List(_) => "datum list",
223        Datum::Vector(_) => "datum vector",
224        Datum::Map(_) => "datum map",
225        Datum::Set(_) => "datum set",
226        Datum::Node { .. } => "datum node",
227    }
228}