use std::ops;
use crate::DataSource;
#[derive(Debug)]
pub struct Embeds {
#[doc(hidden)]
pub entries: &'static [EmbeddedEntry],
}
#[derive(Debug)]
#[non_exhaustive]
pub enum EmbeddedEntry {
Single(EmbeddedFile),
Glob(EmbeddedGlob),
}
#[derive(Debug)]
pub struct EmbeddedGlob {
#[doc(hidden)]
pub pattern: &'static str,
#[doc(hidden)]
pub files: &'static [EmbeddedFile],
#[cfg(dev_mode)]
#[doc(hidden)]
pub base_path: &'static str,
}
#[derive(Debug)]
pub struct EmbeddedFile {
#[doc(hidden)]
pub path: &'static str,
#[cfg(dev_mode)]
#[doc(hidden)]
pub full_path: &'static str,
#[cfg(prod_mode)]
#[doc(hidden)]
pub content: &'static [u8],
#[cfg(prod_mode)]
#[doc(hidden)]
pub compressed: bool,
}
impl Embeds {
pub fn entries(&self) -> impl Iterator<Item = &'static EmbeddedEntry> {
self.entries.iter()
}
pub fn get(&self, embed_pattern: &str) -> Option<&EmbeddedEntry> {
self.entries.iter().find(|entry| entry.embed_pattern() == embed_pattern)
}
}
impl ops::Index<&str> for Embeds {
type Output = EmbeddedEntry;
fn index(&self, index: &str) -> &Self::Output {
self.get(index)
.unwrap_or_else(|| panic!("no embedded entry found with '{}'", index))
}
}
impl EmbeddedEntry {
pub fn embed_pattern(&self) -> &'static str {
match self {
EmbeddedEntry::Single(f) => f.path(),
EmbeddedEntry::Glob(g) => g.pattern(),
}
}
pub fn as_glob(&self) -> Option<&EmbeddedGlob> {
match self {
EmbeddedEntry::Glob(g) => Some(g),
_ => None,
}
}
pub fn as_file(&self) -> Option<&EmbeddedFile> {
match self {
EmbeddedEntry::Single(f) => Some(f),
_ => None,
}
}
pub fn files(&self) -> impl Iterator<Item = &EmbeddedFile> {
match self {
EmbeddedEntry::Single(f) => std::slice::from_ref(f).iter(),
EmbeddedEntry::Glob(glob) => glob.files.iter(),
}
}
}
impl From<EmbeddedGlob> for EmbeddedEntry {
fn from(value: EmbeddedGlob) -> Self {
Self::Glob(value)
}
}
impl From<EmbeddedFile> for EmbeddedEntry {
fn from(value: EmbeddedFile) -> Self {
Self::Single(value)
}
}
impl EmbeddedGlob {
pub fn pattern(&self) -> &'static str {
self.pattern
}
pub fn files(&self) -> impl Iterator<Item = &'static EmbeddedFile> {
self.files.iter()
}
}
impl EmbeddedFile {
pub fn path(&self) -> &'static str {
self.path
}
#[cfg(prod_mode)]
pub fn content(&self) -> std::borrow::Cow<'static, [u8]> {
#[cfg(feature = "compress")]
if self.compressed {
let mut decompressed = Vec::new();
brotli::BrotliDecompress(&mut &*self.content, &mut decompressed)
.expect("unexpected error while decompressing Brotli");
decompressed.into()
} else {
self.content.into()
}
#[cfg(not(feature = "compress"))]
{ self.content.into() }
}
pub(crate) fn data_source(&self) -> DataSource {
#[cfg(dev_mode)]
{ DataSource::File(self.full_path.into()) }
#[cfg(prod_mode)]
{
let bytes = match self.content() {
std::borrow::Cow::Borrowed(slice) => slice.into(),
std::borrow::Cow::Owned(vec) => vec.into(),
};
DataSource::Loaded(bytes)
}
}
}