Skip to content

Resource<A> sealed

sealed class Resource<A> with Functor<A>, Applicative<A>, Monad<A>

Resource is a type that encodes the idea of performing some kind of action or allocation which in turn, requires a finalizer of some kind that must be run to clean up the allocation.

A common example is opening a file to read/write to it, which requires closing the file after, or else risking a leak.

Properties

hashCode no setter inherited

int get hashCode

The hash code for this object.

A hash code is a single integer which represents the state of the object that affects operator == comparisons.

All objects have hash codes. The default hash code implemented by Object represents only the identity of the object, the same way as the default operator == implementation only considers objects equal if they are identical (see identityHashCode).

If operator == is overridden to use the object state instead, the hash code must also be changed to represent that state, otherwise the object cannot be used in hash based data structures like the default Set and Map implementations.

Hash codes must be the same for objects that are equal to each other according to operator ==. The hash code of an object should only change if the object changes in a way that affects equality. There are no further requirements for the hash codes. They need not be consistent between executions of the same program and there are no distribution guarantees.

Objects that are not equal are allowed to have the same hash code. It is even technically allowed that all instances have the same hash code, but if clashes happen too often, it may reduce the efficiency of hash-based data structures like HashSet or HashMap.

If a subclass overrides hashCode, it should override the operator == operator as well to maintain consistency.

Inherited from Object.

Implementation
dart
external int get hashCode;

runtimeType no setter inherited

Type get runtimeType

A representation of the runtime type of the object.

Inherited from Object.

Implementation
dart
external Type get runtimeType;

Methods

allocated()

IO<Record> allocated()

Returns the allocated resource and a release function.

Implementation
dart
IO<(A, IO<Unit>)> allocated() => IO.uncancelable(
  (poll) => poll(allocatedCase()).mapN((b, fin) => (b, fin(ExitCase.succeeded()))),
);

allocatedCase()

IO<Record> allocatedCase()

Returns the resource and a release function that accepts an ExitCase.

Implementation
dart
IO<(A, Function1<ExitCase, IO<Unit>>)> allocatedCase() =>
    _interpretAllocatedCase(this, (_) => IO.unit);

ap() inherited

Monad<B> ap<B>(Monad<B Function(A)> f)

Apply f to the value of this Applicative.

Inherited from Monad.

Implementation
dart
@override
Monad<B> ap<B>(covariant Monad<Function1<A, B>> f) => flatMap((a) => f.map((f) => f(a)));

as()

Resource<B> as<B>(B b)

Replaces the result of this Resource with the given value b.

Implementation
dart
Resource<B> as<B>(B b) => map((_) => b);

attempt()

Resource<Either<Object, A>> attempt()

Extracts any exceptions encountered during evaluation into an Either value.

Implementation
dart
Resource<Either<Object, A>> attempt() {
  &#47;&#47; Handle non-Bind nodes directly
  if (this is! Bind) {
    return switch (this) {
      final Allocate<A> a => Resource.applyFull(
        (poll) => a
            .resource(poll)
            .attempt()
            .map(
              (att) => att.fold(
                (err) => (err.asLeft(), (_) => IO.unit),
                (a) => a((a, release) => (a.asRight(), release)),
              ),
            ),
      ),
      final Pure<A> p => Resource.pure(p.value.asRight()),
      final Eval<A> e => Resource.eval(e.task.attempt()),
      _ => throw UnimplementedError('Resource.attempt unhandled node: $this'),
    };
  }

  &#47;&#47; Walk Bind chain iteratively, collecting continuations
  final conts = <Fn1<dynamic, Resource<dynamic>>>[];
  Resource<dynamic> leaf = this;

  while (leaf is Bind<dynamic, dynamic>) {
    conts.add(leaf.f);
    leaf = leaf.source;
  }

  &#47;&#47; Handle the leaf node
  Resource<Either<Object, dynamic>> result = switch (leaf) {
    final Allocate<dynamic> a => Resource.applyFull(
      (poll) => a
          .resource(poll)
          .attempt()
          .map(
            (att) => att.fold(
              (err) => (err.asLeft(), (_) => IO.unit),
              (a) => a((a, release) => (Right(a), release)),
            ),
          ),
    ),
    final Pure<dynamic> p => Resource.pure(Right<Object, dynamic>(p.value)),
    final Eval<dynamic> e => Resource.eval(e.task.attempt()),
    _ => throw UnimplementedError('Resource.attempt unhandled node: $leaf'),
  };

  &#47;&#47; Chain each continuation (innermost first)
  for (int i = conts.length - 1; i >= 0; i--) {
    final cont = conts[i];
    final prev = result;
    result = Resource.unit
        .flatMap((_) => prev)
        .flatMap(
          (att) => att.fold(
            (err) => Resource.pure(err.asLeft()),
            (s) => cont(s).attempt(),
          ),
        );
  }

  &#47;&#47; Outermost continuation produces Resource<A>, so attempt yields Either<Object, A>.
  &#47;&#47; Use .map() rather than a direct cast to avoid runtime failures when the
  &#47;&#47; intermediate dynamic Left from the Bind&#47;Allocate path is reified.
  return result.map((e) => e.map((a) => a as A));
}

evalMap()

Resource<B> evalMap<B>(IO<B> Function(A) f)

Applies the side-effecting function f to the value generated by this resource, returning it's value.

Implementation
dart
Resource<B> evalMap<B>(Function1<A, IO<B>> f) => flatMap((a) => Resource.eval(f(a)));

evalTap()

Resource<A> evalTap<B>(IO<B> Function(A) f)

Performs the side-effect encoded in f using the value created by this Resource, then returning the original value.

Implementation
dart
Resource<A> evalTap<B>(Function1<A, IO<B>> f) => flatMap((a) => Resource.eval(f(a)).as(a));

flatMap() override

Resource<B> flatMap<B>(Resource<B> Function(A) f)

Applyf to the value in this monadic context, returning the result in the same context.

Implementation
dart
@override
Resource<B> flatMap<B>(Function1<A, Resource<B>> f) => Bind(this, Fn1(f));

flatTap()

Resource<A> flatTap<B>(Resource<B> Function(A) f)

Like flatMap but discards the result of f, returning the original value.

Implementation
dart
Resource<A> flatTap<B>(Function1<A, Resource<B>> f) => flatMap((a) => f(a).as(a));

guaranteeCase()

Resource<A> guaranteeCase(Resource<Unit> Function(Outcome<A>) fin)

Attaches a finalizer that is invoked with the Outcome of the resource evaluation.

Implementation
dart
Resource<A> guaranteeCase(Function1<Outcome<A>, Resource<Unit>> fin) {
  return Resource.applyFull((poll) {
    return poll(allocatedCase()).guaranteeCase((outcome) {
      return outcome.fold(
        () => fin(Outcome.canceled()).use_(),
        (err, st) => fin(Outcome.errored(err, st)).use_().handleError((_) => Unit()),
        (ft) {
          final (a, finEC) = ft;

          return fin(Outcome.succeeded(a)).use_().handleErrorWith(
            (err) => finEC(
              ExitCase.errored(err),
            ).handleError((_) => Unit()).productR(IO.raiseError(err)),
          );
        },
      );
    });
  });
}

handleErrorWith()

Resource<A> handleErrorWith(Resource<A> Function(Object) f)

Intercepts any upstream errors, sequencing in the Resource generated by f.

Implementation
dart
Resource<A> handleErrorWith(Function1<Object, Resource<A>> f) =>
    attempt().flatMap((att) => att.fold((err) => f(err), (a) => Resource.pure(a)));

map() override

Resource<B> map<B>(B Function(A) f)

Applies f to the value of this Functor.

Implementation
dart
@override
Resource<B> map<B>(Function1<A, B> f) => flatMap((a) => Resource.pure(f(a)));

noSuchMethod() inherited

dynamic noSuchMethod(Invocation invocation)

Invoked when a nonexistent method or property is accessed.

A dynamic member invocation can attempt to call a member which doesn't exist on the receiving object. Example:

dart
dynamic object = 1;
object.add(42); // Statically allowed, run-time error

This invalid code will invoke the noSuchMethod method of the integer 1 with an Invocation representing the .add(42) call and arguments (which then throws).

Classes can override noSuchMethod to provide custom behavior for such invalid dynamic invocations.

A class with a non-default noSuchMethod invocation can also omit implementations for members of its interface. Example:

dart
class MockList<T> implements List<T> {
  noSuchMethod(Invocation invocation) {
    log(invocation);
    super.noSuchMethod(invocation); // Will throw.
  }
}
void main() {
  MockList().add(42);
}

This code has no compile-time warnings or errors even though the MockList class has no concrete implementation of any of the List interface methods. Calls to List methods are forwarded to noSuchMethod, so this code will log an invocation similar to Invocation.method(#add, [42]) and then throw.

If a value is returned from noSuchMethod, it becomes the result of the original invocation. If the value is not of a type that can be returned by the original invocation, a type error occurs at the invocation.

The default behavior is to throw a NoSuchMethodError.

Inherited from Object.

Implementation
dart
@pragma("vm:entry-point")
@pragma("wasm:entry-point")
external dynamic noSuchMethod(Invocation invocation);

onCancel()

Resource<A> onCancel(Resource<Unit> fin)

Attaches a finalizer that runs when this resource is canceled.

Implementation
dart
Resource<A> onCancel(Resource<Unit> fin) =>
    Resource.applyFull((poll) => poll(allocatedCase()).onCancel(fin.use_()));

onFinalize()

Resource<A> onFinalize(IO<Unit> f)

Attaches an unconditional finalizer to this resource.

Implementation
dart
Resource<A> onFinalize(IO<Unit> f) => onFinalizeCase((_) => f);

onFinalizeCase()

Resource<A> onFinalizeCase(IO<Unit> Function(ExitCase) f)

Attaches a finalizer that can discriminate the ExitCase.

Implementation
dart
Resource<A> onFinalizeCase(Function1<ExitCase, IO<Unit>> f) =>
    Resource.makeCase(IO.unit, (_, ec) => f(ec)).flatMap((_) => this);

preAllocate()

Resource<A> preAllocate(IO<Unit> precede)

Runs precede prior to the allocation of this resource.

Implementation
dart
Resource<A> preAllocate(IO<Unit> precede) => Resource.eval(precede).flatMap((_) => this);

surround()

IO<B> surround<B>(IO<B> fb)

Allocates this resource, runs fb and then closes this resource when fb finishes, regardless of the outcome.

Implementation
dart
IO<B> surround<B>(IO<B> fb) => use((_) => fb);

toString() inherited

String toString()

A string representation of this object.

Some classes have a default textual representation, often paired with a static parse function (like int.parse). These classes will provide the textual representation as their string representation.

Other classes have no meaningful textual representation that a program will care about. Such classes will typically override toString to provide useful information when inspecting the object, mainly for debugging or logging.

Inherited from Object.

Implementation
dart
external String toString();

use()

IO<B> use<B>(IO<B> Function(A) f)

Allocates this resource and provides it to the given function f. When f completes, regardless of the outcome, the finalizer for this Resource will be invoked.

Implementation
dart
IO<B> use<B>(Function1<A, IO<B>> f) => _interpretUse(this, f, (a, b) => a(b));

use_()

IO<Unit> use_()

Like use but allocates the resource and then immediately releases it.

Implementation
dart
IO<Unit> use_() => use((_) => IO.unit);

useForever()

IO<Never> useForever()

Allocates this resource and supplies a function that will never finish, meaning the resource finalizer will not be invoked.

Implementation
dart
IO<Never> useForever() => use((_) => IO.never());

voided()

Resource<Unit> voided()

Discards the value of this resource, returning Unit.

Implementation
dart
Resource<Unit> voided() => as(Unit());

Extension Methods

evalMapN() extension

Resource<T5> evalMapN<T5>(IO<T5> Function(T1, T2, T3, T4) f)

Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension

Implementation
dart
Resource<T5> evalMapN<T5>(Function4<T1, T2, T3, T4, IO<T5>> f) => evalMap(f.tupled);

evalMapN() extension

Resource<T6> evalMapN<T6>(IO<T6> Function(T1, T2, T3, T4, T5) f)

Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension

Implementation
dart
Resource<T6> evalMapN<T6>(Function5<T1, T2, T3, T4, T5, IO<T6>> f) => evalMap(f.tupled);

evalMapN() extension

Resource<T3> evalMapN<T3>(IO<T3> Function(T1, T2) f)

Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension

Implementation
dart
Resource<T3> evalMapN<T3>(Function2<T1, T2, IO<T3>> f) => evalMap(f.tupled);

evalMapN() extension

Resource<T4> evalMapN<T4>(IO<T4> Function(T1, T2, T3) f)

Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension

Implementation
dart
Resource<T4> evalMapN<T4>(Function3<T1, T2, T3, IO<T4>> f) => evalMap(f.tupled);

evalTapN() extension

Resource<Record> evalTapN<T4>(IO<T4> Function(T1, T2, T3) f)

Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension

Implementation
dart
Resource<(T1, T2, T3)> evalTapN<T4>(Function3<T1, T2, T3, IO<T4>> f) => evalTap(f.tupled);

evalTapN() extension

Resource<Record> evalTapN<T6>(IO<T6> Function(T1, T2, T3, T4, T5) f)

Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension

Implementation
dart
Resource<(T1, T2, T3, T4, T5)> evalTapN<T6>(Function5<T1, T2, T3, T4, T5, IO<T6>> f) =>
    evalTap(f.tupled);

evalTapN() extension

Resource<Record> evalTapN<T3>(IO<T3> Function(T1, T2) f)

Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension

Implementation
dart
Resource<(T1, T2)> evalTapN<T3>(Function2<T1, T2, IO<T3>> f) => evalTap(f.tupled);

evalTapN() extension

Resource<Record> evalTapN<T5>(IO<T5> Function(T1, T2, T3, T4) f)

Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension

Implementation
dart
Resource<(T1, T2, T3, T4)> evalTapN<T5>(Function4<T1, T2, T3, T4, IO<T5>> f) => evalTap(f.tupled);

flatMapN() extension

Resource<T6> flatMapN<T6>(Resource<T6> Function(T1, T2, T3, T4, T5) f)

Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension

Implementation
dart
Resource<T6> flatMapN<T6>(Function5<T1, T2, T3, T4, T5, Resource<T6>> f) => flatMap(f.tupled);

flatMapN() extension

Resource<T3> flatMapN<T3>(Resource<T3> Function(T1, T2) f)

Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension

Implementation
dart
Resource<T3> flatMapN<T3>(Function2<T1, T2, Resource<T3>> f) => flatMap(f.tupled);

flatMapN() extension

Resource<T5> flatMapN<T5>(Resource<T5> Function(T1, T2, T3, T4) f)

Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension

Implementation
dart
Resource<T5> flatMapN<T5>(Function4<T1, T2, T3, T4, Resource<T5>> f) => flatMap(f.tupled);

flatMapN() extension

Resource<T4> flatMapN<T4>(Resource<T4> Function(T1, T2, T3) f)

Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension

Implementation
dart
Resource<T4> flatMapN<T4>(Function3<T1, T2, T3, Resource<T4>> f) => flatMap(f.tupled);

flatTapN() extension

Resource<Record> flatTapN<T5>(Resource<T5> Function(T1, T2, T3, T4) f)

Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension

Implementation
dart
Resource<(T1, T2, T3, T4)> flatTapN<T5>(Function4<T1, T2, T3, T4, Resource<T5>> f) =>
    flatTap(f.tupled);

flatTapN() extension

Resource<Record> flatTapN<T3>(Resource<T3> Function(T1, T2) f)

Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension

Implementation
dart
Resource<(T1, T2)> flatTapN<T3>(Function2<T1, T2, Resource<T3>> f) => flatTap(f.tupled);

flatTapN() extension

Resource<Record> flatTapN<T6>(Resource<T6> Function(T1, T2, T3, T4, T5) f)

Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension

Implementation
dart
Resource<(T1, T2, T3, T4, T5)> flatTapN<T6>(Function5<T1, T2, T3, T4, T5, Resource<T6>> f) =>
    flatTap(f.tupled);

flatTapN() extension

Resource<Record> flatTapN<T4>(Resource<T4> Function(T1, T2, T3) f)

Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension

Implementation
dart
Resource<(T1, T2, T3)> flatTapN<T4>(Function3<T1, T2, T3, Resource<T4>> f) => flatTap(f.tupled);

mapN() extension

Resource<T6> mapN<T6>(T6 Function(T1, T2, T3, T4, T5) f)

Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension

Implementation
dart
Resource<T6> mapN<T6>(Function5<T1, T2, T3, T4, T5, T6> f) => map(f.tupled);

mapN() extension

Resource<T3> mapN<T3>(T3 Function(T1, T2) f)

Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension

Implementation
dart
Resource<T3> mapN<T3>(Function2<T1, T2, T3> f) => map(f.tupled);

mapN() extension

Resource<T5> mapN<T5>(T5 Function(T1, T2, T3, T4) f)

Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension

Implementation
dart
Resource<T5> mapN<T5>(Function4<T1, T2, T3, T4, T5> f) => map(f.tupled);

mapN() extension

Resource<T4> mapN<T4>(T4 Function(T1, T2, T3) f)

Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension

Implementation
dart
Resource<T4> mapN<T4>(Function3<T1, T2, T3, T4> f) => map(f.tupled);

useEval() extension

IO<A> useEval()

Allocates this resource and evaluates the inner IO, releasing the resource afterwards.

Available on Resource<A>, provided by the ResourceIOOps<A> extension

Implementation
dart
IO<A> useEval() => use(identity);

useN() extension

IO<T6> useN<T6>(IO<T6> Function(T1, T2, T3, T4, T5) f)

Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension

Implementation
dart
IO<T6> useN<T6>(Function5<T1, T2, T3, T4, T5, IO<T6>> f) => use(f.tupled);

useN() extension

IO<T3> useN<T3>(IO<T3> Function(T1, T2) f)

Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension

Implementation
dart
IO<T3> useN<T3>(Function2<T1, T2, IO<T3>> f) => use(f.tupled);

useN() extension

IO<T5> useN<T5>(IO<T5> Function(T1, T2, T3, T4) f)

Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension

Implementation
dart
IO<T5> useN<T5>(Function4<T1, T2, T3, T4, IO<T5>> f) => use(f.tupled);

useN() extension

IO<T4> useN<T4>(IO<T4> Function(T1, T2, T3) f)

Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension

Implementation
dart
IO<T4> useN<T4>(Function3<T1, T2, T3, IO<T4>> f) => use(f.tupled);

Operators

operator ==() inherited

bool operator ==(Object other)

The equality operator.

The default behavior for all Objects is to return true if and only if this object and other are the same object.

Override this method to specify a different equality relation on a class. The overriding method must still be an equivalence relation. That is, it must be:

  • Total: It must return a boolean for all arguments. It should never throw.

  • Reflexive: For all objects o, o == o must be true.

  • Symmetric: For all objects o1 and o2, o1 == o2 and o2 == o1 must either both be true, or both be false.

  • Transitive: For all objects o1, o2, and o3, if o1 == o2 and o2 == o3 are true, then o1 == o3 must be true.

The method should also be consistent over time, so whether two objects are equal should only change if at least one of the objects was modified.

If a subclass overrides the equality operator, it should override the hashCode method as well to maintain consistency.

Inherited from Object.

Implementation
dart
external bool operator ==(Object other);

Static Properties

canceled no setter

Resource<Unit> get canceled

Creates a Resource that is immediately canceled.

Implementation
dart
static Resource<Unit> get canceled => Resource.eval(IO.canceled);

cede no setter

Resource<Unit> get cede

Introduces an asynchronous boundary in the Resource/IO runtime loop that can be used for cancelation checking and fairness, among other things.

Implementation
dart
static Resource<Unit> get cede => Resource.eval(IO.cede);

unit no setter

Resource<Unit> get unit

Alias for Resource.pure(Unit()).

Implementation
dart
static Resource<Unit> get unit => Resource.pure(Unit());

Static Methods

apply()

Resource<A> apply<A>(IO<Record> resource)

Creates a resource from an allocating effect.

The provided resource will supply both the result and the finalizer.

Implementation
dart
static Resource<A> apply<A>(IO<(A, IO<Unit>)> resource) => applyCase(
  resource.map(
    (tup) => tup(
      (a, release) => (a, (_) => release),
    ),
  ),
);

applyCase()

Resource<A> applyCase<A>(IO<Record> resource)

Creates a resource from an allocating effect.

The provided resource will supply both the result and the finalizer, which can discriminate the ExitCase of the evaluation.

Implementation
dart
static Resource<A> applyCase<A>(
  IO<(A, Function1<ExitCase, IO<Unit>>)> resource,
) => applyFull((_) => resource);

applyFull()

Resource<A> applyFull<A>(IO<Record> Function(Poll) resource)

Creates a resource from an allocating effect.

The provided resource will supply both the result, which accepts a Poll that can be used for canelable resource acquisitions, and the finalizer, which can discriminate the ExitCase of the evaluation.

Implementation
dart
static Resource<A> applyFull<A>(
  Function1<Poll, IO<(A, Function1<ExitCase, IO<Unit>>)>> resource,
) => Allocate(resource);

both()

Resource<Record> both<A, B>(Resource<A> ra, Resource<B> rb)

Allocated both resources asynchronously, and combines the result from each into a tuple.

Implementation
dart
static Resource<(A, B)> both<A, B>(Resource<A> ra, Resource<B> rb) {
  IO<C> allocate<C>(Resource<C> r, _Update storeFinalizer) {
    return _interpretUse(
      r,
      IO.pure,
      (release, _) => storeFinalizer(
        (fin) => (ec) => IO.unit.productR(fin(ec).guarantee(release(ec))),
      ),
    );
  }

  _Finalizer noop() => (_) => IO.unit;
  final bothFinalizers = Ref.of((noop(), noop()));

  return Resource.makeCase(bothFinalizers, (finalizers, ec) {
    return finalizers.value().flatMapN((aFin, bFin) => IO.both(aFin(ec), bFin(ec)).voided());
  }).evalMap((store) {
    return IO.both(
      allocate(ra, (f) => store.update((a) => (f(a.$1), a.$2))),
      allocate(rb, (f) => store.update((a) => (a.$1, f(a.$2)))),
    );
  });
}

eval()

Resource<A> eval<A>(IO<A> a)

Lifts the given IO a into a Resource, providing no finalizer.

Implementation
dart
static Resource<A> eval<A>(IO<A> a) => Eval(a);

make()

Resource<A> make<A>(IO<A> acquire, IO<Unit> Function(A) release)

Creates a Resource using the allocation acquire and the finalizer release.

Implementation
dart
static Resource<A> make<A>(IO<A> acquire, Function1<A, IO<Unit>> release) =>
    apply(acquire.map((a) => (a, release(a))));

makeCase()

Resource<A> makeCase<A>(IO<A> acquire, IO<Unit> Function(A, ExitCase) release)

Creates a Resource using the allocation acquire and the finalizer release, which can take different actions depending on the ExitCase.

Implementation
dart
static Resource<A> makeCase<A>(
  IO<A> acquire,
  Function2<A, ExitCase, IO<Unit>> release,
) => applyCase(acquire.map((a) => (a, (ec) => release(a, ec))));

makeCaseFull()

Resource<A> makeCaseFull<A>(
  IO<A> Function(Poll) acquire,
  IO<Unit> Function(A, ExitCase) release,
)

Creates a Resource using the cancelable allocation acquire and the finalizer release, which can discriminate the ExitCase.

Implementation
dart
static Resource<A> makeCaseFull<A>(
  Function1<Poll, IO<A>> acquire,
  Function2<A, ExitCase, IO<Unit>> release,
) => applyFull((poll) => acquire(poll).map((a) => (a, (ec) => release(a, ec))));

makeFull()

Resource<A> makeFull<A>(
  IO<A> Function(Poll) acquire,
  IO<Unit> Function(A) release,
)

Creates a Resource using the cancelable allocation acquire and the finalizer release.

Implementation
dart
static Resource<A> makeFull<A>(
  Function1<Poll, IO<A>> acquire,
  Function1<A, IO<Unit>> release,
) => applyFull((poll) => acquire(poll).map((a) => (a, (_) => release(a))));

never()

Resource<A> never<A>()

Returns a non-terminating Resource. An alias for Resource.eval(IO.never()).

Implementation
dart
static Resource<A> never<A>() => Resource.eval(IO.never());

pure()

Resource<B> pure<A>(A a)

Lifts the pure value a into Resource.

Implementation
dart
static Resource<A> pure<A>(A a) => Pure(a);

race()

Resource<Either<A, B>> race<A, B>(Resource<A> ra, Resource<B> rb)
Implementation
dart
static Resource<Either<A, B>> race<A, B>(Resource<A> ra, Resource<B> rb) {
  return Resource.applyFull((poll) {
    IO<Unit> cancelLoser<C>(IOFiber<(C, Function1<ExitCase, IO<Unit>>)> f) {
      return f.cancel().productR(
        f.join().flatMap(
          (ec) => ec.fold(
            () => IO.unit,
            (_, _) => IO.unit,
            (x) => x.$2(ExitCase.canceled()),
          ),
        ),
      );
    }

    return poll(IO.racePair(ra.allocatedCase(), rb.allocatedCase())).flatMap((either) {
      return either.fold(
        (leftTuple) {
          final (oc, f) = leftTuple;

          return oc.fold(
            () => f.cancel().productR(f.join()).flatMap((oc) {
              return oc.fold(
                () => poll(IO.canceled).productR(IO.never()),
                (err, _) => IO.raiseError(err),
                (b) => IO.pure((b.$1.asRight(), b.$2)),
              );
            }),
            (err, _) => IO
                .raiseError<(Either<A, B>, Function1<ExitCase, IO<Unit>>)>(err)
                .guarantee(cancelLoser(f)),
            (aFin) {
              final (a, fin) = aFin;

              return cancelLoser(f).start().flatMap((f) {
                return IO.pure((
                  a.asLeft(),
                  (ExitCase x) => fin(x).guarantee(f.join().flatMap((oc) => oc.embedNever())),
                ));
              });
            },
          );
        },
        (rightTuple) {
          final (f, oc) = rightTuple;

          return oc.fold(
            () => f.cancel().productR(f.join()).flatMap((oc) {
              return oc.fold(
                () => poll(IO.canceled).productR(IO.never()),
                (err, _) => IO.raiseError(err),
                (b) => IO.pure((b.$1.asLeft(), b.$2)),
              );
            }),
            (err, _) => IO
                .raiseError<(Either<A, B>, Function1<ExitCase, IO<Unit>>)>(err)
                .guarantee(cancelLoser(f)),
            (aFin) {
              final (a, fin) = aFin;

              return cancelLoser(f).start().flatMap((f) {
                return IO.pure((
                  a.asRight(),
                  (ExitCase x) => fin(x).guarantee(f.join().flatMap((oc) => oc.embedNever())),
                ));
              });
            },
          );
        },
      );
    });
  });
}

raiseError()

Resource<A> raiseError<A>(Object err)

Creates a Resource that will inject the given error into the evaluation.

Implementation
dart
static Resource<A> raiseError<A>(Object err) => Resource.eval(IO.raiseError(err));

ref()

Resource<Ref<A>> ref<A>(A a)

Creates a new Ref with an initial value of a, lifted into a Resource.

Implementation
dart
static Resource<Ref<A>> ref<A>(A a) => Resource.eval(Ref.of(a));

suspend()

Resource<A> suspend<A>(IO<Resource<A>> fr)

Defers the creation of a Resource until the returned IO is evaluated.

Implementation
dart
static Resource<A> suspend<A>(IO<Resource<A>> fr) => Resource.eval(fr).flatMap((r) => r);