#![feature(stmt_expr_attributes)]
#![feature(future_join)]
#![feature(portable_simd)]
#![feature(allocator_api)]
#![allow(
clippy::await_holding_lock,
clippy::bool_assert_comparison,
clippy::duplicate_mod,
clippy::extra_unused_lifetimes,
clippy::format_in_format_args,
clippy::identity_op,
clippy::if_same_then_else,
clippy::items_after_test_module,
clippy::needless_borrow,
clippy::needless_lifetimes,
clippy::needless_range_loop,
clippy::new_without_default,
clippy::mutable_key_type,
clippy::question_mark,
clippy::result_unit_err,
clippy::tabs_in_doc_comments,
clippy::to_string_trait_impl,
clippy::too_many_arguments,
clippy::type_complexity,
clippy::unused_unit,
clippy::wrong_self_convention,
unused_imports
)]
use std::{alloc::Allocator, any::Any};
use asset::ResourceId;
pub(crate) const ONLINE_DOCS_BASE_URL: &str = match option_env!("BYTE_ENGINE_DOCS_BASE_URL") {
Some(url) => url,
None => "https://byte-engine.0x44491229.dev/docs",
};
pub(crate) fn online_docs_url(path: &str) -> String {
format!(
"{}/{}",
ONLINE_DOCS_BASE_URL.trim_end_matches('/'),
path.trim_start_matches('/')
)
}
pub mod asset;
pub mod resource;
pub mod model;
pub mod reference;
pub mod solver;
pub mod stream;
pub mod types;
pub mod resources;
pub mod shader;
pub mod pbr;
pub mod processors;
pub mod inspect;
pub mod r#async;
pub use asset::asset_handler::{AssetHandler, BakeContext};
#[cfg(debug_assertions)]
pub use asset::{ResourceTrace, ResourceTraceItem, ResourceTraceLevel};
pub use model::Model;
pub use model::{QueryableProperty, QueryableValue};
pub use reference::Reference;
pub use reference::ReferenceModel;
pub use resource::resource_manager::ResourceManager;
pub use resource::Resource;
pub use solver::Solver;
pub use stream::Stream;
pub(crate) type DataStorage = Vec<u8>;
pub type ResourceArchiveError = rkyv::rancor::Error;
pub trait ResourceArchive: Sized + rkyv::Archive + for<'a> rkyv::Serialize<ResourceHighSerializer<'a>> {}
impl<T> ResourceArchive for T where T: rkyv::Archive + for<'a> rkyv::Serialize<ResourceHighSerializer<'a>> {}
type ResourceHighSerializer<'a> =
rkyv::api::high::HighSerializer<rkyv::util::AlignedVec, rkyv::ser::allocator::ArenaHandle<'a>, ResourceArchiveError>;
pub(crate) type ResourceHighDeserializer = rkyv::api::high::HighDeserializer<ResourceArchiveError>;
pub(crate) type ResourceHighValidator<'a> = rkyv::api::high::HighValidator<'a, ResourceArchiveError>;
pub(crate) fn to_vec<T: ResourceArchive>(value: &T) -> Result<Vec<u8>, ResourceArchiveError> {
rkyv::to_bytes::<ResourceArchiveError>(value).map(Vec::from)
}
pub(crate) fn to_vec_in<'a, T: ResourceArchive>(
value: &T,
allocator: &'a dyn Allocator,
) -> Result<Vec<u8, &'a dyn Allocator>, ResourceArchiveError> {
let bytes = rkyv::to_bytes::<ResourceArchiveError>(value)?;
let mut output = Vec::with_capacity_in(bytes.len(), allocator);
output.extend_from_slice(&bytes);
Ok(output)
}
pub(crate) fn from_slice<T>(bytes: &[u8]) -> Result<T, ResourceArchiveError>
where
T: ResourceArchive,
<T as rkyv::Archive>::Archived:
for<'a> rkyv::bytecheck::CheckBytes<ResourceHighValidator<'a>> + rkyv::Deserialize<T, ResourceHighDeserializer>,
{
rkyv::from_bytes::<T, ResourceArchiveError>(bytes)
}
pub(crate) fn archived_from_slice<T>(bytes: &[u8]) -> Result<&<T as rkyv::Archive>::Archived, ResourceArchiveError>
where
T: ResourceArchive,
<T as rkyv::Archive>::Archived: for<'a> rkyv::bytecheck::CheckBytes<ResourceHighValidator<'a>>,
{
rkyv::access::<<T as rkyv::Archive>::Archived, ResourceArchiveError>(bytes)
}
#[derive(Debug, Clone)]
pub struct ProcessedAsset {
id: String,
class: String,
resource: DataStorage,
streams: Option<Vec<StreamDescription>>,
queryable_properties: Vec<QueryableProperty>,
}
impl ProcessedAsset {
pub fn new<T: Model>(id: ResourceId<'_>, resource: T) -> Self {
ProcessedAsset {
id: id.to_string(),
class: T::get_class().to_string(),
resource: to_vec(&resource).unwrap(),
streams: None,
queryable_properties: resource.queryable_properties(id.as_ref()),
}
}
pub fn into_serializable(self, hash: u64, size: usize) -> SerializableResource {
SerializableResource {
id: self.id,
hash,
class: self.class,
size,
resource: self.resource,
streams: self.streams,
queryable_properties: self.queryable_properties,
}
}
pub fn new_with_serialized(id: &str, class: &str, resource: DataStorage) -> Self {
ProcessedAsset {
id: id.to_string(),
class: class.to_string(),
resource,
streams: None,
queryable_properties: vec![QueryableProperty {
name: "name".to_string(),
value: QueryableValue::String(id.to_string()),
}],
}
}
pub fn with_streams(mut self, streams: Vec<StreamDescription>) -> Self {
self.streams = Some(streams);
self
}
}
impl<'a, T: Resource + ResourceArchive + Clone> From<Reference<T>> for ProcessedAsset {
fn from(value: Reference<T>) -> Self {
let id = value.id.clone();
let queryable_properties = value.resource.queryable_properties(&id);
ProcessedAsset {
id,
class: value.resource.get_class().to_string(),
resource: to_vec(&value.resource).unwrap(),
streams: None,
queryable_properties,
}
}
}
impl From<SerializableResource> for ProcessedAsset {
fn from(value: SerializableResource) -> Self {
ProcessedAsset {
id: value.id,
class: value.class,
resource: value.resource.clone(),
streams: None,
queryable_properties: value.queryable_properties,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct StreamDescription {
name: String,
size: usize,
offset: usize,
}
impl StreamDescription {
pub fn new(name: &str, size: usize, offset: usize) -> Self {
StreamDescription {
name: name.to_string(),
size,
offset,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn size(&self) -> usize {
self.size
}
pub fn offset(&self) -> usize {
self.offset
}
}
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct SerializableResource {
id: String,
hash: u64,
class: String,
size: usize,
resource: DataStorage,
streams: Option<Vec<StreamDescription>>,
queryable_properties: Vec<QueryableProperty>,
}
impl SerializableResource {
pub fn new(
id: String,
hash: u64,
class: String,
size: usize,
resource: DataStorage,
streams: Option<Vec<StreamDescription>>,
queryable_properties: Vec<QueryableProperty>,
) -> Self {
SerializableResource {
id,
hash,
class,
size,
resource,
streams,
queryable_properties,
}
}
pub fn id(&self) -> &str {
&self.id
}
pub fn uid(&self) -> String {
resource::ResourceId::from(self.id.as_str()).to_hex()
}
pub fn hash(&self) -> u64 {
self.hash
}
pub fn class(&self) -> &str {
&self.class
}
pub fn size(&self) -> usize {
self.size
}
pub fn resource(&self) -> &[u8] {
&self.resource
}
pub fn streams(&self) -> Option<&[StreamDescription]> {
self.streams.as_deref()
}
pub fn queryable_properties(&self) -> &[QueryableProperty] {
&self.queryable_properties
}
}
impl<M: Model> From<SerializableResource> for ReferenceModel<M> {
fn from(val: SerializableResource) -> Self {
ReferenceModel::new_serialized(&val.id, val.hash, val.size, val.resource, val.streams)
}
}
#[derive(Debug)]
pub enum LoadResults {
ResourceNotFound,
LoadFailed,
CacheFileNotFound,
UnsuportedResourceType,
NoReadTarget,
}
pub trait Description: Any + Send + Sync {
fn get_resource_class() -> &'static str
where
Self: Sized;
}
#[cfg(test)]
mod tests {
pub const ASSETS_PATH: &str = "../../assets";
}