1use std::collections::BTreeMap;
11use std::sync::Arc;
12
13use blockworx_doc::{block_model::Asset, hash::AssetHash};
14
15#[derive(Default)]
18pub struct ImageRegistry(BTreeMap<AssetHash, Arc<str>>);
19
20impl ImageRegistry {
21 pub fn register(&mut self, ctx: &egui::Context, hash: AssetHash, asset: &Asset) {
24 if self.0.contains_key(&hash) {
25 return;
26 }
27 let ext = match asset {
28 Asset::Svg(_) => "svg",
29 Asset::Png(_) => "png",
30 };
31 let uri: Arc<str> = Arc::from(format!("bytes://image-{hash}.{ext}"));
32 ctx.include_bytes(uri.to_string(), asset.bytes().to_vec());
33 self.0.insert(hash, uri);
34 }
35
36 pub fn uri(&self, hash: AssetHash) -> Option<&Arc<str>> {
38 self.0.get(&hash)
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn register_is_keyed_by_the_hash_and_carries_the_format() {
48 let ctx = egui::Context::default();
49 let mut reg = ImageRegistry::default();
50 let svg = Asset::Svg(r#"<svg viewBox="0 0 20 10"></svg>"#.as_bytes().into());
51 let png = Asset::Png(b"\x89PNG\r\n\x1a\n".as_slice().into());
52 assert!(
53 reg.uri(svg.hash()).is_none(),
54 "precondition: nothing registered yet"
55 );
56
57 reg.register(&ctx, svg.hash(), &svg);
58 let first = reg.uri(svg.hash()).expect("the SVG is registered").clone();
59 assert!(
60 first.ends_with(".svg"),
61 "the URI does not name the format: {first}"
62 );
63
64 reg.register(&ctx, svg.hash(), &svg);
65 assert_eq!(
66 reg.uri(svg.hash()),
67 Some(&first),
68 "a second registration of the same hash minted a new URI",
69 );
70
71 reg.register(&ctx, png.hash(), &png);
72 let png_uri = reg.uri(png.hash()).expect("the PNG is registered");
73 assert!(
74 png_uri.ends_with(".png"),
75 "the URI does not name the format: {png_uri}"
76 );
77 assert_ne!(png_uri, &first);
78 }
79}