use std::{
any::Any, marker::PhantomData, sync::atomic::{AtomicUsize, Ordering}
};
use crate::{cond::{ArgIdx, CondAddr, Section::Input, TaskId}, curry::{CallOnce, CallParam, Currier}, meta::{TupleAt, TupleCondAddr, TupleOpt}};
use crate::meta::Fndecl;
#[derive(Clone,Copy)]
pub enum Kind {
Normal,
Exit,
}
static TASKID:TaskIdGen = TaskIdGen::new();
struct TaskIdGen {
nexter: AtomicUsize
}
impl TaskIdGen {
const fn new()->Self {
Self {
nexter: AtomicUsize::new(1)
}
}
fn next(&self)->TaskId {
TaskId::from(
match self.nexter.fetch_add(1, Ordering::Relaxed) {
0 => self.nexter.fetch_add(1, Ordering::Relaxed),
id => id,
}
)
}
}
pub fn taskid_next()->TaskId {
TASKID.next()
}
pub(crate) trait Task
{
fn run(self:Box<Self>)->Box<dyn Any>;
fn as_param_mut(&mut self)->Option<&mut dyn CallParam>;
fn kind(&self)->Kind;
#[allow(dead_code)]
fn id(&self)->TaskId;
}
pub(crate) struct TaskCurrier<Currier> {
pub(crate) currier: Currier,
pub(crate) id: TaskId,
pub(crate) kind: Kind,
}
pub(crate) struct TaskMap<MapFn>(pub(crate) MapFn);
impl<T> Task for TaskCurrier<T>
where
T: CallOnce,
T::R: 'static,
{
fn run(self:Box<Self>)->Box<dyn Any> {
let r = self.currier.call_once();
Box::new(r)
}
fn as_param_mut(&mut self)->Option<&mut dyn CallParam> {
self.currier.as_param_mut()
}
fn kind(&self)->Kind {
self.kind
}
fn id(&self)->TaskId {
self.id
}
}
pub struct TaskNeed<C,MapFn,MapR,ToFn>
where MapR: TupleCondAddr
{
pub(crate) task: TaskCurrier<C>,
pub(crate) map: TaskMap<MapFn>,
pub(crate) tofn: ToFn,
pub(crate) phantom: PhantomData<MapR>
}
impl<C,MapFn,MapR:TupleCondAddr,ToFn> TaskNeed<C,MapFn,MapR,ToFn> {
pub fn id(&self)->TaskId {
self.task.id
}
}
#[test]
#[allow(dead_code)]
fn test_pass_through() {
trait Function {}
impl<F:FnOnce()> Function for F {}
fn do_nothing() {}
struct AA<F:Function>(F);
impl<F:Function> AA<F> {
#[cfg(false)]
fn test()->Self {
let a = AA(do_nothing);
a
}
fn test2() {
let a = AA(do_nothing);
let AA(_f) = a;
#[cfg(false)]
let a = Self(do_nothing);
}
}
}
impl<F,TC,R,MapFn1,R1,ToFn1> TaskNeed<Currier<F,TC,R>, MapFn1,R1,ToFn1>
where
TC: TupleOpt,
R1: TupleCondAddr,
{
pub fn bind_to<'a>(self, ca:CondAddr<R>)
-> TaskNeed<
Currier<F,TC,R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>,
>
{
let map = TaskMap(PassthroughMapFn::<R>::NULL);
let tofn = OneToOne::<(R,)>((ca,));
TaskNeed {
task: self.task,
map,
tofn,
phantom: PhantomData,
}
}
#[deprecated(
since="0.3.0",
note = "Use `.bind_to()` instead for strict type check. \
`to()` will be removed in next release."
)]
pub fn to<'a>(self, to: usize, ai: usize)
-> TaskNeed<
Currier<F,TC,R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>,
>
{
warn!("Use .bind_to() instead, the .to() will be removed in next version.");
debug_assert!(ai <= u8::MAX as usize);
if ai > u8::MAX as usize {
error!("The index of cond#{ai} is too large, shoul be <= {}.",u8::MAX);
}
self.bind_to(CondAddr::from((TaskId::from(to), Input, ArgIdx::from(ai as u8))))
}
}
impl<F,TC,R,MapFn1,R1,ToFn1> TaskNeed<Currier<F,TC,R>, MapFn1,R1,ToFn1>
where
TC: TupleOpt,
R1: TupleCondAddr,
{
pub fn map_tuple_with<'a,MapFn,MapR>(self, mapfn:MapFn)
-> TaskNeed<
Currier<F,TC,R>,
MapFn,
MapR,
OneToOne::<MapR>,
>
where
MapR: TupleCondAddr,
MapR::TCA: Default,
MapFn: Fndecl<(R,),MapR>,
{
TaskNeed {
task: self.task,
map: TaskMap(mapfn),
tofn: OneToOne::<MapR>::ONETOONE,
phantom: PhantomData,
}
}
}
impl<F,TC,R,MapFn1,R1> TaskNeed<Currier<F,TC,R>, MapFn1,R1,OneToOne<R1>>
where
TC: TupleOpt,
R1: TupleCondAddr,
{
pub fn bind_all_to(mut self, cats: R1::TCA)->Self {
self.tofn.0 = cats;
self
}
}
impl<F,TC,R,MapFn1,R1> TaskNeed<Currier<F,TC,R>, MapFn1,R1,OneToOne<R1>>
where
TC: TupleOpt,
R1: TupleCondAddr,
{
pub fn input_ca<const I:u8>(&self)->CondAddr<TC::EleT>
where TC: TupleAt<I>
{
CondAddr::from((self.id(), Input, ArgIdx::from(I)))
}
#[doc(hidden)]
pub fn output_ca<const I:u8>(&self)->CondAddr<R1::EleT>
where R1: TupleAt<I>
{
use crate::cond::Section;
CondAddr::from((self.id(), Section::Output, ArgIdx::from(I)))
}
}
#[doc(hidden)]
pub trait PsOf {
type InputPs;
}
impl<F,C:TupleOpt,R> PsOf for Currier<F,C,R> {
type InputPs = C;
}
#[deprecated(
since="0.3.0",
note = "Use `.bind_to()` directly, for this method has been integrated into the TaskNeed. \
trait `TaskBuildOp` actually do nothing and will be removed in next release."
)]
pub trait TaskBuildOp<Currier,R> {}
pub trait TaskBuildNew<C,F,R,T> {
fn into_task(self)->TaskNeed<C,F,R,T> where R: TupleCondAddr;
#[deprecated(
since="0.2.0",
note = "Use `into_task()` instead for clearer ownership semantic. \
`task()` will be removed in next release."
)]
fn task(self)->TaskNeed<C,F,R,T> where Self:Sized, R: TupleCondAddr {
self.into_task()
}
fn into_exit_task(self)->TaskNeed<C,F,R,T> where R:TupleCondAddr;
#[deprecated(
since="0.2.0",
note = "Use `into_exit_task()` instead for clearer ownership semantic. \
`exit_task()` will be removed in next release."
)]
fn exit_task(self)->TaskNeed<C,F,R,T> where Self:Sized, R:TupleCondAddr {
self.into_exit_task()
}
}
#[test]
fn test_task_build_fan_and_to() {
let task = (||3).into_task();
if true {
task.map_tuple_with(|_:i32| (3,));
} else {
task.bind_to(CondAddr::from((TaskId::from(3),Input, ArgIdx::<i32>::AI0)));
}
let task = (||{}).into_task();
match 0 {
0 => {task.map_tuple_with(|_:()| (3,) ); }
1 => {task.bind_to(CondAddr::from((TaskId::from(3),Input, ArgIdx::AI0))); }
#[allow(deprecated)]
2 => {task.to(1,2); }
_ => {}
}
}
#[doc(hidden)]
pub struct PassthroughMapFn<P> {
phantom: PhantomData<P>
}
impl<P> PassthroughMapFn<P> {
const NULL:Self = Self {phantom:PhantomData};
}
impl<P> Fndecl<(P,),(P,)> for PassthroughMapFn<P> {
type Pt=(P,);
type R=(P,);
fn call(self,ps:Self::Pt)->Self::R {
ps
}
}
#[doc(hidden)]
pub struct OneToOne<Rtuple:TupleCondAddr>(Rtuple::TCA);
impl<P:TupleCondAddr> OneToOne<P>
{
const ONETOONE:Self = Self(P::ONETOONE);
}
impl<'a,Rtuple:TupleCondAddr> Fndecl<(&'a Rtuple,),Rtuple::TCA> for OneToOne<Rtuple> {
type Pt = (&'a Rtuple,);
type R = Rtuple::TCA;
fn call(self,_ps:Self::Pt)->Self::R {
self.0
}
}
impl<F:FnOnce()->R,R> TaskBuildNew<Currier<F,(),R>,PassthroughMapFn<R>,(R,),OneToOne<(R,)>> for F {
fn into_task(self)
-> TaskNeed<
Currier<F,(),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self),
id: TaskId::NONE,
kind: Kind::Normal,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
fn into_exit_task(self)
-> TaskNeed<
Currier<F,(),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self),
id: TaskId::NONE,
kind: Kind::Exit,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
}
impl<F:FnOnce()->R,R> TaskBuildNew<Currier<F,(),R>,PassthroughMapFn<R>,(R,),OneToOne<(R,)>> for (F,TaskId) {
fn into_task(self)
-> TaskNeed<
Currier<F,(),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self.0),
id: self.1,
kind: Kind::Normal,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
fn into_exit_task(self)
-> TaskNeed<
Currier<F,(),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self.0),
id: self.1,
kind: Kind::Exit,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
}
impl<F:FnOnce(P1)->R,P1,R> TaskBuildNew<Currier<F,(P1,),R>,PassthroughMapFn<R>,(R,),OneToOne<(R,)>> for F {
fn into_task(self)
-> TaskNeed<
Currier<F,(P1,),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self),
id: TaskId::NONE,
kind: Kind::Normal,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
fn into_exit_task(self)
-> TaskNeed<
Currier<F,(P1,),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self),
id: TaskId::NONE,
kind: Kind::Exit,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
}
impl<F:FnOnce(P1,)->R,P1,R> TaskBuildNew<Currier<F,(P1,),R>,PassthroughMapFn<R>,(R,),OneToOne<(R,)>> for (F,TaskId) {
fn into_task(self)
-> TaskNeed<
Currier<F,(P1,),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self.0),
id: self.1,
kind: Kind::Normal,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
fn into_exit_task(self)
-> TaskNeed<
Currier<F,(P1,),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self.0),
id: self.1,
kind: Kind::Exit,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
}
macro_rules! impl_task_build_new {
($($P:ident),+) => {
impl<F:FnOnce($($P),+)->R,$($P),+,R> TaskBuildNew<Currier<F,($($P),+),R>,PassthroughMapFn<R>,(R,),OneToOne<(R,)>> for F {
fn into_task(self)
-> TaskNeed<
Currier<F,($($P),+),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self),
id: TaskId::NONE,
kind: Kind::Normal,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
fn into_exit_task(self)
-> TaskNeed<
Currier<F,($($P),+),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self),
id: TaskId::NONE,
kind: Kind::Exit,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
}
impl<F:FnOnce($($P),+)->R,$($P),+,R> TaskBuildNew<Currier<F,($($P),+),R>,PassthroughMapFn<R>,(R,),OneToOne<(R,)>> for (F,TaskId) {
fn into_task(self)
-> TaskNeed<
Currier<F,($($P),+),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self.0),
id: self.1,
kind: Kind::Normal,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
fn into_exit_task(self)
-> TaskNeed<
Currier<F,($($P),+),R>,
PassthroughMapFn<R>,
(R,),
OneToOne<(R,)>
>
where
PassthroughMapFn<R>: Fndecl<(R,),(R,)>,
{
TaskNeed {
task: TaskCurrier {
currier: Currier::from(self.0),
id: self.1,
kind: Kind::Exit,
},
map: TaskMap(PassthroughMapFn::NULL),
tofn: OneToOne::ONETOONE,
phantom: PhantomData,
}
}
}
};
}
impl_task_build_new!(P1,P2);
impl_task_build_new!(P1,P2,P3);
impl_task_build_new!(P1,P2,P3,P4);
impl_task_build_new!(P1,P2,P3,P4,P5);
impl_task_build_new!(P1,P2,P3,P4,P5,P6);
impl_task_build_new!(P1,P2,P3,P4,P5,P6,P7);
impl_task_build_new!(P1,P2,P3,P4,P5,P6,P7,P8);
#[test]
fn test_taskneed_construct() {
let task: TaskNeed<Currier<_, (), ()>, PassthroughMapFn<()>, ((),), OneToOne<((),)>>
= (||println!("task='free': Hello, 1 2 3 .."),TaskId::from(1)).into_task();
println!("task type={:?}", std::any::type_name_of_val(&task));
}
#[test]
fn test_task_new() {
let f = ||();
let t = f.into_exit_task();
let t :Box<dyn Task> = Box::new(t.task);
t.run();
let t = f.into_task();
let t :Box<dyn Task> = Box::new(t.task);
t.run();
let s = String::new();
let f = ||{let _s=s;};
let t = f.into_task();
let t :Box<dyn Task> = Box::new(t.task);
t.run();
}
#[should_panic]
#[test]
fn test_task_new_panic() {
let f = |_:i32,_:i32|{};
let t = f.into_task();
let t :Box<dyn Task> = Box::new(t.task);
t.run();
}
#[test]
fn test_task_postdo() {
let mut v = 3;
let f = ||{v=3;v};
let v = Some(String::new());
let postdo = |_:i32|{v.unwrap();};
let _r1: &dyn FnMut()->i32 = &f;
let r1: Box<dyn FnOnce(i32)> = Box::new(postdo);
r1(3);
}
#[test]
fn test_task_run() {
let c1 = (|_p:i32|println!("get c1")).into_task();
let mut c1: Box<dyn Task> = Box::new(c1.task);
c1.as_param_mut().map(|e|e.set(0, &5));
c1.run();
let tp1 = 1;
let tp2 = "2nd static str";
let tp3 = "3rd String".to_string();
let tp4 = vec![41,42,43];
let tp5 = 5;
let tp6 = 6;
let tp7 = 7;
let tp8 = 8;
let tr8 = tp1+tp5+tp6+tp7+tp8;
let c8 = (
|p1:i32,
p2:&'static str,
p3:String,
p4:Vec<i32>,
p5:i32,
p6:i32,
p7:i32,
p8:i32|{
assert_eq!(p1,tp1);
assert_eq!(p2,tp2);
assert_eq!(p3,tp3);
assert_eq!(p4,tp4);
assert_eq!(p5,tp5);
assert_eq!(p6,tp6);
assert_eq!(p7,tp7);
assert_eq!(p8,tp8);
println!("recevied cond: {p1},{p2},{p3},{p4:?},{p5},{p6},{p7},{p8},");
p1+p5+p6+p7+p8
}).into_task();
let mut c8: Box<dyn Task> = Box::new(c8.task);
c8.as_param_mut().map(
|e|
e.set(0, &tp1) &&
e.set(1, &tp2) &&
e.set(2, &tp3) &&
e.set(3, &tp4) &&
e.set(4, &tp5) &&
e.set(5, &tp6) &&
e.set(6, &tp7) &&
e.set(7, &tp8)
);
let r = c8.run();
let r = r.downcast::<i32>().unwrap();
assert_eq!(*r, tr8);
}