#![allow(clippy::needless_doctest_main)]
use std::borrow::Cow;
pub use rust_embed::{EmbeddedFile, RustEmbed};
#[doc(hidden)]
pub use rust_embed;
#[cfg(feature = "axum")]
pub mod axum;
pub mod build;
pub struct Asset {
pub path: String,
pub data: Cow<'static, [u8]>,
pub gzipped: bool,
}
impl Asset {
fn from_embedded(path: String, file: EmbeddedFile, gzipped: bool) -> Self {
Self {
path,
data: file.data,
gzipped,
}
}
pub fn decoded(&self) -> std::io::Result<Cow<'_, [u8]>> {
if !self.gzipped {
return Ok(Cow::Borrowed(&self.data));
}
use std::io::Read;
let mut out = Vec::with_capacity(self.data.len() * 4);
flate2::read::GzDecoder::new(&self.data[..]).read_to_end(&mut out)?;
Ok(Cow::Owned(out))
}
}
pub fn resolve<A: RustEmbed>(path: &str) -> Option<Asset> {
let path = path.trim_start_matches('/');
let path = if path.is_empty() { "index.html" } else { path };
let candidates: [String; 4] = [
path.to_string(),
format!("{}.html", path.trim_end_matches('/')),
format!("{}/index.html", path.trim_end_matches('/')),
"index.html".to_string(),
];
for candidate in candidates {
let gz = format!("{candidate}.gz");
if let Some(file) = A::get(&gz) {
return Some(Asset::from_embedded(candidate, file, true));
}
if let Some(file) = A::get(&candidate) {
return Some(Asset::from_embedded(candidate, file, false));
}
}
None
}