use crate::{
AddImpulse, AsyncMap, AsyncMapMarker, BlockingMap, BlockingMapMarker, ImpulseAsyncMap,
ImpulseBlockingMap, ProvideOnce, Sendish, StreamPack,
};
use bevy_ecs::prelude::{Commands, Entity};
use std::future::Future;
pub struct MapOnceDef<F>(F);
#[allow(clippy::wrong_self_convention)]
pub trait AsMapOnce<M> {
type MapType;
fn as_map_once(self) -> Self::MapType;
}
pub(crate) trait CallBlockingMapOnce<Request, Response, Streams: StreamPack> {
fn call(self, input: BlockingMap<Request, Streams>) -> Response;
}
impl<F, Request, Response, Streams> CallBlockingMapOnce<Request, Response, Streams>
for MapOnceDef<F>
where
F: FnOnce(BlockingMap<Request, Streams>) -> Response + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
fn call(self, input: BlockingMap<Request, Streams>) -> Response {
(self.0)(input)
}
}
pub struct BlockingMapOnceDef<Def, Request, Response, Streams> {
def: Def,
_ignore: std::marker::PhantomData<fn(Request, Response, Streams)>,
}
impl<Def, Request, Response, Streams> ProvideOnce
for BlockingMapOnceDef<Def, Request, Response, Streams>
where
Def: CallBlockingMapOnce<Request, Response, Streams> + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
type Request = Request;
type Response = Response;
type Streams = ();
fn connect(self, _: Option<Entity>, source: Entity, target: Entity, commands: &mut Commands) {
commands.add(AddImpulse::new(
source,
ImpulseBlockingMap::new(target, self.def),
));
}
}
impl<F, Request, Response, Streams> AsMapOnce<(Request, Response, Streams, BlockingMapMarker)> for F
where
F: FnOnce(BlockingMap<Request, Streams>) -> Response + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
Streams: StreamPack,
{
type MapType = BlockingMapOnceDef<MapOnceDef<F>, Request, Response, Streams>;
fn as_map_once(self) -> Self::MapType {
BlockingMapOnceDef {
def: MapOnceDef(self),
_ignore: Default::default(),
}
}
}
pub trait IntoBlockingMapOnce<M> {
type MapType;
fn into_blocking_map_once(self) -> Self::MapType;
}
impl<F, Request, Response> IntoBlockingMapOnce<(Request, Response)> for F
where
F: FnOnce(Request) -> Response + 'static + Send + Sync,
Request: 'static + Send + Sync,
Response: 'static + Send + Sync,
{
type MapType = BlockingMapOnceDef<BlockingMapOnceAdapter<F>, Request, Response, ()>;
fn into_blocking_map_once(self) -> Self::MapType {
BlockingMapOnceDef {
def: BlockingMapOnceAdapter(self),
_ignore: Default::default(),
}
}
}
pub struct BlockingMapOnceAdapter<F>(F);
impl<F, Request, Response> CallBlockingMapOnce<Request, Response, ()> for BlockingMapOnceAdapter<F>
where
F: FnOnce(Request) -> Response,
{
fn call(self, BlockingMap { request, .. }: BlockingMap<Request, ()>) -> Response {
(self.0)(request)
}
}
pub(crate) trait CallAsyncMapOnce<Request, Task, Streams: StreamPack> {
fn call(self, input: AsyncMap<Request, Streams>) -> Task;
}
impl<F, Request, Task, Streams> CallAsyncMapOnce<Request, Task, Streams> for MapOnceDef<F>
where
F: FnOnce(AsyncMap<Request, Streams>) -> Task + 'static + Send + Sync,
Request: 'static + Send + Sync,
Streams: StreamPack,
{
fn call(self, input: AsyncMap<Request, Streams>) -> Task {
(self.0)(input)
}
}
impl<F, Request, Task, Streams> AsMapOnce<(Request, Task, Streams, AsyncMapMarker)> for F
where
F: FnOnce(AsyncMap<Request, Streams>) -> Task + 'static + Send + Sync,
Task: Future + 'static + Sendish,
Request: 'static + Send + Sync,
Task::Output: 'static + Send + Sync,
Streams: StreamPack,
{
type MapType = AsyncMapOnceDef<MapOnceDef<F>, Request, Task, Streams>;
fn as_map_once(self) -> Self::MapType {
AsyncMapOnceDef {
def: MapOnceDef(self),
_ignore: Default::default(),
}
}
}
pub struct AsyncMapOnceDef<Def, Request, Task, Streams> {
def: Def,
_ignore: std::marker::PhantomData<fn(Request, Task, Streams)>,
}
impl<Def, Request, Task, Streams> ProvideOnce for AsyncMapOnceDef<Def, Request, Task, Streams>
where
Def: CallAsyncMapOnce<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, _: Option<Entity>, source: Entity, target: Entity, commands: &mut Commands) {
commands.add(AddImpulse::new(
source,
ImpulseAsyncMap::new(target, self.def),
));
}
}
pub trait IntoAsyncMapOnce<M> {
type MapType;
fn into_async_map_once(self) -> Self::MapType;
}
impl<F, Request, Task> IntoAsyncMapOnce<(Request, Task)> for F
where
F: FnOnce(Request) -> Task + 'static + Send + Sync,
Request: 'static + Send + Sync,
Task: Future + 'static + Sendish,
Task::Output: 'static + Send + Sync,
{
type MapType = AsyncMapOnceDef<AsyncMapOnceAdapter<F>, Request, Task, ()>;
fn into_async_map_once(self) -> Self::MapType {
AsyncMapOnceDef {
def: AsyncMapOnceAdapter(self),
_ignore: Default::default(),
}
}
}
pub struct AsyncMapOnceAdapter<F>(F);
impl<F, Request, Task> CallAsyncMapOnce<Request, Task, ()> for AsyncMapOnceAdapter<F>
where
F: FnOnce(Request) -> Task + 'static + Send + Sync,
Task: Future + 'static + Sendish,
{
fn call(self, AsyncMap { request, .. }: AsyncMap<Request, ()>) -> Task {
(self.0)(request)
}
}