Compare commits

..

No commits in common. "5e867e30ee34a18da5d352a75f2a9a75dc22c23f" and "2a469e10e819c9b8866b94805c908c86b25f0486" have entirely different histories.

11 changed files with 130 additions and 128 deletions

View File

@ -5,4 +5,11 @@ linter:
lines_longer_than_80_chars: false lines_longer_than_80_chars: false
use_setters_to_change_properties: false use_setters_to_change_properties: false
avoid_positional_boolean_parameters: false avoid_positional_boolean_parameters: false
avoid_bool_literals_in_conditional_expressions: false avoid_bool_literals_in_conditional_expressions: false
analyzer:
exclude:
- "**/*.g.dart"
- "**/*.freezed.dart"
- "test/"
- "integration_test/"

View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"flake-utils": { "flake-utils": {
"locked": { "locked": {
"lastModified": 1656065134, "lastModified": 1667395993,
"narHash": "sha256-oc6E6ByIw3oJaIyc67maaFcnjYOz1mMcOtHxbEf9NwQ=", "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "bee6a7250dd1b01844a2de7e02e4df7d8a0a206c", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -17,16 +17,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1657540956, "lastModified": 1667610399,
"narHash": "sha256-ihGbOFWtAkENwxBE5kV/yWt2MncvW+BObLDsmxCLo/Q=", "narHash": "sha256-XZd0f4ZWAY0QOoUSdiNWj/eFiKb4B9CJPtl9uO9SYY4=",
"owner": "NANASHI0X74", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "043de04db8a6b0391b3fefaaade160514d866946", "rev": "1dd8696f96db47156e1424a49578fe7dd4ce99a4",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NANASHI0X74", "owner": "NixOS",
"ref": "flutter-3-0-0", "ref": "nixpkgs-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View File

@ -1,7 +1,7 @@
{ {
description = "moxlib"; description = "moxlib";
inputs = { inputs = {
nixpkgs.url = "github:NANASHI0X74/nixpkgs/flutter-3-0-0"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
}; };

View File

@ -13,7 +13,7 @@ class JsonImplementation {
factory JsonImplementation.fromJson(Map<String, dynamic> json) { factory JsonImplementation.fromJson(Map<String, dynamic> json) {
return JsonImplementation(); return JsonImplementation();
} }
Map<String, dynamic> toJson() => {}; Map<String, dynamic> toJson() => {};
} }
@ -29,17 +29,17 @@ class DataWrapper<T extends JsonImplementation> {
/// The actual data. /// The actual data.
final T data; final T data;
Map<String, dynamic> toJson() => {
'id': id,
'data': data.toJson()
};
Map<String, dynamic> toJson() => {'id': id, 'data': data.toJson()}; static DataWrapper fromJson<T extends JsonImplementation>(Map<String, dynamic> json) => DataWrapper<T>(
json['id']! as String,
static DataWrapper fromJson<T extends JsonImplementation>( json['data']! as T,
Map<String, dynamic> json, );
) =>
DataWrapper<T>(
json['id']! as String,
json['data']! as T,
);
DataWrapper reply(T newData) => DataWrapper(id, newData); DataWrapper reply(T newData) => DataWrapper(id, newData);
} }
@ -49,14 +49,16 @@ class DataWrapper<T extends JsonImplementation> {
/// ///
/// awaiting [sendData] will return a [Future] that will resolve to the reresponse when /// awaiting [sendData] will return a [Future] that will resolve to the reresponse when
/// received via [onData]. /// received via [onData].
abstract class AwaitableDataSender<S extends JsonImplementation, abstract class AwaitableDataSender<
R extends JsonImplementation> { S extends JsonImplementation,
R extends JsonImplementation
> {
@mustCallSuper @mustCallSuper
AwaitableDataSender(); AwaitableDataSender();
/// A mapping of ID to completer for pending requests. /// A mapping of ID to completer for pending requests.
final Map<String, Completer<R>> _awaitables = {}; final Map<String, Completer<R>> _awaitables = {};
/// Critical section for accessing [AwaitableDataSender._awaitables]. /// Critical section for accessing [AwaitableDataSender._awaitables].
final Lock _lock = Lock(); final Lock _lock = Lock();
@ -65,7 +67,7 @@ abstract class AwaitableDataSender<S extends JsonImplementation,
/// A logger. /// A logger.
final Logger _log = Logger('AwaitableDataSender'); final Logger _log = Logger('AwaitableDataSender');
@visibleForTesting @visibleForTesting
Map<String, Completer<R>> getAwaitables() => _awaitables; Map<String, Completer<R>> getAwaitables() => _awaitables;
@ -76,38 +78,34 @@ abstract class AwaitableDataSender<S extends JsonImplementation,
/// NOTE: Must be overwritten by the actual implementation /// NOTE: Must be overwritten by the actual implementation
@visibleForOverriding @visibleForOverriding
Future<void> sendDataImpl(DataWrapper data); Future<void> sendDataImpl(DataWrapper data);
/// Sends [data] using [sendDataImpl]. If [awaitable] is true, then a /// Sends [data] using [sendDataImpl]. If [awaitable] is true, then a
/// Future will be returned that can be used to await a response. If it /// Future will be returned that can be used to await a response. If it
/// is false, then null will be imediately resolved. /// is false, then null will be imediately resolved.
Future<R?> sendData( Future<R?> sendData(S data, { bool awaitable = true, @visibleForTesting String? id }) async {
S data, {
bool awaitable = true,
@visibleForTesting String? id,
}) async {
// ignore: no_leading_underscores_for_local_identifiers // ignore: no_leading_underscores_for_local_identifiers
final _id = id ?? _uuid.v4(); final _id = id ?? _uuid.v4();
var future = Future<R?>.value(); var future = Future<R?>.value();
_log.fine('sendData: Waiting to acquire lock...'); _log.fine('sendData: Waiting to acquire lock...');
await _lock.synchronized(() async { await _lock.synchronized(() async {
_log.fine('sendData: Done'); _log.fine('sendData: Done');
if (awaitable) { if (awaitable) {
_awaitables[_id] = Completer(); _awaitables[_id] = Completer();
onAdd(); onAdd();
} }
await sendDataImpl(
DataWrapper<S>(
_id,
data,
),
);
await sendDataImpl( if (awaitable) {
DataWrapper<S>( future = _awaitables[_id]!.future;
_id, }
data,
),
);
if (awaitable) { _log.fine('sendData: Releasing lock...');
future = _awaitables[_id]!.future;
}
_log.fine('sendData: Releasing lock...');
}); });
return future; return future;
@ -130,7 +128,7 @@ abstract class AwaitableDataSender<S extends JsonImplementation,
}); });
completer?.complete(data.data); completer?.complete(data.data);
return completer != null; return completer != null;
} }
} }

16
lib/lists.dart Normal file
View File

@ -0,0 +1,16 @@
/// A wrapper around List<T>.firstWhere that does not throw but instead just
/// returns true if [test] returns true for an element or false if [test] never
/// returned true.
bool listContains<T>(List<T> list, bool Function(T element) test) {
return firstWhereOrNull<T>(list, test) != null;
}
/// A wrapper around [List<T>.firstWhere] that does not throw but instead just
/// return null if [test] never returned true
T? firstWhereOrNull<T>(List<T> list, bool Function(T element) test) {
try {
return list.firstWhere(test);
} catch(e) {
return null;
}
}

View File

@ -1,5 +1,5 @@
library moxlib; library moxlib;
export 'src/awaitabledatasender.dart'; export 'awaitabledatasender.dart';
export 'src/math.dart'; export 'lists.dart';
export 'src/result.dart'; export 'math.dart';

View File

@ -1,24 +0,0 @@
/// Holds a value of either [T] or [V].
class Result<T, V> {
/// Constructs a result. [_data] must be either of type [T] or [V].
const Result(this._data)
: assert(
_data is T || _data is V,
'Invalid data type $_data: Must be either $T or $V',
);
final dynamic _data;
/// Returns true if the data contained within is of type [S]. If not, returns false.
bool isType<S>() => _data is S;
/// Returns the data contained within cast to [S]. Before doing this call, it's recommended
/// to check isType<S>() first.
S get<S>() {
assert(_data is S, 'Data is not $S');
return _data as S;
}
/// Returns the runtime type of the data.
Object get dataRuntimeType => _data.runtimeType;
}

View File

@ -1,11 +1,11 @@
name: moxlib name: moxlib
description: A collection of code for sharing between various moxxy libraries. Not intended for outside use. description: A collection of code for sharing between various moxxy libraries. Not inteded for outside use.
version: 0.2.0 version: 0.1.5
homepage: https://codeberg.org/moxxy/moxlib homepage: https://codeberg.org/moxxy/moxlib
publish_to: https://git.polynom.me/api/packages/Moxxy/pub publish_to: https://git.polynom.me/api/packages/Moxxy/pub
environment: environment:
sdk: ">=2.17.0 <3.0.0" sdk: ">=2.17.0-266.1.beta <3.0.0"
dependencies: dependencies:
logging: ^1.0.2 logging: ^1.0.2

View File

@ -1,24 +1,30 @@
import 'package:moxlib/moxlib.dart'; import "package:moxlib/awaitabledatasender.dart";
import 'package:test/test.dart';
import "package:test/test.dart";
class TestDataType implements JsonImplementation { class TestDataType implements JsonImplementation {
TestDataType(this.data);
factory TestDataType.fromJson(Map<String, dynamic> json) =>
TestDataType(json['data']! as String);
final String data; final String data;
TestDataType(this.data);
@override @override
Map<String, dynamic> toJson() => {'data': data}; Map<String, dynamic> toJson() => {
"data": data
};
factory TestDataType.fromJson(Map<String, dynamic> json) => TestDataType(
json["data"]!
);
} }
class FakeAwaitableDataSender<S extends JsonImplementation, class FakeAwaitableDataSender<
R extends JsonImplementation> extends AwaitableDataSender<S, R> { S extends JsonImplementation,
FakeAwaitableDataSender({this.onAddFunc}) : super(); R extends JsonImplementation
> extends AwaitableDataSender<S, R> {
final void Function()? onAddFunc; final void Function()? onAddFunc;
FakeAwaitableDataSender({ this.onAddFunc }) : super();
@override @override
Future<void> sendDataImpl(DataWrapper data) async {} Future<void> sendDataImpl(DataWrapper data) async {}
@ -29,41 +35,39 @@ class FakeAwaitableDataSender<S extends JsonImplementation,
} }
void main() { void main() {
test('Sending an event without awaiting it', () async { test("Sending an event without awaiting it", () async {
final handler = FakeAwaitableDataSender<TestDataType, TestDataType>(); final handler = FakeAwaitableDataSender<TestDataType, TestDataType>();
final result = final result = await handler.sendData(TestDataType("hallo"), awaitable: false);
await handler.sendData(TestDataType('hallo'), awaitable: false);
expect(result, null); expect(result, null);
expect(handler.getAwaitables().length, 0); expect(handler.getAwaitables().length, 0);
}); });
test('Sending an event without awaiting it', () async { test("Sending an event without awaiting it", () async {
final handler = FakeAwaitableDataSender<TestDataType, TestDataType>(); final handler = FakeAwaitableDataSender<TestDataType, TestDataType>();
const id = 'abc123'; const id = "abc123";
final result = final result = handler.sendData(TestDataType("hallo"), awaitable: true, id: id);
handler.sendData(TestDataType('hallo'), awaitable: true, id: id); await handler.onData(DataWrapper(id, TestDataType("welt")));
await handler.onData(DataWrapper(id, TestDataType('welt')));
expect((await result)!.data, 'welt'); expect((await result)!.data, "welt");
expect(handler.getAwaitables().length, 0); expect(handler.getAwaitables().length, 0);
}); });
test('Queue multiple data packets and resolve in reverse order', () async { test("Queue multiple data packets and resolve in reverse order", () async {
var i = 0; int i = 0;
final handler = FakeAwaitableDataSender<TestDataType, TestDataType>( final handler = FakeAwaitableDataSender<TestDataType, TestDataType>(
onAddFunc: () { onAddFunc: () {
i++; i++;
expect(i <= 2, true); expect(i <= 2, true);
}, }
); );
final a = handler.sendData(TestDataType('1'), id: '1'); final a = handler.sendData(TestDataType("1"), id: "1");
final b = handler.sendData(TestDataType('2'), id: '2'); final b = handler.sendData(TestDataType("2"), id: "2");
await handler.onData(DataWrapper('2', TestDataType('4'))); await handler.onData(DataWrapper("2", TestDataType("4")));
await handler.onData(DataWrapper('1', TestDataType('1'))); await handler.onData(DataWrapper("1", TestDataType("1")));
expect((await a)!.data, '1'); expect((await a)!.data, "1");
expect((await b)!.data, '4'); expect((await b)!.data, "4");
}); });
} }

View File

@ -1,13 +1,14 @@
import 'package:moxlib/moxlib.dart'; import "package:moxlib/math.dart";
import 'package:test/test.dart';
import "package:test/test.dart";
void main() { void main() {
group('implies', () { group("implies", () {
test('Truth table test', () { test("Truth table test", () {
expect(implies(true, true), true); expect(implies(true, true), true);
expect(implies(true, false), false); expect(implies(true, false), false);
expect(implies(false, true), true); expect(implies(false, true), true);
expect(implies(false, false), true); expect(implies(false, false), true);
}); });
}); });
} }