tauri_utils/
assets.rs

1// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5//! Assets handled by Tauri during compile time and runtime.
6
7#[doc(hidden)]
8pub use phf;
9use std::{
10  borrow::Cow,
11  path::{Component, Path},
12};
13
14/// Represent an asset file path in a normalized way.
15///
16/// The following rules are enforced and added if needed:
17/// * Unix path component separators
18/// * Has a root directory
19/// * No trailing slash - directories are not included in assets
20#[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    // TODO: change this to utilize `Cow` to prevent allocating an intermediate `PathBuf` when not necessary
38    let path = path.as_ref().to_owned();
39
40    // add in root to mimic how it is used from a server url
41    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      // remove the last slash
63      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
76/// Represents a container of file assets that are retrievable during runtime.
77pub trait Assets: Send + Sync + 'static {
78  /// Get the content of the passed [`AssetKey`].
79  fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>>;
80}
81
82/// [`Assets`] implementation that only contains compile-time compressed and embedded assets.
83#[derive(Debug)]
84pub struct EmbeddedAssets(phf::Map<&'static str, &'static [u8]>);
85
86impl EmbeddedAssets {
87  /// Wrap a [zstd] compressed [`phf::Map`].
88  ///
89  /// [zstd]: https://facebook.github.io/zstd/
90  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}