Skip to content

Commit

Permalink
introduce Scope
Browse files Browse the repository at this point in the history
  • Loading branch information
SandroMaglione committed Mar 29, 2024
1 parent 56f9ad7 commit bed477a
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
28 changes: 28 additions & 0 deletions packages/fpdart/lib/src/effect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ part 'context.dart';
part 'deferred.dart';
part 'either.dart';
part 'option.dart';
part 'scope.dart';

typedef EffectGen<E, L> = ({
FutureOr<A> Function<A>(IEffect<E, L, A>) async,
Expand Down Expand Up @@ -160,6 +161,10 @@ final class Effect<E, L, R> extends IEffect<E, L, R> {
(_) => f().then(Right.new),
);

/// {@category constructors}
factory Effect.lazy(Effect<E, L, R> Function() effect) =>
Effect.from((context) => effect().__unsafeRun(context));

/// {@category constructors}
factory Effect.fail(L value) => Effect.from((_) => Left(Failure(value)));

Expand Down Expand Up @@ -480,6 +485,15 @@ final class Effect<E, L, R> extends IEffect<E, L, R> {
Effect<E, L, R> race(Effect<E, L, R> effect) =>
Effect.raceAll([this, effect]);

/// {@category sequencing}
Effect<E, L, R> alwaysIgnore<C>(Effect<E, L, C> effect) => Effect.from(
(context) => race(context.signal.wait()).__unsafeRun(context).then(
(exit) => effect.__unsafeRun(context.withoutSignal).then(
(_) => exit,
),
),
);

/// {@category sequencing}
Effect<E, L, C> flatMap<C>(Effect<E, L, C> Function(R r) f) => Effect.from(
(context) => _unsafeRun(context).then(
Expand Down Expand Up @@ -632,6 +646,20 @@ final class Effect<E, L, R> extends IEffect<E, L, R> {

/// {@category interruption}
Effect<E, Never, R> interrupt() => Effect.failCause(const Interrupted());

/// {@category scoping}
Effect<Scope<E>, L, R> get scopedEnv => Effect.from(
(context) => __unsafeRun(context.withEnv(context.env.env)),
);
}

extension EffectWithScope<E, L, R> on Effect<Scope<E>, L, R> {
Effect<E, L, R> get scoped => Effect.from((context) {
final scope = Scope.withEnv(context.env);
return alwaysIgnore(scope.closeScope()).__unsafeRun(
context.withEnv(scope),
);
});
}

extension ProvideNull<L, R> on Effect<Null, L, R> {
Expand Down
4 changes: 4 additions & 0 deletions packages/fpdart/lib/src/extension/iterable_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ extension FpdartOnIterableOfIterable<T> on Iterable<Iterable<T>> {
Iterable<T> get flatten => expand(identity);
}

extension IterableEffect<E, L, R> on Iterable<Effect<E, L, R>> {
Effect<E, L, Iterable<R>> get all => Effect.all(this);
}

extension FpdartSequenceIterableOption<R> on Iterable<Option<R>> {
Iterable<R> get getSomes => Option.getSomes(this);
}
Expand Down
44 changes: 44 additions & 0 deletions packages/fpdart/lib/src/scope.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
part of "effect.dart";

mixin ScopeMixin {
bool get scopeClosable => false;

final scopeFinalizers = <Effect<Null, Never, Unit>>[];

Effect<E, L, Unit> addScopeFinalizer<E, L>(
Effect<Null, Never, Unit> finalizer,
) =>
Effect.functionSucceed(() {
scopeFinalizers.add(finalizer);
return unit;
});

Effect<E, L, Unit> removeScopeFinalizer<L, E>(
Effect<Null, Never, Unit> finalizer,
) =>
Effect.functionSucceed(() {
scopeFinalizers.remove(finalizer);
return unit;
});

Effect<E, L, Unit> closeScope<E, L>() => Effect.lazy(
() => scopeFinalizers.reversed.all.zipRight(Effect.functionSucceed(
() {
scopeFinalizers.clear();
return unit;
},
)).withEnv(),
);
}

class Scope<R> with ScopeMixin {
final bool _closable;
final R env;
Scope._(this.env, this._closable);

factory Scope.withEnv(R env, [bool closable = false]) =>
Scope._(env, closable);

@override
bool get scopeClosable => _closable;
}

0 comments on commit bed477a

Please sign in to comment.