Skip to content

Commit ac5668c

Browse files
authored
Better exceptions (#2)
1 parent da23e5e commit ac5668c

File tree

4 files changed

+204
-50
lines changed

4 files changed

+204
-50
lines changed
Lines changed: 191 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,202 @@
1-
abstract class SaneException implements Exception {}
1+
import 'package:ffi/ffi.dart';
2+
import 'package:meta/meta.dart';
3+
import 'package:sane/src/bindings.g.dart';
4+
import 'package:sane/src/dylib.dart';
25

3-
class SaneUnsupportedException extends SaneException {}
6+
/// Base class for all possible errors that can occur in the SANE library.
7+
///
8+
/// See also:
9+
///
10+
/// - [SaneEofException]
11+
/// - [SaneJammedException]
12+
/// - [SaneDeviceBusyException]
13+
/// - [SaneInvalidDataException]
14+
/// - [SaneIoException]
15+
/// - [SaneNoDocumentsException]
16+
/// - [SaneCoverOpenException]
17+
/// - [SaneUnsupportedException]
18+
/// - [SaneCancelledException]
19+
/// - [SaneNoMemoryException]
20+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
21+
sealed class SaneException implements Exception {
22+
SANE_Status get _status;
423

5-
class SaneCancelledException extends SaneException {}
24+
const SaneException._();
625

7-
class SaneDeviceBusyException extends SaneException {}
26+
factory SaneException(SANE_Status status) {
27+
final exception = switch (status) {
28+
SANE_Status.STATUS_GOOD =>
29+
throw ArgumentError(
30+
'Cannot create SaneException with status STATUS_GOOD',
31+
'status',
32+
),
33+
SANE_Status.STATUS_UNSUPPORTED => SaneUnsupportedException(),
34+
SANE_Status.STATUS_CANCELLED => SaneCancelledException(),
35+
SANE_Status.STATUS_DEVICE_BUSY => SaneDeviceBusyException(),
36+
SANE_Status.STATUS_INVAL => SaneInvalidDataException(),
37+
SANE_Status.STATUS_EOF => SaneEofException(),
38+
SANE_Status.STATUS_JAMMED => SaneJammedException(),
39+
SANE_Status.STATUS_NO_DOCS => SaneNoDocumentsException(),
40+
SANE_Status.STATUS_COVER_OPEN => SaneCoverOpenException(),
41+
SANE_Status.STATUS_IO_ERROR => SaneIoException(),
42+
SANE_Status.STATUS_NO_MEM => SaneNoMemoryException(),
43+
SANE_Status.STATUS_ACCESS_DENIED => SaneAccessDeniedException(),
44+
};
845

9-
class SaneInvalidException extends SaneException {}
46+
assert(exception._status == status);
1047

11-
class SaneJammedException extends SaneException {}
48+
return exception;
49+
}
1250

13-
class SaneNoDocumentsException extends SaneException {}
51+
String get message {
52+
return dylib.sane_strstatus(_status).cast<Utf8>().toDartString();
53+
}
1454

15-
class SaneCoverOpenException extends SaneException {}
55+
@override
56+
String toString() {
57+
return '$runtimeType: $message';
58+
}
59+
}
1660

17-
class SaneIOErrorException extends SaneException {}
61+
/// No more data available.
62+
///
63+
/// See also:
64+
///
65+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
66+
final class SaneEofException extends SaneException {
67+
const SaneEofException() : super._();
1868

19-
class SaneNoMemoryException extends SaneException {}
69+
@override
70+
SANE_Status get _status => SANE_Status.STATUS_EOF;
71+
}
2072

21-
class SaneAccessDeniedException extends SaneException {}
73+
/// The document feeder is jammed.
74+
///
75+
/// See also:
76+
///
77+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
78+
final class SaneJammedException extends SaneException {
79+
const SaneJammedException() : super._();
2280

23-
class SaneNotFoundOption extends SaneException {}
81+
@override
82+
SANE_Status get _status => SANE_Status.STATUS_JAMMED;
83+
}
84+
85+
/// The document feeder is out of documents.
86+
///
87+
/// See also:
88+
///
89+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
90+
final class SaneNoDocumentsException extends SaneException {
91+
const SaneNoDocumentsException() : super._();
92+
93+
@override
94+
SANE_Status get _status => SANE_Status.STATUS_NO_DOCS;
95+
}
96+
97+
/// The scanner cover is open.
98+
///
99+
/// See also:
100+
///
101+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
102+
final class SaneCoverOpenException extends SaneException {
103+
const SaneCoverOpenException() : super._();
104+
105+
@override
106+
SANE_Status get _status => SANE_Status.STATUS_COVER_OPEN;
107+
}
108+
109+
/// The device is busy.
110+
///
111+
/// See also:
112+
///
113+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
114+
final class SaneDeviceBusyException extends SaneException {
115+
const SaneDeviceBusyException() : super._();
116+
117+
@override
118+
SANE_Status get _status => SANE_Status.STATUS_DEVICE_BUSY;
119+
}
120+
121+
/// Data is invalid.
122+
///
123+
/// See also:
124+
///
125+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
126+
final class SaneInvalidDataException extends SaneException {
127+
const SaneInvalidDataException() : super._();
128+
129+
@override
130+
SANE_Status get _status => SANE_Status.STATUS_INVAL;
131+
}
132+
133+
/// Error during device I/O.
134+
///
135+
/// See also:
136+
///
137+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
138+
final class SaneIoException extends SaneException {
139+
const SaneIoException() : super._();
140+
141+
@override
142+
SANE_Status get _status => SANE_Status.STATUS_IO_ERROR;
143+
}
144+
145+
/// Out of memory.
146+
///
147+
/// See also:
148+
///
149+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
150+
final class SaneNoMemoryException extends SaneException {
151+
const SaneNoMemoryException() : super._();
152+
153+
@override
154+
SANE_Status get _status => SANE_Status.STATUS_NO_MEM;
155+
}
156+
157+
/// Access to resource has been denied.
158+
///
159+
/// See also:
160+
///
161+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
162+
final class SaneAccessDeniedException extends SaneException {
163+
const SaneAccessDeniedException() : super._();
164+
165+
@override
166+
SANE_Status get _status => SANE_Status.STATUS_ACCESS_DENIED;
167+
}
168+
169+
/// Operation was cancelled.
170+
///
171+
/// See also:
172+
///
173+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
174+
final class SaneCancelledException extends SaneException {
175+
const SaneCancelledException() : super._();
176+
177+
@override
178+
SANE_Status get _status => SANE_Status.STATUS_CANCELLED;
179+
}
180+
181+
/// Operation is not supported.
182+
///
183+
/// See also:
184+
///
185+
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
186+
final class SaneUnsupportedException extends SaneException {
187+
const SaneUnsupportedException() : super._();
188+
189+
@override
190+
SANE_Status get _status => SANE_Status.STATUS_UNSUPPORTED;
191+
}
192+
193+
@internal
194+
extension SaneStatusExtension on SANE_Status {
195+
/// Throws [SaneException] if the status is not [SANE_Status.STATUS_GOOD].
196+
@pragma('vm:prefer-inline')
197+
void check() {
198+
if (this != SANE_Status.STATUS_GOOD) {
199+
throw SaneException(this);
200+
}
201+
}
202+
}

packages/sane/lib/src/sane.dart

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class Sane {
4949
final status = dylib.sane_init(versionCodePointer, nativeAuthCallback);
5050
print('sane_init() -> ${status.name}');
5151

52-
_handleSaneStatus(status);
52+
status.check();
5353

5454
final versionCode = versionCodePointer.value;
5555
print('SANE version: ${SaneUtils.version(versionCodePointer.value)}');
@@ -90,7 +90,7 @@ class Sane {
9090
);
9191
print('sane_get_devices() -> ${status.name}');
9292

93-
_handleSaneStatus(status);
93+
status.check();
9494

9595
final devices = <SaneDevice>[];
9696
for (var i = 0; deviceListPointer.value[i] != ffi.nullptr; i++) {
@@ -115,7 +115,7 @@ class Sane {
115115
final status = dylib.sane_open(deviceNamePointer, nativeHandlePointer);
116116
print('sane_open() -> ${status.name}');
117117

118-
_handleSaneStatus(status);
118+
status.check();
119119

120120
final handle = SaneHandle(deviceName: deviceName);
121121
_nativeHandles.addAll({
@@ -230,7 +230,7 @@ class Sane {
230230
valuePointer = ffi.nullptr;
231231

232232
case SaneOptionValueType.group:
233-
throw SaneInvalidException();
233+
throw SaneInvalidDataException();
234234
}
235235

236236
if (action == SaneAction.setValue) {
@@ -266,7 +266,7 @@ class Sane {
266266

267267
invalid:
268268
default:
269-
throw SaneInvalidException();
269+
throw SaneInvalidDataException();
270270
}
271271
}
272272

@@ -279,7 +279,7 @@ class Sane {
279279
);
280280
print('sane_control_option($index, $action, $value) -> ${status.name}');
281281

282-
_handleSaneStatus(status);
282+
status.check();
283283

284284
final infos = saneOptionInfoFromNative(infoPointer.value);
285285
late final dynamic result;
@@ -305,7 +305,7 @@ class Sane {
305305
result = null;
306306

307307
default:
308-
throw SaneInvalidException();
308+
throw SaneInvalidDataException();
309309
}
310310

311311
ffi.calloc.free(valuePointer);
@@ -397,7 +397,7 @@ class Sane {
397397
_getNativeHandle(handle), nativeParametersPointer);
398398
print('sane_get_parameters() -> ${status.name}');
399399

400-
_handleSaneStatus(status);
400+
status.check();
401401

402402
final parameters = saneParametersFromNative(nativeParametersPointer.ref);
403403

@@ -416,7 +416,7 @@ class Sane {
416416
final status = dylib.sane_start(_getNativeHandle(handle));
417417
print('sane_start() -> ${status.name}');
418418

419-
_handleSaneStatus(status);
419+
status.check();
420420

421421
completer.complete();
422422
});
@@ -439,7 +439,7 @@ class Sane {
439439
);
440440
print('sane_read() -> ${status.name}');
441441

442-
_handleSaneStatus(status);
442+
status.check();
443443

444444
final bytes = Uint8List.fromList(
445445
List.generate(
@@ -480,37 +480,11 @@ class Sane {
480480
);
481481
print('sane_set_io_mode() -> ${status.name}');
482482

483-
_handleSaneStatus(status);
483+
status.check();
484484

485485
completer.complete();
486486
});
487487

488488
return completer.future;
489489
}
490-
491-
void _handleSaneStatus(SANE_Status status) {
492-
switch (status) {
493-
case SANE_Status.STATUS_UNSUPPORTED:
494-
throw SaneUnsupportedException();
495-
case SANE_Status.STATUS_CANCELLED:
496-
throw SaneCancelledException();
497-
case SANE_Status.STATUS_DEVICE_BUSY:
498-
throw SaneDeviceBusyException();
499-
case SANE_Status.STATUS_INVAL:
500-
throw SaneInvalidException();
501-
case SANE_Status.STATUS_JAMMED:
502-
throw SaneJammedException();
503-
case SANE_Status.STATUS_NO_DOCS:
504-
throw SaneNoDocumentsException();
505-
case SANE_Status.STATUS_COVER_OPEN:
506-
throw SaneCoverOpenException();
507-
case SANE_Status.STATUS_IO_ERROR:
508-
throw SaneIOErrorException();
509-
case SANE_Status.STATUS_NO_MEM:
510-
throw SaneNoMemoryException();
511-
case SANE_Status.STATUS_ACCESS_DENIED:
512-
throw SaneAccessDeniedException();
513-
default:
514-
}
515-
}
516490
}

packages/sane/pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ packages:
191191
source: hosted
192192
version: "0.12.16+1"
193193
meta:
194-
dependency: transitive
194+
dependency: "direct main"
195195
description:
196196
name: meta
197197
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c

packages/sane/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ environment:
1111

1212
dependencies:
1313
ffi: ^2.1.3
14+
meta: ^1.16.0
1415

1516
dev_dependencies:
1617
ffigen: ^14.0.1

0 commit comments

Comments
 (0)