1use std::future::Future;
2use std::marker::PhantomData;
3use std::ops::Add;
4
5use frunk_core::coproduct::{CNil, CoproductSubsetter};
6use frunk_core::hlist::{HCons, HNil};
7
8use crate::control::Cancelled;
9use crate::coproduct::{AsyncHandleMut, AsyncHandleWith, HandleMut, HandleWith, HandlersToEffects};
10use crate::coroutine::{Co, CoSend, GenericCo, Yielder};
11use crate::effect::{CanStart, Effects, Resumes};
12use crate::locality::{Local, Locality, Sendable};
13
14pub type Effectful<'a, Effs, R, L = Local> = Program<'a, Effs, R, L, Effs, HNil>;
33
34#[deprecated(since = "0.3.0", note = "renamed to `Effectful`")]
36pub type Eff<'a, Effs, R, L = Local> = Effectful<'a, Effs, R, L>;
37
38pub struct Program<'a, Effs: Effects<'a>, Result, L: Locality, Remaining, Handlers> {
45 pub(crate) co: GenericCo<'a, Effs, Result, L>,
46 handlers: Handlers,
47 _remaining: PhantomData<Remaining>,
48}
49
50impl<'a, Result> Program<'a, CNil, Result, Local, CNil, HNil> {
51 pub fn new<Effs, F>(
64 f: impl FnOnce(Yielder<'a, Effs>) -> F + 'a,
65 ) -> Program<'a, Effs, Result, Local, Effs, HNil>
66 where
67 Effs: Effects<'a>,
68 F: Future<Output = Result>,
69 {
70 Program::from_co(Co::new(f))
71 }
72}
73
74impl<'a, Result> Program<'a, CNil, Result, Sendable, CNil, HNil> {
75 pub fn new_send<Effs, F>(
88 f: impl FnOnce(Yielder<'a, Effs>) -> F + Send + 'a,
89 ) -> Program<'a, Effs, Result, Sendable, Effs, HNil>
90 where
91 Effs: Effects<'a>,
92 for<'r> Resumes<'r, CanStart<Effs>>: Send + Sync,
93 F: Future<Output = Result> + Send,
94 {
95 Program::from_co(CoSend::new(f))
96 }
97}
98
99impl<'a, Effs, R, L> Program<'a, Effs, R, L, Effs, HNil>
100where
101 Effs: Effects<'a>,
102 L: Locality,
103{
104 #[inline]
106 pub fn from_co(co: GenericCo<'a, Effs, R, L>) -> Self {
107 Program {
108 co,
109 handlers: HNil,
110 _remaining: PhantomData,
111 }
112 }
113}
114
115type HandleEffects<'a, Remaining, H, Effs, HandleIdx, SubsetIdx> =
116 <Remaining as CoproductSubsetter<
117 <H as HandlersToEffects<'a, Effs, HandleIdx>>::Effects,
118 SubsetIdx,
119 >>::Remainder;
120
121impl<'a, Effs, R, L, Remaining, Handlers> Program<'a, Effs, R, L, Remaining, Handlers>
122where
123 Effs: Effects<'a>,
124 L: Locality,
125{
126 #[allow(clippy::type_complexity)]
132 #[inline]
133 pub fn handle<F, HandleIdx, SubsetIdx>(
134 self,
135 handler: F,
136 ) -> Program<
137 'a,
138 Effs,
139 R,
140 L,
141 HandleEffects<'a, Remaining, HCons<F, HNil>, Effs, HandleIdx, SubsetIdx>,
142 <Handlers as Add<HCons<F, HNil>>>::Output,
143 >
144 where
145 HCons<F, HNil>: HandlersToEffects<'a, Effs, HandleIdx>,
146 Remaining: CoproductSubsetter<
147 <HCons<F, HNil> as HandlersToEffects<'a, Effs, HandleIdx>>::Effects,
148 SubsetIdx,
149 >,
150 Handlers: Add<HCons<F, HNil>>,
151 {
152 self.handle_all(HCons {
153 head: handler,
154 tail: HNil,
155 })
156 }
157
158 #[allow(clippy::type_complexity)]
165 #[inline]
166 pub fn handle_all<H, HandleIdx, SubsetIdx>(
167 self,
168 handlers: H,
169 ) -> Program<
170 'a,
171 Effs,
172 R,
173 L,
174 HandleEffects<'a, Remaining, H, Effs, HandleIdx, SubsetIdx>,
175 <Handlers as Add<H>>::Output,
176 >
177 where
178 H: HandlersToEffects<'a, Effs, HandleIdx>,
179 Remaining: CoproductSubsetter<H::Effects, SubsetIdx>,
180 Handlers: Add<H>,
181 {
182 Program {
183 co: self.co,
184 handlers: self.handlers + handlers,
185 _remaining: PhantomData,
186 }
187 }
188}
189
190impl<'a, Effs, R, L, Handlers> Program<'a, Effs, R, L, CNil, Handlers>
191where
192 Effs: Effects<'a>,
193 L: Locality,
194{
195 #[inline]
197 pub fn run_sync<Indices>(self) -> Result<R, Cancelled>
198 where
199 Effs: HandleMut<'a, Effs, Handlers, Indices>,
200 {
201 let mut handlers = self.handlers;
202 crate::sync::run(self.co, &mut handlers)
203 }
204
205 #[inline]
207 pub fn run_sync_stateful<S, Indices>(self, state: &mut S) -> Result<R, Cancelled>
208 where
209 Effs: HandleWith<'a, Effs, Handlers, S, Indices>,
210 {
211 let handlers = self.handlers;
212 crate::sync::run_stateful(self.co, state, &handlers)
213 }
214
215 #[inline]
217 pub async fn run<Indices>(self) -> Result<R, Cancelled>
218 where
219 Effs: AsyncHandleMut<'a, Effs, Handlers, Indices>,
220 {
221 let mut handlers = self.handlers;
222 crate::asynk::run(self.co, &mut handlers).await
223 }
224
225 #[inline]
227 pub async fn run_stateful<S, Indices>(self, state: &mut S) -> Result<R, Cancelled>
228 where
229 Effs: AsyncHandleWith<'a, Effs, Handlers, S, Indices>,
230 {
231 let handlers = self.handlers;
232 crate::asynk::run_stateful(self.co, state, &handlers).await
233 }
234}