use crate::{
AddOperation, AsyncMap, BlockingMap, OperateAsyncMap, OperateBlockingMap, ProvideOnce,
Provider, Sendish, StreamPack,
};
use bevy_ecs::prelude::{Commands, Entity};
use std::future::Future;
#[derive(Clone, Copy)]
pub struct MapDef<F>(F);
#[allow(clippy::wrong_self_convention)]
pub trait AsMap<M> {
type MapType;
fn as_map(self) -> Self::MapType;
}
pub type RequestOfMap<M, F> = <<F as AsMap<M>>::MapType as ProvideOnce>::Request;
pub type ResponseOfMap<M, F> = <<F as AsMap<M>>::MapType as ProvideOnce>::Response;
pub type StreamsOfMap<M, F> = <<F as AsMap<M>>::MapType as ProvideOnce>::Streams;
pub(crate) trait CallBlockingMap<Request, Response, Streams: StreamPack> {
fn call(&mut self, input: BlockingMap<Request, Streams>) -> Response;
}
impl<F, Request, Response, Streams> CallBlockingMap<Request, Response, Streams> for MapDef<F>
where
F: FnMut(BlockingMap<Request, Streams>) -> Response + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
fn call(&mut self, request: BlockingMap<Request, Streams>) -> Response {
(self.0)(request)
}
}
pub struct BlockingMapDef<Def, Request, Response, Streams> {
def: Def,
_ignore: std::marker::PhantomData<fn(Request, Response, Streams)>,
}
impl<Def: Clone, Request, Response, Streams> Clone
for BlockingMapDef<Def, Request, Response, Streams>
{
fn clone(&self) -> Self {
Self {
def: self.def.clone(),
_ignore: Default::default(),
}
}
}
impl<Def, Request, Response, Streams> ProvideOnce
for BlockingMapDef<Def, Request, Response, Streams>
where
Def: CallBlockingMap<Request, Response, Streams> + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
type Request = Request;
type Response = Response;
type Streams = Streams;
fn connect(
self,
scope: Option<Entity>,
source: Entity,
target: Entity,
commands: &mut Commands,
) {
commands.add(AddOperation::new(
scope,
source,
OperateBlockingMap::new(target, self.def),
));
}
}
impl<Def, Request, Response, Streams> Provider for BlockingMapDef<Def, Request, Response, Streams>
where
Def: CallBlockingMap<Request, Response, Streams> + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
}
pub struct BlockingMapMarker;
impl<F, Request, Response, Streams> AsMap<(Request, Response, Streams, BlockingMapMarker)> for F
where
F: FnMut(BlockingMap<Request, Streams>) -> Response + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
type MapType = BlockingMapDef<MapDef<F>, Request, Response, Streams>;
fn as_map(self) -> Self::MapType {
BlockingMapDef {
def: MapDef(self),
_ignore: Default::default(),
}
}
}
pub trait IntoBlockingMap<M> {
type MapType;
fn into_blocking_map(self) -> Self::MapType;
}
impl<F, Request, Response, Streams> IntoBlockingMap<(Request, Response, Streams)> for F
where
F: FnMut(Request) -> Response + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
type MapType = BlockingMapDef<BlockingMapAdapter<F>, Request, Response, Streams>;
fn into_blocking_map(self) -> Self::MapType {
BlockingMapDef {
def: BlockingMapAdapter(self),
_ignore: Default::default(),
}
}
}
pub struct BlockingMapAdapter<F>(F);
impl<F, Request, Response> CallBlockingMap<Request, Response, ()> for BlockingMapAdapter<F>
where
F: FnMut(Request) -> Response,
{
fn call(&mut self, BlockingMap { request, .. }: BlockingMap<Request, ()>) -> Response {
(self.0)(request)
}
}
pub(crate) trait CallAsyncMap<Request, Task, Streams: StreamPack> {
fn call(&mut self, input: AsyncMap<Request, Streams>) -> Task;
}
impl<F, Request, Task, Streams> CallAsyncMap<Request, Task, Streams> for MapDef<F>
where
F: FnMut(AsyncMap<Request, Streams>) -> Task + 'static + Send + Sync,
Request: 'static + Send + Sync,
Task: 'static + Send,
Streams: StreamPack,
{
fn call(&mut self, input: AsyncMap<Request, Streams>) -> Task {
(self.0)(input)
}
}
pub struct AsyncMapMarker;
impl<F, Request, Task, Streams> AsMap<(Request, Task, Streams, AsyncMapMarker)> for F
where
F: FnMut(AsyncMap<Request, Streams>) -> Task + 'static + Send + Sync,
Task: Future + 'static + Sendish,
Request: 'static + Send + Sync,
Task::Output: 'static + Send + Sync,
Streams: StreamPack,
{
type MapType = AsyncMapDef<MapDef<F>, Request, Task, Streams>;
fn as_map(self) -> Self::MapType {
AsyncMapDef {
def: MapDef(self),
_ignore: Default::default(),
}
}
}
pub struct AsyncMapDef<Def, Request, Task, Streams> {
def: Def,
_ignore: std::marker::PhantomData<fn(Request, Task, Streams)>,
}
impl<Def: Clone, Request, Task, Streams> Clone for AsyncMapDef<Def, Request, Task, Streams> {
fn clone(&self) -> Self {
Self {
def: self.def.clone(),
_ignore: Default::default(),
}
}
}
impl<Def, Request, Task, Streams> ProvideOnce for AsyncMapDef<Def, Request, Task, Streams>
where
Def: CallAsyncMap<Request, Task, Streams> + 'static + Send + Sync,
Task: Future + 'static + Sendish,
Request: 'static + Send + Sync,
Task::Output: 'static + Send + Sync,
Streams: StreamPack,
{
type Request = Request;
type Response = Task::Output;
type Streams = Streams;
fn connect(
self,
scope: Option<Entity>,
source: Entity,
target: Entity,
commands: &mut Commands,
) {
commands.add(AddOperation::new(
scope,
source,
OperateAsyncMap::new(target, self.def),
));
}
}
impl<Def, Request, Task, Streams> Provider for AsyncMapDef<Def, Request, Task, Streams>
where
Def: CallAsyncMap<Request, Task, Streams> + 'static + Send + Sync,
Task: Future + 'static + Sendish,
Request: 'static + Send + Sync,
Task::Output: 'static + Send + Sync,
Streams: StreamPack,
{
}
pub trait IntoAsyncMap<M> {
type MapType;
fn into_async_map(self) -> Self::MapType;
}
impl<F, Request, Task> IntoAsyncMap<(Request, Task)> for F
where
F: FnMut(Request) -> Task + 'static + Send + Sync,
Request: 'static + Send + Sync,
Task: Future + 'static + Sendish,
Task::Output: 'static + Send + Sync,
{
type MapType = AsyncMapDef<AsyncMapAdapter<F>, Request, Task, ()>;
fn into_async_map(self) -> Self::MapType {
AsyncMapDef {
def: AsyncMapAdapter(self),
_ignore: Default::default(),
}
}
}
pub struct AsyncMapAdapter<F>(F);
impl<F, Request, Task> CallAsyncMap<Request, Task, ()> for AsyncMapAdapter<F>
where
F: FnMut(Request) -> Task + 'static + Send + Sync,
Task: Future + 'static + Sendish,
{
fn call(&mut self, AsyncMap { request, .. }: AsyncMap<Request, ()>) -> Task {
(self.0)(request)
}
}