Files
pkh/src/data.rs
T

73 lines
3.4 KiB
Rust

//! Embedding convention for the static reference data files (`data/*.yml`)
//!
//! Reference data that changes independently of the code — distro series
//! pointers, pinned SSH host keys, package quirks — lives in YAML files
//! under `data/` at the repo root instead of hardcoded in the source, so
//! it is updatable in one reviewable place.
//!
//! This module is deliberately not a central registry: each file is
//! embedded by the module that owns it (distro_info.rs owns
//! data/distro_info.yml, launchpad.rs owns data/launchpad.yml,
//! apt/keyring.rs owns data/keyserver.yml, put/ssh.rs owns
//! data/host_keys.yml, quirks.rs owns data/quirks.yml) through the
//! [`embed_data!`] macro below, so data
//! and its accessors stay together and a diff touching one domain cannot
//! half-touch another. The macro embeds the file at compile time and
//! parses it once into a `lazy_static` on first use; since the data ships
//! inside the binary, a parse failure is a build-time bug that cannot be
//! recovered from at runtime, and the macro panics on it.
//!
//! Paths and URLs in the data files carry their variable parts as `{name}`
//! placeholders, substituted with `str::replace` at the use site — no
//! template engine.
/// Embed one YAML data file as a lazily-parsed static, following the
/// convention documented at the module level.
///
/// Takes the visibility of the generated static (none for private, `pub` or
/// `pub(crate)`-style), its name, its struct type (which stays defined in
/// the owning module, next to its accessors) and the file path relative to
/// the invoking source file (`"../data/distro_info.yml"` from
/// `src/distro_info.rs`, `"../../data/host_keys.yml"` from
/// `src/put/ssh.rs`, ...), and expands to the house `include_str!` →
/// `lazy_static` → parse pattern — only the embed+parse boilerplate is
/// generated.
///
/// ```ignore
/// embed_data! {
/// static ref MY_DATA: MyData = "../data/my_data.yml"
/// }
/// ```
macro_rules! embed_data {
// Internal arm: the visibility arrives wrapped in parentheses (empty for
// private statics) because `lazy_static!` only re-matches literal
// `pub`/`pub(...)` token sequences, not an opaque forwarded `vis`.
(@expand ($($vis:tt)*) static ref $name:ident : $ty:ty = $path:literal) => {
lazy_static::lazy_static! {
// The YAML is include_str!'d at compile time and statically
// valid; if it ever failed to parse it would be a build-time bug
// that cannot be recovered from at runtime, so panicking here is
// acceptable.
$($vis)* static ref $name: $ty = serde_yaml::from_str(include_str!($path))
.expect(concat!(
"built-in ",
$path,
" data is statically valid and must parse"
));
}
};
(static ref $name:ident : $ty:ty = $path:literal) => {
$crate::data::embed_data!(@expand () static ref $name : $ty = $path);
};
(pub static ref $name:ident : $ty:ty = $path:literal) => {
$crate::data::embed_data!(@expand (pub) static ref $name : $ty = $path);
};
(pub ($($vis:tt)+) static ref $name:ident : $ty:ty = $path:literal) => {
$crate::data::embed_data!(@expand (pub ($($vis)+)) static ref $name : $ty = $path);
};
}
/// Makes the macro available through the module path
/// (`use crate::data::embed_data;`)
pub(crate) use embed_data;