1#[doc(hidden)]
8pub use phf;
9use std::{
10 borrow::Cow,
11 path::{Component, Path},
12};
13
14#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
21pub struct AssetKey(String);
22
23impl From<AssetKey> for String {
24 fn from(key: AssetKey) -> Self {
25 key.0
26 }
27}
28
29impl AsRef<str> for AssetKey {
30 fn as_ref(&self) -> &str {
31 &self.0
32 }
33}
34
35impl<P: AsRef<Path>> From<P> for AssetKey {
36 fn from(path: P) -> Self {
37 let path = path.as_ref().to_owned();
39
40 let path = if path.has_root() {
42 path
43 } else {
44 Path::new(&Component::RootDir).join(path)
45 };
46
47 let buf = if cfg!(windows) {
48 let mut buf = String::new();
49 for component in path.components() {
50 match component {
51 Component::RootDir => buf.push('/'),
52 Component::CurDir => buf.push_str("./"),
53 Component::ParentDir => buf.push_str("../"),
54 Component::Prefix(prefix) => buf.push_str(&prefix.as_os_str().to_string_lossy()),
55 Component::Normal(s) => {
56 buf.push_str(&s.to_string_lossy());
57 buf.push('/')
58 }
59 }
60 }
61
62 if buf != "/" {
64 buf.pop();
65 }
66
67 buf
68 } else {
69 path.to_string_lossy().to_string()
70 };
71
72 AssetKey(buf)
73 }
74}
75
76pub trait Assets: Send + Sync + 'static {
78 fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>>;
80}
81
82#[derive(Debug)]
84pub struct EmbeddedAssets(phf::Map<&'static str, &'static [u8]>);
85
86impl EmbeddedAssets {
87 pub const fn from_zstd(map: phf::Map<&'static str, &'static [u8]>) -> Self {
91 Self(map)
92 }
93}
94
95impl Assets for EmbeddedAssets {
96 fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
97 self
98 .0
99 .get(key.as_ref())
100 .copied()
101 .map(zstd::decode_all)
102 .and_then(Result::ok)
103 .map(Cow::Owned)
104 }
105}