Skip to content

Commit

Permalink
refactor impl (#10)
Browse files Browse the repository at this point in the history
* refactor impl

* refactor impl
  • Loading branch information
hoc081098 committed Aug 21, 2022
1 parent 3f55472 commit 555b0d0
Showing 1 changed file with 45 additions and 47 deletions.
92 changes: 45 additions & 47 deletions lib/src/dart_either.dart
Expand Up @@ -16,9 +16,6 @@ extension on Object {
if (this is ControlError) {
throw this;
}
if (this is _InvalidEitherError) {
throw this;
}
return this;
}
}
Expand Down Expand Up @@ -76,6 +73,23 @@ T Function(Object?) _const<T>(T t) => (_) => t;
abstract class Either<L, R> {
const Either._();

Object? get _unionValue;

@pragma('vm:always-consider-inlining')
@pragma('vm:prefer-inline')
@pragma('dart2js:tryInline')
C _foldInternal<C>({
required C Function(L value) ifLeft,
required C Function(R value) ifRight,
}) {
if (isLeft) {
return ifLeft(_unionValue as L);
} else {
assert(isRight);
return ifRight(_unionValue as R);
}
}

// -----------------------------------------------------------------------------
//
// BEGIN: constructors
Expand Down Expand Up @@ -417,13 +431,11 @@ abstract class Either<L, R> {
final result = ListBuilder<R>();

for (final either in values) {
if (either is Left<L, R>) {
return Either<L, BuiltList<R>>.left(either.value);
}
if (either is Right<L, R>) {
result.add(either.value);
if (either.isLeft) {
return Either<L, BuiltList<R>>.left(either._unionValue as L);
} else {
throw _InvalidEitherError<L, R>(either);
assert(either.isRight);
result.add(either._unionValue as R);
}
}

Expand Down Expand Up @@ -476,11 +488,11 @@ abstract class Either<L, R> {
// -----------------------------------------------------------------------------

/// Returns `true` if this is a [Left], `false` otherwise.
/// Used only for performance instead of fold.
/// Used only for performance instead of [fold].
bool get isLeft;

/// Returns `true` if this is a [Right], `false` otherwise.
/// Used only for performance instead of fold.
/// Used only for performance instead of [fold].
bool get isRight;

/// Applies [ifLeft] if this is a [Left] or [ifRight] if this is a [Right].
Expand All @@ -503,16 +515,8 @@ abstract class Either<L, R> {
C fold<C>({
required C Function(L value) ifLeft,
required C Function(R value) ifRight,
}) {
final self = this;
if (self is Left<L, R>) {
return ifLeft(self.value);
}
if (self is Right<L, R>) {
return ifRight(self.value);
}
throw _InvalidEitherError<L, R>(self);
}
}) =>
_foldInternal(ifLeft: ifLeft, ifRight: ifRight);

/// If this is a [Right], applies [ifRight] with [initial] and [Right.value].
/// Returns [initial] otherwise.
Expand All @@ -525,7 +529,8 @@ abstract class Either<L, R> {
///
/// result.foldLeft<String>(initial, combine); // Result: 'dart_either hoc081098'
/// ```
C foldLeft<C>(C initial, C Function(C acc, R element) rightOperation) => fold(
C foldLeft<C>(C initial, C Function(C acc, R element) rightOperation) =>
_foldInternal(
ifLeft: _const(initial),
ifRight: (r) => rightOperation(initial, r),
);
Expand All @@ -537,7 +542,7 @@ abstract class Either<L, R> {
/// Left<String, Never>('left').swap(); // Result: Right('left')
/// Right<Never, String>('right').swap(); // Result: Left('right')
/// ```
Either<R, L> swap() => fold(
Either<R, L> swap() => _foldInternal(
ifLeft: (l) => Either.right(l),
ifRight: (r) => Either.left(r),
);
Expand All @@ -549,7 +554,7 @@ abstract class Either<L, R> {
/// Right<int, int>(12).map((_) => 'flower'); // Result: Right('flower')
/// Left<int, int>(12).map((_) => 'flower'); // Result: Left(12)
/// ```
Either<L, C> map<C>(C Function(R value) f) => fold(
Either<L, C> map<C>(C Function(R value) f) => _foldInternal(
ifLeft: (l) => Either<L, C>.left(l),
ifRight: (r) => Either<L, C>.right(f(r)),
);
Expand All @@ -561,7 +566,7 @@ abstract class Either<L, R> {
/// Right<int, int>(12).mapLeft((_) => 'flower'); // Result: Right(12)
/// Left<int, int>(12).mapLeft((_) => 'flower'); // Result: Left('flower')
/// ```
Either<C, R> mapLeft<C>(C Function(L value) f) => fold(
Either<C, R> mapLeft<C>(C Function(L value) f) => _foldInternal(
ifLeft: (l) => Either<C, R>.left(f(l)),
ifRight: (r) => Either<C, R>.right(r),
);
Expand All @@ -581,7 +586,7 @@ abstract class Either<L, R> {
/// Left<String, int>('12').flatMap((v) => Right<String, String>('flower $v')); // Result: Left('12')
/// Left<String, int>('12').flatMap((v) => Left<String, String>('flower $v')); // Result: Left('12')
/// ```
Either<L, C> flatMap<C>(Either<L, C> Function(R value) f) => fold(
Either<L, C> flatMap<C>(Either<L, C> Function(R value) f) => _foldInternal(
ifLeft: (l) => Either<L, C>.left(l),
ifRight: (r) => f(r),
);
Expand Down Expand Up @@ -612,7 +617,7 @@ abstract class Either<L, R> {
required C Function(L value) leftOperation,
required D Function(R value) rightOperation,
}) =>
fold(
_foldInternal(
ifLeft: (l) => Either.left(leftOperation(l)),
ifRight: (r) => Either.right(rightOperation(r)),
);
Expand All @@ -628,7 +633,7 @@ abstract class Either<L, R> {
/// Left<int, int>(12).exists((v) => v > 10); // Result: false
/// Left<int, int>(12).exists((v) => v < 10); // Result: false
/// ```
bool exists(bool Function(R value) predicate) => fold(
bool exists(bool Function(R value) predicate) => _foldInternal(
ifLeft: _const(false),
ifRight: predicate,
);
Expand All @@ -640,7 +645,7 @@ abstract class Either<L, R> {
/// Right<int, int>(12).getOrElse(() => 17); // Result: 12
/// Left<int, int>(12).getOrElse(() => 17); // Result: 17
/// ```
R getOrElse(R Function() defaultValue) => fold(
R getOrElse(R Function() defaultValue) => _foldInternal(
ifLeft: (_) => defaultValue(),
ifRight: _identity,
);
Expand All @@ -652,7 +657,7 @@ abstract class Either<L, R> {
/// Right<int, int>(12).orNull(); // Result: 12
/// Left<int, int>(12).orNull(); // Result: null
/// ```
R? orNull() => fold(
R? orNull() => _foldInternal(
ifLeft: _const(null),
ifRight: _identity,
);
Expand All @@ -665,7 +670,7 @@ abstract class Either<L, R> {
/// Right<int, int>(12).getOrHandle((v) => 17); // Result: 12
/// Left<int, int>(12).getOrHandle((v) => v + 5); // Result: 17
/// ```
R getOrHandle(R Function(L value) defaultValue) => fold(
R getOrHandle(R Function(L value) defaultValue) => _foldInternal(
ifLeft: defaultValue,
ifRight: _identity,
);
Expand Down Expand Up @@ -694,14 +699,12 @@ abstract class Either<L, R> {
required C Function(Left<L, R> left) ifLeft,
required C Function(Right<L, R> right) ifRight,
}) {
final self = this;
if (self is Left<L, R>) {
return ifLeft(self);
}
if (self is Right<L, R>) {
return ifRight(self);
if (isLeft) {
return ifLeft(this as Left<L, R>);
} else {
assert(isRight);
return ifRight(this as Right<L, R>);
}
throw _InvalidEitherError<L, R>(self);
}
}

Expand Down Expand Up @@ -729,6 +732,9 @@ class Left<L, R> extends Either<L, R> {

@override
String toString() => 'Either.Left($value)';

@override
L get _unionValue => value;
}

/// The right side of the disjoint union, as opposed to the [Left] side.
Expand All @@ -755,17 +761,9 @@ class Right<L, R> extends Either<L, R> {

@override
String toString() => 'Either.Right($value)';
}

class _InvalidEitherError<L, R> extends Error {
final Either<L, R> invalid;

_InvalidEitherError(this.invalid);

@override
String toString() =>
'Unknown $invalid. $invalid must be either a `Right<$L, $R>` or `Left<$L, $R>`.'
' Cannot implement or extend `Either` class';
R get _unionValue => value;
}

// -----------------------------------------------------------------------------
Expand Down

0 comments on commit 555b0d0

Please sign in to comment.