use bevy::{
prelude::*,
tasks::block_on,
};
use crate::{
backend::AppBackend,
prelude::*,
};
pub trait AppPathwayExt {
fn insert_pathway<P>(&mut self, backend: P::Backend) -> &mut Self
where
P: Pathway<Backend: for<'a> Backend<P::Key<'a>> + Send + Sync + 'static>;
fn init_pathway<P>(&mut self) -> &mut Self
where
P: Pathway<Backend: FromWorld + for<'a> Backend<P::Key<'a>> + Send + Sync + 'static>;
}
impl AppPathwayExt for App {
fn insert_pathway<P>(&mut self, backend: P::Backend) -> &mut Self
where
P: Pathway<Backend: for<'a> Backend<P::Key<'a>> + Send + Sync + 'static>,
{
self.insert_backend(backend)
}
fn init_pathway<P>(&mut self) -> &mut Self
where
P: Pathway<Backend: FromWorld + for<'a> Backend<P::Key<'a>> + Send + Sync + 'static>,
{
self.init_backend::<P::Backend, _>()
}
}
pub trait WorldPathwayExt {
fn capture<P>(&mut self, pathway: &P) -> P::Capture
where
P: Pathway<Capture: CaptureInput<P>>;
fn capture_with<P>(
&mut self,
pathway: &P,
builder: <P::Capture as CaptureInput<P>>::Builder,
) -> P::Capture
where
P: Pathway<Capture: CaptureInput<P>>;
fn save<P>(&mut self, pathway: &P) -> Result<(), Error>
where
P: Pathway<Capture: CaptureInput<P> + CaptureSerialize>;
fn apply<P>(&mut self, pathway: &P, capture: P::Capture) -> Result<P::Capture, Error>
where
P: Pathway<Capture: CaptureOutput<P>>;
fn load<P>(&mut self, pathway: &P) -> Result<P::Capture, Error>
where
P: Pathway<Capture: CaptureOutput<P> + CaptureDeserialize>;
}
impl WorldPathwayExt for World {
fn capture<P>(&mut self, pathway: &P) -> P::Capture
where
P: Pathway<Capture: CaptureInput<P>>,
{
self.capture_with(pathway, P::Capture::builder(pathway, self))
}
fn capture_with<P>(
&mut self,
pathway: &P,
builder: <P::Capture as CaptureInput<P>>::Builder,
) -> P::Capture
where
P: Pathway<Capture: CaptureInput<P>>,
{
type Builder<P> = <<P as Pathway>::Capture as CaptureInput<P>>::Builder;
let label = pathway.capture(self).intern();
let out;
if let Some(mut flow) = self
.get_resource_mut::<Flows<Builder<P>>>()
.and_then(|mut r| r.take_flow(label))
{
flow.initialize(self);
out = flow.run(builder, self);
self.resource_mut::<Flows<Builder<P>>>()
.insert_flow(label, flow);
} else {
out = builder;
}
P::Capture::build(out, pathway, self)
}
fn save<P>(&mut self, pathway: &P) -> Result<(), Error>
where
P: Pathway<Capture: CaptureInput<P> + CaptureSerialize>,
{
let cap = self.capture(pathway);
let backend = &self.resource::<AppBackend<P::Backend>>().0;
let seed = cap.value(self);
block_on(backend.save::<P::Format, _>(pathway.key(), &seed))
}
fn apply<P>(&mut self, pathway: &P, capture: P::Capture) -> Result<P::Capture, Error>
where
P: Pathway<Capture: CaptureOutput<P>>,
{
type Builder<P> = <<P as Pathway>::Capture as CaptureOutput<P>>::Builder;
let seed = P::Capture::builder(capture, pathway, self);
let label = pathway.apply(self).intern();
let out;
if let Some(mut flow) = self
.get_resource_mut::<Flows<Builder<P>>>()
.and_then(|mut r| r.take_flow(label))
{
flow.initialize(self);
out = flow.run(seed, self);
self.resource_mut::<Flows<Builder<P>>>()
.insert_flow(label, flow);
} else {
out = seed;
}
P::Capture::build(out, pathway, self)
.map_err(|_| Error::custom("Failed to build capture from applier"))
}
fn load<P>(&mut self, pathway: &P) -> Result<P::Capture, Error>
where
P: Pathway<Capture: CaptureOutput<P> + CaptureDeserialize>,
{
let backend = &self.resource::<AppBackend<P::Backend>>().0;
let seed = <P::Capture as CaptureDeserialize>::seed(self);
let capture = block_on(backend.load::<P::Format, _, _>(pathway.key(), seed))?;
self.apply(pathway, capture)
}
}