Skip to content

Commit 1118bd6

Browse files
async, asyncInterrupt, sleep
1 parent 5efd738 commit 1118bd6

File tree

3 files changed

+106
-11
lines changed

3 files changed

+106
-11
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
part of "effect.dart";
2+
3+
class AsyncContext<L, R> {
4+
final _deferred = Deferred<L, R>.unsafeMake();
5+
6+
void succeed(R value) => _deferred.unsafeCompleteExit(Right(value));
7+
void fail(L error) => _deferred.unsafeCompleteExit(Left(Failure(error)));
8+
void failCause(Cause<L> cause) => _deferred.unsafeCompleteExit(Left(cause));
9+
void die(dynamic defect) => _deferred.unsafeCompleteExit(Left(
10+
Die(defect, StackTrace.current),
11+
));
12+
}

packages/fpdart/lib/src/effect.dart

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import './extension/future_or_extension.dart';
66
import './extension/iterable_extension.dart';
77
import 'unit.dart' as fpdart_unit;
88

9+
part 'async_context.dart';
910
part 'context.dart';
1011
part 'deferred.dart';
1112
part 'either.dart';
@@ -152,18 +153,70 @@ final class Effect<E, L, R> extends IEffect<E, L, R> {
152153
(_) => f().then(Right.new),
153154
);
154155

156+
/// {@category constructors}
157+
factory Effect.fail(L value) => Effect.from((_) => Left(Failure(value)));
158+
159+
/// {@category constructors}
160+
factory Effect.failCause(Cause<L> cause) => Effect.from((_) => Left(cause));
161+
162+
/// {@category constructors}
163+
factory Effect.succeed(R value) => Effect.from((_) => Right(value));
164+
155165
/// {@category constructors}
156166
factory Effect.lazy(Effect<E, L, R> Function() effect) =>
157167
Effect.from((context) => effect()._unsafeRun(context));
158168

159169
/// {@category constructors}
160-
factory Effect.fail(L value) => Effect.from((_) => Left(Failure(value)));
170+
factory Effect.async(void Function(AsyncContext<L, R> resume) callback) =>
171+
Effect.from(
172+
(context) {
173+
final asyncContext = AsyncContext<L, R>();
174+
callback(asyncContext);
175+
return asyncContext._deferred.wait<E>()._unsafeRun(context);
176+
},
177+
);
161178

162179
/// {@category constructors}
163-
factory Effect.failCause(Cause<L> cause) => Effect.from((_) => Left(cause));
180+
factory Effect.asyncInterrupt(
181+
Effect<Null, Never, Unit> Function(AsyncContext<L, R> resume) callback,
182+
) =>
183+
Effect.from((context) {
184+
final asyncContext = AsyncContext<L, R>();
185+
186+
final finalizer = callback(asyncContext);
187+
if (asyncContext._deferred.unsafeCompleted) {
188+
return asyncContext._deferred.wait<E>()._unsafeRun(context);
189+
}
190+
191+
final interruption = context.signal.wait<E>().alwaysIgnore(
192+
finalizer.withEnv<E>(),
193+
);
194+
195+
return asyncContext._deferred
196+
.wait<E>()
197+
.race(interruption)
198+
._unsafeRun(context.withoutSignal);
199+
});
164200

165201
/// {@category constructors}
166-
factory Effect.succeed(R value) => Effect.from((_) => Right(value));
202+
static Effect<E, L, void> sleep<E, L>(Duration duration) =>
203+
Effect.asyncInterrupt(
204+
(resume) {
205+
final timer = Timer(duration, () {
206+
resume.succeed(null);
207+
});
208+
209+
if (resume._deferred.unsafeCompleted) {
210+
timer.cancel();
211+
return resume._deferred.wait<Null>().match(
212+
onFailure: (_) => fpdart_unit.unit,
213+
onSuccess: (_) => fpdart_unit.unit,
214+
);
215+
}
216+
217+
return Effect.unit();
218+
},
219+
);
167220

168221
/// {@category constructors}
169222
factory Effect.raceAll(Iterable<Effect<E, L, R>> iterable) =>
@@ -189,14 +242,6 @@ final class Effect<E, L, R> extends IEffect<E, L, R> {
189242
);
190243
});
191244

192-
/// {@category constructors}
193-
static Effect<E, L, void> sleep<E, L>(Duration duration) => Effect.from(
194-
(_) => Future.delayed(
195-
duration,
196-
() => const Right(null),
197-
),
198-
);
199-
200245
/// {@category constructors}
201246
static Effect<E, Never, Never> die<E>(dynamic defect) => Effect.from(
202247
(_) => Left(Die.current(defect)),

packages/fpdart/test/src/effect/effect_constructors_test.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,44 @@ void main() {
1717
expect(result, "error");
1818
});
1919

20+
group('async', () {
21+
test('succeed callback', () async {
22+
final main = Effect<Null, String, int>.async(
23+
(resume) => resume.succeed(10),
24+
);
25+
final result = await main.runFuture();
26+
expect(result, 10);
27+
});
28+
29+
test('fail callback', () async {
30+
final main = Effect<Null, String, int>.async(
31+
(resume) => resume.fail("error"),
32+
);
33+
final result = await main.flip().runFuture();
34+
expect(result, "error");
35+
});
36+
37+
test('succeed async callback', () async {
38+
final main = Effect<Null, String, int>.async(
39+
(resume) => Future.delayed(Duration(milliseconds: 100)).then(
40+
(_) => resume.succeed(10),
41+
),
42+
);
43+
final result = await main.runFuture();
44+
expect(result, 10);
45+
});
46+
47+
test('fail async callback', () async {
48+
final main = Effect<Null, String, int>.async(
49+
(resume) => Future.delayed(Duration(milliseconds: 100)).then(
50+
(_) => resume.fail("error"),
51+
),
52+
);
53+
final result = await main.flip().runFuture();
54+
expect(result, "error");
55+
});
56+
});
57+
2058
group('tryCatch', () {
2159
test('executes once', () {
2260
var mutable = 0;

0 commit comments

Comments
 (0)