release_kit/release/
embedded.rs1use std::collections::HashMap;
10use std::sync::OnceLock;
11
12use crate::digest::Digest;
13use crate::embedded;
14use crate::error::RkError;
15
16use super::{Artifact, PAYLOAD_SCHEMA, ReleaseManifest, ReleaseSource, unknown_digest};
17
18#[derive(Debug, Default, Clone, Copy)]
20pub struct EmbeddedReleaseSource;
21
22fn manifest() -> &'static ReleaseManifest {
24 static MANIFEST: OnceLock<ReleaseManifest> = OnceLock::new();
25 MANIFEST.get_or_init(|| {
26 let artifacts = embedded::artifacts()
27 .into_iter()
28 .map(|(path, bytes)| Artifact {
29 path,
30 sha256: Digest::of(bytes),
31 })
32 .collect();
33 ReleaseManifest::new(
34 env!("CARGO_PKG_VERSION").to_owned(),
35 PAYLOAD_SCHEMA,
36 artifacts,
37 )
38 })
39}
40
41fn blobs() -> &'static HashMap<Digest, &'static [u8]> {
43 static BLOBS: OnceLock<HashMap<Digest, &'static [u8]>> = OnceLock::new();
44 BLOBS.get_or_init(|| {
45 embedded::artifacts()
46 .into_iter()
47 .map(|(_, bytes)| (Digest::of(bytes), bytes))
48 .collect()
49 })
50}
51
52impl EmbeddedReleaseSource {
53 #[must_use]
55 pub fn manifest_ref() -> &'static ReleaseManifest {
56 manifest()
57 }
58}
59
60impl ReleaseSource for EmbeddedReleaseSource {
61 fn manifest(&self) -> Result<ReleaseManifest, RkError> {
62 Ok(manifest().clone())
63 }
64
65 fn blob(&self, digest: &Digest) -> Result<Vec<u8>, RkError> {
66 blobs()
67 .get(digest)
68 .map(|bytes| bytes.to_vec())
69 .ok_or_else(|| unknown_digest(digest))
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::EmbeddedReleaseSource;
76 use crate::digest::Digest;
77 use crate::release::ReleaseSource;
78
79 #[test]
80 fn the_embedded_source_serves_every_artifact_it_names() {
81 let source = EmbeddedReleaseSource;
82 let manifest = source
83 .manifest()
84 .expect("the embedded bundle describes itself");
85 assert_eq!(manifest.release_kit_version, env!("CARGO_PKG_VERSION"));
86 assert_eq!(manifest.payload_schema, crate::release::PAYLOAD_SCHEMA);
87 assert!(!manifest.artifacts.is_empty());
88 for artifact in &manifest.artifacts {
89 let bytes = source.blob(&artifact.sha256).expect("a named blob reads");
90 assert_eq!(Digest::of(&bytes), artifact.sha256, "{}", artifact.path);
91 }
92 assert!(source.blob(&Digest::of(b"absent")).is_err());
93 }
94}