use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::ops::Deref;
#[cfg(feature = "std")]
use std::path::Path;
use crate::AssetError;
#[cfg(feature = "std")]
use crate::download_remote_bytes;
#[derive(Debug, Clone)]
pub struct Data {
bytes: Arc<[u8]>,
}
impl Data {
#[must_use]
pub fn from_bytes(bytes: Vec<u8>) -> Self {
Self {
bytes: bytes.into(),
}
}
#[must_use]
pub fn from_static(bytes: &'static [u8]) -> Self {
Self {
bytes: Arc::from(bytes),
}
}
#[cfg(feature = "std")]
pub fn from_local(path: impl AsRef<Path>) -> Result<Self, AssetError> {
let path = path.as_ref();
let bytes = std::fs::read(path).map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
AssetError::not_found(path.display().to_string())
} else {
AssetError::io(e.to_string())
}
})?;
Ok(Self::from_bytes(bytes))
}
#[cfg(feature = "std")]
pub async fn from_remote(url: &str) -> Result<Self, AssetError> {
Ok(Self::from_bytes(download_remote_bytes(url).await?))
}
#[must_use]
pub fn len(&self) -> usize {
self.bytes.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
pub fn as_str(&self) -> Result<&str, core::str::Utf8Error> {
core::str::from_utf8(&self.bytes)
}
#[cfg(feature = "std")]
pub fn into_string(self) -> Result<String, core::str::Utf8Error> {
self.as_str().map(String::from)
}
}
impl Deref for Data {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
impl AsRef<[u8]> for Data {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl From<Vec<u8>> for Data {
fn from(bytes: Vec<u8>) -> Self {
Self::from_bytes(bytes)
}
}
impl From<&'static [u8]> for Data {
fn from(bytes: &'static [u8]) -> Self {
Self::from_static(bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_from_bytes() {
let data = Data::from_bytes(vec![1, 2, 3, 4]);
assert_eq!(data.len(), 4);
assert_eq!(&*data, &[1, 2, 3, 4]);
}
#[test]
fn test_from_static() {
static BYTES: &[u8] = b"hello world";
let data = Data::from_static(BYTES);
assert_eq!(data.as_str().unwrap(), "hello world");
}
#[test]
fn test_deref() {
let data = Data::from_bytes(b"test".to_vec());
let slice: &[u8] = &data;
assert_eq!(slice, b"test");
}
}