Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bench/record_result.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: null_check_on_nullable_type_parameter

import 'package:inline_result/inline_result.dart';

extension type RecordResult<T>._((T? value, Exception? exception) _value) {
Expand Down
2 changes: 1 addition & 1 deletion example/inline_result_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import 'package:inline_result/inline_result.dart';

Result<int> divide(int a, int b) {
Result<int, Object> divide(int a, int b) {
return runCatching(() {
if (b == 0) {
throw Exception('Division by zero');
Expand Down
4 changes: 2 additions & 2 deletions lib/src/failure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ part of 'result.dart';

/// Internal class representing a failed Result.
@immutable
class _Failure {
class _Failure<F extends Object> {
/// The exception encapsulated in this failure.
final Exception exception;
final F exception;

/// Optional stacktrace of this failure.
final StackTrace? stacktrace;
Expand Down
12 changes: 6 additions & 6 deletions lib/src/fold.dart
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
part of 'result.dart';

/// Extension providing folding functionality for [Result].
extension ResultFold<T> on Result<T> {
extension ResultFold<T, F extends Object> on Result<T, F> {
/// Combines both cases of Result into a single value.
///
/// [onSuccess] handles successful values.
/// [onFailure] handles exceptions.
@pragma('vm:prefer-inline')
R fold<R>({
required Transformer<T, R> onSuccess,
required FailureTransformer<R, Exception> onFailure,
required FailureTransformer<R, F> onFailure,
}) =>
_value is _Failure
_value is _Failure<F>
? onFailure(_value.exception, _value.stacktrace)
: onSuccess(_value as T);
}

/// Extension providing folding functionality for [Result].
extension FutureResultFold<T> on Future<Result<T>> {
extension FutureResultFold<T, F extends Object> on Future<Result<T, F>> {
/// Combines both cases of Result into a single value.
///
/// [onSuccess] handles successful values.
/// [onFailure] handles exceptions.
@pragma('vm:prefer-inline')
Future<R> fold<R>({
required AsyncTransformer<T, R> onSuccess,
required AsyncFailureTransformer<R, Exception> onFailure,
required AsyncFailureTransformer<R, F> onFailure,
}) =>
then((result) => result._value is _Failure
then((result) => result._value is _Failure<F>
? onFailure(result._value.exception, result._value.stacktrace)
: onSuccess(result._value));
}
8 changes: 4 additions & 4 deletions lib/src/future.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ extension FutureResult<T> on Future<T> {
///
/// - If the [Future] completes successfully, wraps the value in [Result.success].
/// - If the [Future] completes with an [Exception], wraps the exception in [Result.failure].
Future<Result<T>> get asResult =>
then(Result.success).onError<Exception>(Result<T>.failure);
Future<Result<T, F>> asResult<F extends Object>() =>
then(Result<T, F>.success).onError<F>(Result<T, F>.failure);
}

extension FutureOrResult<T> on FutureOr<T> {
FutureOr<Result<T>> get asResult async {
FutureOr<Result<T, F>> asResult<F extends Object>() async {
try {
return Result.success(await this);
} on Exception catch (e, st) {
} on F catch (e, st) {
return Result.failure(e, st);
}
}
Expand Down
42 changes: 34 additions & 8 deletions lib/src/getter.dart
Original file line number Diff line number Diff line change
@@ -1,39 +1,50 @@
part of 'result.dart';

/// Extension providing getters for Result's values
extension ResultGetter<T> on Result<T> {
extension ResultGetter<T, F extends Object> on Result<T, F> {
/// Returns the encapsulated value if successful, otherwise `null`.
@pragma('vm:prefer-inline')
T? get getOrNull => isFailure ? null : _value as T;

/// Returns the encapsulated exception if failed, otherwise `null`.
@pragma('vm:prefer-inline')
Exception? get exceptionOrNull =>
isFailure ? (_value as _Failure).exception : null;
F? get exceptionOrNull => _value is _Failure<F> ? _value.exception : null;

/// Returns the encapsulated stacktrace if failed and there is stacktrace,
/// otherwise `null`.
@pragma('vm:prefer-inline')
StackTrace? get stacktraceOrNull =>
_value is _Failure ? _value.stacktrace : null;
_value is _Failure<F> ? _value.stacktrace : null;

/// Returns the encapsulated value if successful, otherwise throws the exception.
///
/// Throws the encapsulated [Exception] if this Result is a failure.
@pragma('vm:prefer-inline')
T get getOrThrow => _value is _Failure ? throw _value.exception : _value as T;
T get getOrThrow =>
//ignore:only_throw_errors
_value is _Failure<F> ? throw _value.exception : _value as T;

/// Returns the value if successful, otherwise applies [onFailure].
@pragma('vm:prefer-inline')
T getOrElse(FailureTransformer<T, F> onFailure) => _value is _Failure<F>
? onFailure(_value.exception, _value.stacktrace)
: _value as T;

/// Returns the value if successful, otherwise [defaultValue].
@pragma('vm:prefer-inline')
T getOrDefault(T defaultValue) =>
_value is _Failure<F> ? defaultValue : _value as T;
}

/// Extension providing getters for Result's values
extension FutureResultGetter<T> on Future<Result<T>> {
extension FutureResultGetter<T, F extends Object> on Future<Result<T, F>> {
/// Returns the encapsulated value if successful, otherwise `null`.
@pragma('vm:prefer-inline')
Future<T?> get getOrNull => then((result) => result.getOrNull);

/// Returns the encapsulated exception if failed, otherwise `null`.
@pragma('vm:prefer-inline')
Future<Exception?> get exceptionOrNull =>
then((result) => result.exceptionOrNull);
Future<F?> get exceptionOrNull => then((result) => result.exceptionOrNull);

/// Returns the encapsulated stacktrace if failed and there is stacktrace,
/// otherwise `null`.
Expand All @@ -46,4 +57,19 @@ extension FutureResultGetter<T> on Future<Result<T>> {
/// Throws the encapsulated [Exception] if this Result is a failure.
@pragma('vm:prefer-inline')
Future<T> get getOrThrow => then((result) => result.getOrThrow);

/// Returns the value if successful, otherwise applies [onFailure].
@pragma('vm:prefer-inline')
Future<T> getOrElse(AsyncFailureTransformer<T, F> onFailure) =>
then((result) => result._value is _Failure<F>
? onFailure(
result._value.exception,
result._value.stacktrace,
)
: result._value as T);

/// Returns the value if successful, otherwise [defaultValue].
@pragma('vm:prefer-inline')
Future<T> getOrDefault(T defaultValue) =>
then((result) => result.getOrDefault(defaultValue));
}
19 changes: 11 additions & 8 deletions lib/src/on_action.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
part of 'result.dart';

/// Extension providing side-effect methods for [Result].
extension ResultOnActions<T> on Result<T> {
extension ResultOnActions<T, F extends Object> on Result<T, F> {
/// Executes [action] if this Result is a failure and returns itself.
///
/// Useful for logging or handling failures without modifying the Result.
@pragma('vm:prefer-inline')
Result<T> onFailure<E extends Exception>(FailureTransformer<void, E> action) {
if (_value is _Failure && _value.exception is E) {
Result<T, F> onFailure<E extends F>(
FailureTransformer<void, E> action,
) {
if (_value is _Failure<F> && _value.exception is E) {
action(_value.exception as E, _value.stacktrace);
}
return this;
Expand All @@ -17,27 +19,28 @@ extension ResultOnActions<T> on Result<T> {
///
/// Useful for processing successful values without modifying the Result.
@pragma('vm:prefer-inline')
Result<T> onSuccess(Transformer<T, void> action) {
Result<T, F> onSuccess(Transformer<T, void> action) {
if (_value is T) {
action(_value);
}
return this;
}
}

extension FutureResultOnActions<T> on Future<Result<T>> {
extension FutureResultOnActions<T, F extends Object> on Future<Result<T, F>> {
/// Executes [action] if this Result is a failure and returns itself.
///
/// Useful for logging or handling failures without modifying the Result.
@pragma('vm:prefer-inline')
Future<Result<T>> onFailure<E extends Exception>(
FailureTransformer<void, E> action) =>
Future<Result<T, F>> onFailure<E extends F>(
FailureTransformer<void, E> action,
) =>
then((result) => result.onFailure<E>(action));

/// Executes [action] if this Result is successful and returns itself.
///
/// Useful for processing successful values without modifying the Result.
@pragma('vm:prefer-inline')
Future<Result<T>> onSuccess(void Function(T value) action) =>
Future<Result<T, F>> onSuccess(void Function(T value) action) =>
then((result) => result.onSuccess(action));
}
33 changes: 0 additions & 33 deletions lib/src/or.dart

This file was deleted.

31 changes: 16 additions & 15 deletions lib/src/recover.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
part of 'result.dart';

/// Extension providing recovery methods for [Result].
extension ResultRecover<T> on Result<T> {
extension ResultRecover<T, F extends Object> on Result<T, F> {
/// Transforms a failure into a success using [transform].
///
/// If this [Result] is a failure, applies [transform] to the exception and returns
/// a successful [Result] containing the transformed value.
/// If successful, returns the original [Result].
@pragma('vm:prefer-inline')
Result<T> recover<E extends Exception>(FailureTransformer<T, E> transform) =>
_value is _Failure && _value.exception is E
Result<T, F> recover<E extends F>(FailureTransformer<T, E> transform) =>
_value is _Failure<F> && _value.exception is E
? Result.success(transform(_value.exception as E, _value.stacktrace))
: this;

/// Transforms a failure into a success, catching exceptions from [transform].
///
/// Similar to [recover], but wraps any exceptions thrown by [transform] in a [Result].
@pragma('vm:prefer-inline')
Result<T> recoverCatching<E extends Exception>(
Result<T, F> recoverCatching<E extends F>(
FailureTransformer<T, E> transform,
) =>
_value is _Failure && _value.exception is E
_value is _Failure<F> && _value.exception is E
? runCatching(() => transform(
_value.exception as E,
_value.stacktrace,
Expand All @@ -29,18 +29,18 @@ extension ResultRecover<T> on Result<T> {
}

/// Extension providing recovery methods for [Result].
extension FutureResultRecover<T> on Future<Result<T>> {
extension FutureResultRecover<T, F extends Object> on Future<Result<T, F>> {
/// Transforms a failure into a success using [transform].
///
/// If this [Result] is a failure, applies [transform] to the exception and returns
/// a successful [Result] containing the transformed value.
/// If successful, returns the original [Result].
@pragma('vm:prefer-inline')
Future<Result<T>> recover<E extends Exception>(
Future<Result<T, F>> recover<E extends F>(
AsyncFailureTransformer<T, E> transform,
) =>
then((result) async =>
result._value is _Failure && result._value.exception is E
result._value is _Failure<F> && result._value.exception is E
? Result.success(await transform(
result._value.exception as E,
result._value.stacktrace,
Expand All @@ -51,13 +51,14 @@ extension FutureResultRecover<T> on Future<Result<T>> {
///
/// Similar to [recover], but wraps any exceptions thrown by [transform] in a [Result].
@pragma('vm:prefer-inline')
Future<Result<T>> recoverCatching<E extends Exception>(
Future<Result<T, F>> recoverCatching<E extends F>(
AsyncFailureTransformer<T, E> transform,
) =>
then((result) => result._value is _Failure && result._value.exception is E
? transform(
result._value.exception as E,
result._value.stacktrace,
).asResult
: result);
then((result) =>
result._value is _Failure<F> && result._value.exception is E
? transform(
result._value.exception as E,
result._value.stacktrace,
).asResult()
: result);
}
24 changes: 4 additions & 20 deletions lib/src/result.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ part 'getter.dart';

part 'on_action.dart';

part 'or.dart';

part 'recover.dart';

part 'run_catching.dart';
Expand All @@ -26,12 +24,12 @@ typedef Transformer<T, R> = R Function(T value);
typedef AsyncTransformer<T, R> = FutureOr<R> Function(T value);

/// Transform failure result from [exception] and optional [stacktrace] into new value of [R].
typedef FailureTransformer<R, E extends Exception> = R Function(
typedef FailureTransformer<R, E extends Object> = R Function(
E exception,
StackTrace? stacktrace,
);

typedef AsyncFailureTransformer<R, E extends Exception> = FutureOr<R> Function(
typedef AsyncFailureTransformer<R, E extends Object> = FutureOr<R> Function(
E exception,
StackTrace? stacktrace,
);
Expand All @@ -45,28 +43,14 @@ typedef Block<T> = T Function();
/// This is implemented as an extension type for zero-cost wrapping, providing static type safety
/// while having no runtime overhead. Use [Result.success] to wrap successful values and
/// [Result.failure] to wrap exceptions.
extension type const Result<T>._(dynamic _value) {
extension type const Result<T, F extends Object>._(dynamic _value) {
/// Creates a successful Result containing [value].
const factory Result.success(T value) = Result._;

/// Creates a failed Result containing [exception] and optional [stacktrace].
factory Result.failure(Exception exception, [StackTrace? stacktrace]) =>
factory Result.failure(F exception, [StackTrace? stacktrace]) =>
Result._(_Failure(exception, stacktrace));

/// Executes [block] and wraps any thrown [Exception] in a [Result].
///
/// If [block] completes successfully, returns [Result.success] with the result.
/// If [block] throws, returns [Result.failure] with the exception.
@Deprecated('Will be removed. Use global function runCatching instead.')
@pragma('vm:prefer-inline')
static Result<T> runCatching<T>(Block<T> block) {
try {
return Result.success(block());
} on Exception catch (exception, stacktrace) {
return Result.failure(exception, stacktrace);
}
}

/// Returns `true` if this [Result] is successful.
bool get isSuccess => _value is! _Failure;

Expand Down
Loading