Created with <3 with dartpad.dev.
Last active
January 5, 2023 10:55
-
-
Save priezz/59853d90dab5c4382a6bfa86d6f8fff7 to your computer and use it in GitHub Desktop.
Sealed classes for Dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// --------------------------------------------------------------------------------- // | |
/// GENERATED ---> /// | |
class _ResultBaseModel<T> { | |
_ResultBaseModel({required this.value}); | |
T value; | |
} | |
abstract class Result<T> implements ISerializable { | |
final _ResultBaseModel<T> _model = _ResultBaseModel<T>(); | |
T get value => _model.value; | |
@override | |
Json toJson() => { | |
'value': value, | |
}; | |
/// >>> SEALED SPECIFIC | |
factory Result.failure({required T value, required String message}) => | |
ResultFailure<T>(value: value, message: message); | |
factory Result.success({required T value}) => ResultSuccess<T>(value: value); | |
Result._(); | |
factory Result.fromJson(Json json) { | |
switch (json['@class']) { | |
case 'ResultFailure': | |
return ResultFailure<T>.fromJson(json); | |
case 'ResultSuccess': | |
return ResultSuccess<T>.fromJson(json); | |
default: | |
throw Exception('Could not deserialize Result from $json'); | |
} | |
} | |
R? maybe<R>({ | |
R Function(ResultFailure<T>)? failure, | |
R Function(ResultSuccess<T>)? success, | |
R Function()? $else, | |
}) { | |
final self = this; | |
if (success != null && self is ResultSuccess<T>) { | |
return success(self); | |
} else if (failure != null && self is ResultFailure<T>) { | |
return failure(self); | |
} else if ($else != null) { | |
return $else(); | |
} else { | |
return null; | |
} | |
} | |
R? whenOrNull<R>({ | |
R Function(ResultFailure<T>)? failure, | |
R Function(ResultSuccess<T>)? success, | |
}) { | |
final self = this; | |
if (self is ResultSuccess<T>) { | |
return success?.call(self); | |
} else if (self is ResultFailure<T>) { | |
return failure?.call(self); | |
} else { | |
throw Exception('Unexpected subclass of Result.'); | |
} | |
} | |
R when<R>({ | |
required R Function(ResultFailure<T>) failure, | |
required R Function(ResultSuccess<T>) success, | |
}) => whenOrNull( | |
failure: failure, | |
success: success, | |
)!; | |
R? whenFailure<R>(R Function(ResultFailure<T>) f) => this is ResultFailure<T> ? f(this as ResultFailure<T>) : null; | |
R? whenSuccess<R>(R Function(ResultSuccess<T>) f) => this is ResultSuccess<T> ? f(this as ResultSuccess<T>) : null; | |
ResultFailure<T>? get asFailureOrNull => castOrNull(this); | |
ResultFailure<T>? get asSuccessOrNull => castOrNull(this); | |
/// <<< SEALED SPECIFIC | |
} | |
/// SEALED SPECIFIC | |
class _ResultFailureModel<T> extends _ResultBaseModel<T> { | |
late String message; | |
} | |
class ResultFailure<T> extends Result<T> { | |
factory ResultFailure({required T value, required String message}) => | |
ResultFailure._build( | |
(b) => b | |
..message = message | |
..value = value, | |
); | |
ResultFailure._build( | |
void Function(_ResultFailureModel<T>) builder, | |
/// >>> SEALED SPECIFIC | |
): super._() { | |
/// <<< SEALED SPECIFIC | |
builder.call(_model); | |
} | |
factory ResultFailure.fromJson(Json json) { | |
/// >>> SEALED SPECIFIC | |
if (json['@class'] != 'ResultFailure') { | |
throw Exception('Invalid json data for ResultSuccess. $json'); | |
} | |
/// <<< SEALED SPECIFIC | |
return ResultFailure._fromModel(_modelFromJson<T>(json)); | |
} | |
factory ResultFailure._fromModel( | |
_ResultFailureModel<T> source, | |
) => | |
ResultFailure<T>._build((dest) => _modelCopy<T>(source, dest)); | |
static void _modelCopy<T>( | |
_ResultFailureModel<T> source, | |
_ResultFailureModel<T> dest, | |
) { | |
dest.message = source.message; | |
dest.value = source.value; | |
} | |
static _ResultFailureModel<T> _modelFromJson<T>( | |
Json json, | |
) => _ResultFailureModel() | |
..message = json['message'] as String | |
..value = json['value']; | |
@override | |
// ignore: overridden_fields | |
final _ResultFailureModel<T> _model = _ResultFailureModel(); | |
String get message => _model.message; | |
@override | |
Json toJson() => { | |
/// >>> SEALED SPECIFIC | |
'@class': 'ResultFailure', | |
...super.toJson(), | |
/// <<< SEALED SPECIFIC | |
'message': _model.message, | |
}; | |
} | |
/// SEALED SPECIFIC | |
class _ResultSuccessModel<T> extends _ResultBaseModel<T> { | |
} | |
class ResultSuccess<T> extends Result<T> { | |
factory ResultSuccess({required T value}) => | |
ResultSuccess._build( | |
(b) => b | |
..value = value, | |
); | |
ResultSuccess._build( | |
void Function(_ResultSuccessModel<T>) builder, | |
/// >>> SEALED SPECIFIC | |
): super._() { | |
/// <<< SEALED SPECIFIC | |
builder.call(_model); | |
} | |
factory ResultSuccess.fromJson(Json json) { | |
/// >>> SEALED SPECIFIC | |
if (json['@class'] != 'ResultSuccess') { | |
throw Exception('Invalid json data for ResultSuccess. $json'); | |
} | |
/// <<< SEALED SPECIFIC | |
return ResultSuccess._fromModel(_modelFromJson<T>(json)); | |
} | |
factory ResultSuccess._fromModel( | |
_ResultSuccessModel<T> source, | |
) => | |
ResultSuccess<T>._build((dest) => _modelCopy<T>(source, dest)); | |
static void _modelCopy<T>( | |
_ResultSuccessModel<T> source, | |
_ResultSuccessModel<T> dest, | |
) { | |
dest.value = source.value; | |
} | |
static _ResultSuccessModel<T> _modelFromJson<T>( | |
Json json, | |
) => _ResultSuccessModel() | |
..value = json['value']; | |
@override | |
// ignore: overridden_fields | |
final _ResultSuccessModel<T> _model = _ResultSuccessModel(); | |
@override | |
Json toJson() => { | |
/// >>> SEALED SPECIFIC | |
'@class': 'ResultSuccess', | |
...super.toJson(), | |
/// <<< SEALED SPECIFIC | |
}; | |
} | |
/// <--- GENERATED /// | |
// --------------------------------------------------------------------------------- // | |
// @sealed | |
// ignore: unused_element | |
abstract class _ResultModel<T> { | |
Class failure(String message); | |
Class success(); | |
late T value; | |
} | |
// @sealed | |
// ignore: unused_element | |
abstract class _RustResultModel<Success, Failure> { | |
Class failure(Failure error); | |
Class success(Success value); | |
} | |
extension ResultX<T> on Result<T> { | |
display() { | |
final String result = when( | |
failure: (f) => '${f.value}: ${f.message}', | |
success: (s) => '${s.value}', | |
); | |
print(result); | |
} | |
} | |
void main() { | |
try { | |
final Result<int> result = Result.failure(value: 404, message: 'Not found'); | |
print(result.runtimeType); | |
result.display(); | |
final Map json = result.toJson(); | |
final Result otherResult = Result.fromJson(json); | |
print(otherResult.runtimeType); | |
otherResult.display(); | |
final Result<int> otherResult2 = Result.fromJson(json); | |
print(otherResult2.runtimeType); | |
otherResult2.display(); | |
final Result<int> otherResult3 = ResultSuccess.fromJson(json); | |
print(otherResult3.runtimeType); | |
otherResult3.display(); | |
} catch(e) { | |
print('\n$e'); | |
} | |
} | |
// --------------------------------------------------------------------------------- // | |
/// From data_classes.dart | |
T? castOrNull<T>(dynamic x) => x != null && x is T ? x : null; | |
abstract class ISerializable {} | |
typedef Class = void; | |
typedef Json = Map<dynamic, dynamic>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// GENERATED START /// | |
abstract class Result<T> extends _ResultSealed<T> { | |
Result._({this.value}); | |
factory Result.Failure() => _ResultFailure<T>(); | |
factory Result.Success(T value) => _ResultSuccess<T>(value); | |
T? value; | |
R when<R>({ | |
required R Function() Failure, | |
required R Function() Success, | |
}) { | |
if (this is _ResultSuccess<T>) { | |
return Success(); | |
} else if (this is _ResultFailure) { | |
return Failure(); | |
} else { | |
throw Exception('[Result] class cannot be instantiated directly.'); | |
} | |
} | |
} | |
class _ResultSuccess<T> extends Result<T> { | |
_ResultSuccess(T value): super._(value: value) {Success(value);} | |
} | |
class _ResultFailure<T> extends Result<T> { | |
_ResultFailure(): super._() {Failure();} | |
} | |
/// GENERATED END /// | |
// ---------------------------------------------------------------------- // | |
// | |
@sealed | |
class _ResultSealed<T> { | |
Failure() {} | |
Success(T value) {score = 10;} | |
int score = 0; | |
} | |
extension ResultX<T> on Result<T> { | |
display<T>() { | |
final int score = when<( | |
Success: (s) => f.value ? s.score : 0, | |
Failure: (f) => f.score, | |
); | |
print('$str: $score'); | |
} | |
} | |
Result<bool> getResult() => Result.Success(true); | |
void main() { | |
getResult().display(); | |
test(a: null); | |
final n = null; | |
// _defaultNull.p(); | |
// null.p(); | |
} | |
extension on int? { | |
p() => print('int, ${this.runtimeType}'); | |
} | |
extension on Null { | |
p() => print('null'); | |
} | |
const _defaultNull = null; | |
// class Ii implements int {} | |
test({int? a = _defaultNull, int? b = _defaultNull}) { | |
final bool withA = a != _defaultNull; | |
final bool withB = b != _defaultNull; | |
// final bool withA = a is Null; | |
// final bool withB = b is Null; | |
print('a provided: $withA'); | |
print('b provided: $withB'); | |
// _defaultNull.p(); | |
// if (a == null) (a as Null).p(); | |
a.p(); | |
b.p(); | |
// if (b == null) (b as Null).p(); | |
} | |
// copyWith({int? value}) --> copyWith({V<int?>? value} = const V<int?>()) (edited) | |
// white_check_mark | |
// +1 | |
// heavy_check_mark | |
// 10:02 | |
// copyWith();. | |
// copyWith(value: V(10)); | |
// copyWith(value: V(null)); (edited) | |
// 10:04 | |
// copy((b) => b.value = 10); (edited) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment