Compare commits
No commits in common. "5e867e30ee34a18da5d352a75f2a9a75dc22c23f" and "2a469e10e819c9b8866b94805c908c86b25f0486" have entirely different histories.
5e867e30ee
...
2a469e10e8
@ -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/"
|
||||||
|
18
flake.lock
18
flake.lock
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
16
lib/lists.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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';
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user