Skip to content

Commit 137e087

Browse files
authored
Implement singleton logic (#22)
1 parent c3ba1c2 commit 137e087

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

packages/sane/lib/src/exceptions.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,8 @@ final class SaneUnsupportedException extends SaneException {
186186
@override
187187
SANE_Status get _status => SANE_Status.STATUS_UNSUPPORTED;
188188
}
189+
190+
/// SANE has been exited or the device has been closed.
191+
final class SaneDisposedError extends StateError {
192+
SaneDisposedError() : super('SANE has been exited');
193+
}

packages/sane/lib/src/sane.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,21 @@ import 'package:sane/src/utils.dart';
1414
typedef AuthCallback = SaneCredentials Function(String resourceName);
1515

1616
class Sane {
17+
factory Sane() => _instance ??= Sane._();
18+
19+
Sane._();
20+
21+
static Sane? _instance;
22+
bool _exited = false;
1723
final Map<SaneHandle, SANE_Handle> _nativeHandles = {};
24+
1825
SANE_Handle _getNativeHandle(SaneHandle handle) => _nativeHandles[handle]!;
1926

2027
Future<int> init({
2128
AuthCallback? authCallback,
2229
}) {
30+
_checkIfExited();
31+
2332
final completer = Completer<int>();
2433

2534
void authCallbackAdapter(
@@ -65,13 +74,19 @@ class Sane {
6574
}
6675

6776
Future<void> exit() {
77+
if (_exited) return Future.value();
78+
6879
final completer = Completer<void>();
6980

7081
Future(() {
82+
_exited = true;
83+
7184
dylib.sane_exit();
7285
print('sane_exit()');
7386

7487
completer.complete();
88+
89+
_instance = null;
7590
});
7691

7792
return completer.future;
@@ -80,6 +95,8 @@ class Sane {
8095
Future<List<SaneDevice>> getDevices({
8196
required bool localOnly,
8297
}) {
98+
_checkIfExited();
99+
83100
final completer = Completer<List<SaneDevice>>();
84101

85102
Future(() {
@@ -108,6 +125,8 @@ class Sane {
108125
}
109126

110127
Future<SaneHandle> open(String deviceName) {
128+
_checkIfExited();
129+
111130
final completer = Completer<SaneHandle>();
112131

113132
Future(() {
@@ -133,10 +152,14 @@ class Sane {
133152
}
134153

135154
Future<SaneHandle> openDevice(SaneDevice device) {
155+
_checkIfExited();
156+
136157
return open(device.name);
137158
}
138159

139160
Future<void> close(SaneHandle handle) {
161+
_checkIfExited();
162+
140163
final completer = Completer<void>();
141164

142165
Future(() {
@@ -154,6 +177,8 @@ class Sane {
154177
SaneHandle handle,
155178
int index,
156179
) {
180+
_checkIfExited();
181+
157182
final completer = Completer<SaneOptionDescriptor>();
158183

159184
Future(() {
@@ -175,6 +200,8 @@ class Sane {
175200
Future<List<SaneOptionDescriptor>> getAllOptionDescriptors(
176201
SaneHandle handle,
177202
) {
203+
_checkIfExited();
204+
178205
final completer = Completer<List<SaneOptionDescriptor>>();
179206

180207
Future(() {
@@ -201,6 +228,8 @@ class Sane {
201228
required SaneAction action,
202229
T? value,
203230
}) {
231+
_checkIfExited();
232+
204233
final completer = Completer<SaneOptionResult<T>>();
205234

206235
Future(() {
@@ -393,6 +422,8 @@ class Sane {
393422
}
394423

395424
Future<SaneParameters> getParameters(SaneHandle handle) {
425+
_checkIfExited();
426+
396427
final completer = Completer<SaneParameters>();
397428

398429
Future(() {
@@ -416,6 +447,8 @@ class Sane {
416447
}
417448

418449
Future<void> start(SaneHandle handle) {
450+
_checkIfExited();
451+
419452
final completer = Completer<void>();
420453

421454
Future(() {
@@ -431,6 +464,8 @@ class Sane {
431464
}
432465

433466
Future<Uint8List> read(SaneHandle handle, int bufferSize) {
467+
_checkIfExited();
468+
434469
final completer = Completer<Uint8List>();
435470

436471
Future(() {
@@ -464,6 +499,8 @@ class Sane {
464499
}
465500

466501
Future<void> cancel(SaneHandle handle) {
502+
_checkIfExited();
503+
467504
final completer = Completer<void>();
468505

469506
Future(() {
@@ -477,6 +514,8 @@ class Sane {
477514
}
478515

479516
Future<void> setIOMode(SaneHandle handle, SaneIOMode mode) {
517+
_checkIfExited();
518+
480519
final completer = Completer<void>();
481520

482521
Future(() {
@@ -493,4 +532,9 @@ class Sane {
493532

494533
return completer.future;
495534
}
535+
536+
@pragma('vm:prefer-inline')
537+
void _checkIfExited() {
538+
if (_exited) throw SaneDisposedError();
539+
}
496540
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import 'package:sane/sane.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
late Sane sane;
6+
7+
test('can instantiate', () {
8+
sane = Sane();
9+
});
10+
11+
test('same instance on repeated instantiation', () {
12+
final newSane = Sane();
13+
expect(sane, equals(newSane));
14+
});
15+
16+
test('can exit', () {
17+
expect(sane.exit, returnsNormally);
18+
});
19+
20+
test('throws upon use', () {
21+
expect(
22+
() => sane.getDevices(localOnly: true),
23+
throwsA(isA<SaneDisposedError>()),
24+
);
25+
});
26+
27+
test('can reinstiate with new instance', () {
28+
final newSane = Sane();
29+
expect(sane, isNot(newSane));
30+
sane = newSane;
31+
});
32+
33+
test('doesn\'t throw upon use', () {
34+
expect(() => sane.getDevices(localOnly: true), returnsNormally);
35+
});
36+
}

0 commit comments

Comments
 (0)