Resolvable<T extends Object> constructor
Resolvable<T extends Object> (
- @mustBeAnonymous @mustAwaitAllFutures FutureOr<
T> mustAwaitAllFutures(), { - @noFutures TOnErrorCallback<
T> ? onError, - @noFutures TVoidCallback? onFinalize,
Creates a Sync or Async depending on the return type of
mustAwaitAllFutures.
IMPORTANT:
Always all futures witin mustAwaitAllFutures to ensure errors are be
caught and propagated.
Implementation
factory Resolvable(
@mustBeAnonymous
@mustAwaitAllFutures
FutureOr<T> Function() mustAwaitAllFutures, {
@noFutures TOnErrorCallback<T>? onError,
@noFutures TVoidCallback? onFinalize,
}) {
// The closure invocation must NOT escape — a synchronous throw needs to
// become an Err on the returned Sync, not propagate to the caller. This
// is the library's core "absorb all throws" contract.
Result<T> result;
try {
final v = mustAwaitAllFutures();
if (v is Future<T>) {
return Async(() => v, onError: onError, onFinalize: onFinalize);
}
result = Ok(v);
} on Err catch (err) {
// Preserve a user-thrown Err verbatim — statusCode and breadcrumbs are
// load-bearing for life-critical callers. `onError` does NOT fire for
// Err throws: an Err is already a structured error value.
result = err.transfErr<T>();
} catch (error, stackTrace) {
// Non-Err throw — route through `onError` if the caller supplied one.
if (onError == null) {
result = Err<T>(error, stackTrace: stackTrace);
} else {
try {
result = onError(error, stackTrace);
} on Err catch (err) {
result = err.transfErr<T>();
} catch (error, stackTrace) {
result = Err<T>(error, stackTrace: stackTrace);
}
}
}
// Run `onFinalize` separately so its throws are absorbed into `result`
// instead of escaping this factory. A thrown finalize error overrides
// whatever `result` held — failed cleanup is a meaningful failure mode
// that callers need to see, surfaced as `Sync.err(...)` to keep the
// package's no-throw contract intact.
if (onFinalize != null) {
try {
onFinalize();
} on Err catch (err) {
result = err.transfErr<T>();
} catch (error, stackTrace) {
result = Err<T>(error, stackTrace: stackTrace);
}
}
return Sync.result(result);
}