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.
Mixed-in types
Available Extensions
Properties
hashCode no setter inherited
int get hashCodeThe 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
external int get hashCode;runtimeType no setter inherited
Type get runtimeTypeA representation of the runtime type of the object.
Inherited from Object.
Implementation
external Type get runtimeType;Methods
allocated()
IO<Record> allocated()Returns the allocated resource and a release function.
Implementation
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
IO<(A, Function1<ExitCase, IO<Unit>>)> allocatedCase() =>
_interpretAllocatedCase(this, (_) => IO.unit);ap() inherited
Apply f to the value of this Applicative.
Inherited from Monad.
Implementation
@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
Resource<B> as<B>(B b) => map((_) => b);attempt()
Extracts any exceptions encountered during evaluation into an Either value.
Implementation
Resource<Either<Object, A>> attempt() {
// 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'),
};
}
// 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;
}
// 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'),
};
// 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(),
),
);
}
// Outermost continuation produces Resource<A>, so attempt yields Either<Object, A>.
// Use .map() rather than a direct cast to avoid runtime failures when the
// intermediate dynamic Left from the Bind/Allocate path is reified.
return result.map((e) => e.map((a) => a as A));
}evalMap()
Applies the side-effecting function f to the value generated by this resource, returning it's value.
Implementation
Resource<B> evalMap<B>(Function1<A, IO<B>> f) => flatMap((a) => Resource.eval(f(a)));evalTap()
Performs the side-effect encoded in f using the value created by this Resource, then returning the original value.
Implementation
Resource<A> evalTap<B>(Function1<A, IO<B>> f) => flatMap((a) => Resource.eval(f(a)).as(a));flatMap() override
Applyf to the value in this monadic context, returning the result in the same context.
Implementation
@override
Resource<B> flatMap<B>(Function1<A, Resource<B>> f) => Bind(this, Fn1(f));flatTap()
Like flatMap but discards the result of f, returning the original value.
Implementation
Resource<A> flatTap<B>(Function1<A, Resource<B>> f) => flatMap((a) => f(a).as(a));guaranteeCase()
Attaches a finalizer that is invoked with the Outcome of the resource evaluation.
Implementation
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()
Intercepts any upstream errors, sequencing in the Resource generated by f.
Implementation
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
@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:
dynamic object = 1;
object.add(42); // Statically allowed, run-time errorThis 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:
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
@pragma("vm:entry-point")
@pragma("wasm:entry-point")
external dynamic noSuchMethod(Invocation invocation);onCancel()
Attaches a finalizer that runs when this resource is canceled.
Implementation
Resource<A> onCancel(Resource<Unit> fin) =>
Resource.applyFull((poll) => poll(allocatedCase()).onCancel(fin.use_()));onFinalize()
Attaches an unconditional finalizer to this resource.
Implementation
Resource<A> onFinalize(IO<Unit> f) => onFinalizeCase((_) => f);onFinalizeCase()
Attaches a finalizer that can discriminate the ExitCase.
Implementation
Resource<A> onFinalizeCase(Function1<ExitCase, IO<Unit>> f) =>
Resource.makeCase(IO.unit, (_, ec) => f(ec)).flatMap((_) => this);preAllocate()
Runs precede prior to the allocation of this resource.
Implementation
Resource<A> preAllocate(IO<Unit> precede) => Resource.eval(precede).flatMap((_) => this);surround()
Allocates this resource, runs fb and then closes this resource when fb finishes, regardless of the outcome.
Implementation
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
external String toString();use()
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
IO<B> use<B>(Function1<A, IO<B>> f) => _interpretUse(this, f, (a, b) => a(b));use_()
Like use but allocates the resource and then immediately releases it.
Implementation
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
IO<Never> useForever() => use((_) => IO.never());voided()
Discards the value of this resource, returning Unit.
Implementation
Resource<Unit> voided() => as(Unit());Extension Methods
evalMapN() extension
Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension
Implementation
Resource<T5> evalMapN<T5>(Function4<T1, T2, T3, T4, IO<T5>> f) => evalMap(f.tupled);evalMapN() extension
Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension
Implementation
Resource<T6> evalMapN<T6>(Function5<T1, T2, T3, T4, T5, IO<T6>> f) => evalMap(f.tupled);evalMapN() extension
Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension
Implementation
Resource<T3> evalMapN<T3>(Function2<T1, T2, IO<T3>> f) => evalMap(f.tupled);evalMapN() extension
Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension
Implementation
Resource<T4> evalMapN<T4>(Function3<T1, T2, T3, IO<T4>> f) => evalMap(f.tupled);evalTapN() extension
Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension
Implementation
Resource<(T1, T2, T3)> evalTapN<T4>(Function3<T1, T2, T3, IO<T4>> f) => evalTap(f.tupled);evalTapN() extension
Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension
Implementation
Resource<(T1, T2, T3, T4, T5)> evalTapN<T6>(Function5<T1, T2, T3, T4, T5, IO<T6>> f) =>
evalTap(f.tupled);evalTapN() extension
Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension
Implementation
Resource<(T1, T2)> evalTapN<T3>(Function2<T1, T2, IO<T3>> f) => evalTap(f.tupled);evalTapN() extension
Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension
Implementation
Resource<(T1, T2, T3, T4)> evalTapN<T5>(Function4<T1, T2, T3, T4, IO<T5>> f) => evalTap(f.tupled);flatMapN() extension
Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension
Implementation
Resource<T6> flatMapN<T6>(Function5<T1, T2, T3, T4, T5, Resource<T6>> f) => flatMap(f.tupled);flatMapN() extension
Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension
Implementation
Resource<T3> flatMapN<T3>(Function2<T1, T2, Resource<T3>> f) => flatMap(f.tupled);flatMapN() extension
Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension
Implementation
Resource<T5> flatMapN<T5>(Function4<T1, T2, T3, T4, Resource<T5>> f) => flatMap(f.tupled);flatMapN() extension
Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension
Implementation
Resource<T4> flatMapN<T4>(Function3<T1, T2, T3, Resource<T4>> f) => flatMap(f.tupled);flatTapN() extension
Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension
Implementation
Resource<(T1, T2, T3, T4)> flatTapN<T5>(Function4<T1, T2, T3, T4, Resource<T5>> f) =>
flatTap(f.tupled);flatTapN() extension
Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension
Implementation
Resource<(T1, T2)> flatTapN<T3>(Function2<T1, T2, Resource<T3>> f) => flatTap(f.tupled);flatTapN() extension
Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension
Implementation
Resource<(T1, T2, T3, T4, T5)> flatTapN<T6>(Function5<T1, T2, T3, T4, T5, Resource<T6>> f) =>
flatTap(f.tupled);flatTapN() extension
Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension
Implementation
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
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
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
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
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
IO<A> useEval() => use(identity);useN() extension
Available on Resource<A>, provided by the ResourceTuple5Ops<T1, T2, T3, T4, T5> extension
Implementation
IO<T6> useN<T6>(Function5<T1, T2, T3, T4, T5, IO<T6>> f) => use(f.tupled);useN() extension
Available on Resource<A>, provided by the ResourceTuple2Ops<T1, T2> extension
Implementation
IO<T3> useN<T3>(Function2<T1, T2, IO<T3>> f) => use(f.tupled);useN() extension
Available on Resource<A>, provided by the ResourceTuple4Ops<T1, T2, T3, T4> extension
Implementation
IO<T5> useN<T5>(Function4<T1, T2, T3, T4, IO<T5>> f) => use(f.tupled);useN() extension
Available on Resource<A>, provided by the ResourceTuple3Ops<T1, T2, T3> extension
Implementation
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 == omust be true.Symmetric: For all objects
o1ando2,o1 == o2ando2 == o1must either both be true, or both be false.Transitive: For all objects
o1,o2, ando3, ifo1 == o2ando2 == o3are true, theno1 == o3must 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
external bool operator ==(Object other);Static Properties
canceled no setter
Creates a Resource that is immediately canceled.
Implementation
static Resource<Unit> get canceled => Resource.eval(IO.canceled);cede no setter
Introduces an asynchronous boundary in the Resource/IO runtime loop that can be used for cancelation checking and fairness, among other things.
Implementation
static Resource<Unit> get cede => Resource.eval(IO.cede);unit no setter
Alias for Resource.pure(Unit()).
Implementation
static Resource<Unit> get unit => Resource.pure(Unit());Static Methods
apply()
Creates a resource from an allocating effect.
The provided resource will supply both the result and the finalizer.
Implementation
static Resource<A> apply<A>(IO<(A, IO<Unit>)> resource) => applyCase(
resource.map(
(tup) => tup(
(a, release) => (a, (_) => release),
),
),
);applyCase()
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
static Resource<A> applyCase<A>(
IO<(A, Function1<ExitCase, IO<Unit>>)> resource,
) => applyFull((_) => resource);applyFull()
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
static Resource<A> applyFull<A>(
Function1<Poll, IO<(A, Function1<ExitCase, IO<Unit>>)>> resource,
) => Allocate(resource);both()
Allocated both resources asynchronously, and combines the result from each into a tuple.
Implementation
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()
Lifts the given IO a into a Resource, providing no finalizer.
Implementation
static Resource<A> eval<A>(IO<A> a) => Eval(a);make()
Creates a Resource using the allocation acquire and the finalizer release.
Implementation
static Resource<A> make<A>(IO<A> acquire, Function1<A, IO<Unit>> release) =>
apply(acquire.map((a) => (a, release(a))));makeCase()
Creates a Resource using the allocation acquire and the finalizer release, which can take different actions depending on the ExitCase.
Implementation
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
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()
Creates a Resource using the cancelable allocation acquire and the finalizer release.
Implementation
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
static Resource<A> never<A>() => Resource.eval(IO.never());pure()
Resource<B> pure<A>(A a)Lifts the pure value a into Resource.
Implementation
static Resource<A> pure<A>(A a) => Pure(a);race()
Implementation
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
static Resource<A> raiseError<A>(Object err) => Resource.eval(IO.raiseError(err));ref()
Creates a new Ref with an initial value of a, lifted into a Resource.
Implementation
static Resource<Ref<A>> ref<A>(A a) => Resource.eval(Ref.of(a));suspend()
Defers the creation of a Resource until the returned IO is evaluated.
Implementation
static Resource<A> suspend<A>(IO<Resource<A>> fr) => Resource.eval(fr).flatMap((r) => r);