use std::io::Read;
use std::sync::{Arc, RwLock};
use uuid::Uuid;
use crate::application::prelude::{LifecycleListener, LifecycleListenerHandle};
use super::manifest::ManfiestResolver;
use super::request::{Request, RequestQueue, Response};
use super::shortcut::ShortcutResolver;
use super::url::Url;
use super::vfs::SchemaResolver;
use super::ResourceParams;
pub struct ResourceSystem {
shortcut: ShortcutResolver,
schemas: SchemaResolver,
manifest: RwLock<ManfiestResolver>,
requests: Arc<RequestQueue>,
lifecycle: LifecycleListenerHandle,
}
struct Lifecycle {
requests: Arc<RequestQueue>,
}
impl LifecycleListener for Lifecycle {
fn on_post_update(&mut self) -> Result<(), failure::Error> {
self.requests.advance();
Ok(())
}
}
impl Drop for ResourceSystem {
fn drop(&mut self) {
crate::application::detach(self.lifecycle);
}
}
impl ResourceSystem {
pub fn new(params: ResourceParams) -> Result<Self, failure::Error> {
debug_assert!(crate::application::valid(), "");
let requests = Arc::new(RequestQueue::new());
let sys = ResourceSystem {
shortcut: params.shortcuts,
schemas: params.schemas,
manifest: RwLock::new(ManfiestResolver::new()),
requests: requests.clone(),
lifecycle: crate::application::attach(Lifecycle { requests }),
};
Ok(sys)
}
#[inline]
pub fn attach<T>(&self, prefix: T, file: &mut dyn Read) -> Result<(), failure::Error>
where
T: AsRef<str>,
{
let prefix = prefix.as_ref();
let url = self
.shortcut
.resolve(prefix)
.ok_or_else(|| format_err!("Could not resolve manifest filename: {}.", prefix))?;
self.manifest.write().unwrap().add(url, file)
}
#[inline]
pub fn resolve<T: AsRef<str>>(&self, url: T) -> Option<String> {
self.shortcut.resolve(url.as_ref())
}
#[inline]
pub fn find<T: AsRef<str>>(&self, filename: T) -> Option<Uuid> {
let filename = filename.as_ref();
self.shortcut
.resolve(filename)
.and_then(|url| self.manifest.read().unwrap().find(&url))
}
#[inline]
pub fn exists(&self, uuid: Uuid) -> bool {
self.manifest.read().unwrap().contains(uuid)
}
#[inline]
pub fn load_with_callback<T>(&self, uuid: Uuid, func: T) -> Result<(), failure::Error>
where
T: FnOnce(Response) + Send + 'static,
{
let req = self.load(uuid)?;
self.requests.add(req, func);
Ok(())
}
#[inline]
pub fn load_manifest_with_callback<T1, T2>(
&self,
filename: T1,
func: T2,
) -> Result<(), failure::Error>
where
T1: AsRef<str>,
T2: FnOnce(Response) + Send + 'static,
{
let filename = format!("{}{}", filename.as_ref(), super::manifest::NAME);
let url = self
.shortcut
.resolve(&filename)
.ok_or_else(|| format_err!("Could not resolve filename: {}.", filename))?;
let url = Url::new(url)?;
let state = Request::latch();
let req = Request::new(state.clone());
self.requests.add(req, func);
let vfs = self.schemas.locate(url.schema())?;
crate::sched::spawn(move || vfs.request(&url, state));
Ok(())
}
#[inline]
pub fn load_from_with_callback<T1, T2>(
&self,
filename: T1,
func: T2,
) -> Result<(), failure::Error>
where
T1: AsRef<str>,
T2: FnOnce(Response) + Send + 'static,
{
let filename = filename.as_ref();
let req = self.load_from(filename)?;
self.requests.add(req, func);
Ok(())
}
pub fn load(&self, uuid: Uuid) -> Result<Request, failure::Error> {
let url =
self.manifest.read().unwrap().resolve(uuid).ok_or_else(|| {
format_err!("Could not found resource {} in this registry.", uuid)
})?;
let url = Url::new(url)?;
let vfs = self.schemas.locate(url.schema())?;
let state = Request::latch();
let req = Request::new(state.clone());
crate::sched::spawn(move || vfs.request(&url, state));
Ok(req)
}
pub fn load_from<T: AsRef<str>>(&self, filename: T) -> Result<Request, failure::Error> {
let filename = filename.as_ref();
let url = self
.shortcut
.resolve(filename)
.ok_or_else(|| format_err!("Could not resolve filename: {}.", filename))?;
let uuid = self.manifest.read().unwrap().find(&url).ok_or_else(|| {
format_err!(
"Could not found resource {} (resolved into {}) in this registry.",
filename,
url
)
})?;
self.load(uuid)
}
}