Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 191 additions & 12 deletions packages/sane/lib/src/exceptions.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,202 @@
abstract class SaneException implements Exception {}
import 'package:ffi/ffi.dart';
import 'package:meta/meta.dart';
import 'package:sane/src/bindings.g.dart';
import 'package:sane/src/dylib.dart';

class SaneUnsupportedException extends SaneException {}
/// Base class for all possible errors that can occur in the SANE library.
///
/// See also:
///
/// - [SaneEofException]
/// - [SaneJammedException]
/// - [SaneDeviceBusyException]
/// - [SaneInvalidDataException]
/// - [SaneIoException]
/// - [SaneNoDocumentsException]
/// - [SaneCoverOpenException]
/// - [SaneUnsupportedException]
/// - [SaneCancelledException]
/// - [SaneNoMemoryException]
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
sealed class SaneException implements Exception {
SANE_Status get _status;

class SaneCancelledException extends SaneException {}
const SaneException._();

class SaneDeviceBusyException extends SaneException {}
factory SaneException(SANE_Status status) {
final exception = switch (status) {
SANE_Status.STATUS_GOOD =>
throw ArgumentError(
'Cannot create SaneException with status STATUS_GOOD',
'status',
),
SANE_Status.STATUS_UNSUPPORTED => SaneUnsupportedException(),
SANE_Status.STATUS_CANCELLED => SaneCancelledException(),
SANE_Status.STATUS_DEVICE_BUSY => SaneDeviceBusyException(),
SANE_Status.STATUS_INVAL => SaneInvalidDataException(),
SANE_Status.STATUS_EOF => SaneEofException(),
SANE_Status.STATUS_JAMMED => SaneJammedException(),
SANE_Status.STATUS_NO_DOCS => SaneNoDocumentsException(),
SANE_Status.STATUS_COVER_OPEN => SaneCoverOpenException(),
SANE_Status.STATUS_IO_ERROR => SaneIoException(),
SANE_Status.STATUS_NO_MEM => SaneNoMemoryException(),
SANE_Status.STATUS_ACCESS_DENIED => SaneAccessDeniedException(),
};

class SaneInvalidException extends SaneException {}
assert(exception._status == status);

class SaneJammedException extends SaneException {}
return exception;
}

class SaneNoDocumentsException extends SaneException {}
String get message {
return dylib.sane_strstatus(_status).cast<Utf8>().toDartString();
}

class SaneCoverOpenException extends SaneException {}
@override
String toString() {
return '$runtimeType: $message';
}
}

class SaneIOErrorException extends SaneException {}
/// No more data available.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneEofException extends SaneException {
const SaneEofException() : super._();

class SaneNoMemoryException extends SaneException {}
@override
SANE_Status get _status => SANE_Status.STATUS_EOF;
}

class SaneAccessDeniedException extends SaneException {}
/// The document feeder is jammed.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneJammedException extends SaneException {
const SaneJammedException() : super._();

class SaneNotFoundOption extends SaneException {}
@override
SANE_Status get _status => SANE_Status.STATUS_JAMMED;
}

/// The document feeder is out of documents.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneNoDocumentsException extends SaneException {
const SaneNoDocumentsException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_NO_DOCS;
}

/// The scanner cover is open.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneCoverOpenException extends SaneException {
const SaneCoverOpenException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_COVER_OPEN;
}

/// The device is busy.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneDeviceBusyException extends SaneException {
const SaneDeviceBusyException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_DEVICE_BUSY;
}

/// Data is invalid.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneInvalidDataException extends SaneException {
const SaneInvalidDataException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_INVAL;
}

/// Error during device I/O.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneIoException extends SaneException {
const SaneIoException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_IO_ERROR;
}

/// Out of memory.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneNoMemoryException extends SaneException {
const SaneNoMemoryException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_NO_MEM;
}

/// Access to resource has been denied.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneAccessDeniedException extends SaneException {
const SaneAccessDeniedException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_ACCESS_DENIED;
}

/// Operation was cancelled.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneCancelledException extends SaneException {
const SaneCancelledException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_CANCELLED;
}

/// Operation is not supported.
///
/// See also:
///
/// - <https://sane-project.gitlab.io/standard/api.html#tab-status>
final class SaneUnsupportedException extends SaneException {
const SaneUnsupportedException() : super._();

@override
SANE_Status get _status => SANE_Status.STATUS_UNSUPPORTED;
}

@internal
extension SaneStatusExtension on SANE_Status {
/// Throws [SaneException] if the status is not [SANE_Status.STATUS_GOOD].
@pragma('vm:prefer-inline')
void check() {
if (this != SANE_Status.STATUS_GOOD) {
throw SaneException(this);
}
}
}
48 changes: 11 additions & 37 deletions packages/sane/lib/src/sane.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Sane {
final status = dylib.sane_init(versionCodePointer, nativeAuthCallback);
print('sane_init() -> ${status.name}');

_handleSaneStatus(status);
status.check();

final versionCode = versionCodePointer.value;
print('SANE version: ${SaneUtils.version(versionCodePointer.value)}');
Expand Down Expand Up @@ -90,7 +90,7 @@ class Sane {
);
print('sane_get_devices() -> ${status.name}');

_handleSaneStatus(status);
status.check();

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

_handleSaneStatus(status);
status.check();

final handle = SaneHandle(deviceName: deviceName);
_nativeHandles.addAll({
Expand Down Expand Up @@ -230,7 +230,7 @@ class Sane {
valuePointer = ffi.nullptr;

case SaneOptionValueType.group:
throw SaneInvalidException();
throw SaneInvalidDataException();
}

if (action == SaneAction.setValue) {
Expand Down Expand Up @@ -266,7 +266,7 @@ class Sane {

invalid:
default:
throw SaneInvalidException();
throw SaneInvalidDataException();
}
}

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

_handleSaneStatus(status);
status.check();

final infos = saneOptionInfoFromNative(infoPointer.value);
late final dynamic result;
Expand All @@ -305,7 +305,7 @@ class Sane {
result = null;

default:
throw SaneInvalidException();
throw SaneInvalidDataException();
}

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

_handleSaneStatus(status);
status.check();

final parameters = saneParametersFromNative(nativeParametersPointer.ref);

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

_handleSaneStatus(status);
status.check();

completer.complete();
});
Expand All @@ -439,7 +439,7 @@ class Sane {
);
print('sane_read() -> ${status.name}');

_handleSaneStatus(status);
status.check();

final bytes = Uint8List.fromList(
List.generate(
Expand Down Expand Up @@ -480,37 +480,11 @@ class Sane {
);
print('sane_set_io_mode() -> ${status.name}');

_handleSaneStatus(status);
status.check();

completer.complete();
});

return completer.future;
}

void _handleSaneStatus(SANE_Status status) {
switch (status) {
case SANE_Status.STATUS_UNSUPPORTED:
throw SaneUnsupportedException();
case SANE_Status.STATUS_CANCELLED:
throw SaneCancelledException();
case SANE_Status.STATUS_DEVICE_BUSY:
throw SaneDeviceBusyException();
case SANE_Status.STATUS_INVAL:
throw SaneInvalidException();
case SANE_Status.STATUS_JAMMED:
throw SaneJammedException();
case SANE_Status.STATUS_NO_DOCS:
throw SaneNoDocumentsException();
case SANE_Status.STATUS_COVER_OPEN:
throw SaneCoverOpenException();
case SANE_Status.STATUS_IO_ERROR:
throw SaneIOErrorException();
case SANE_Status.STATUS_NO_MEM:
throw SaneNoMemoryException();
case SANE_Status.STATUS_ACCESS_DENIED:
throw SaneAccessDeniedException();
default:
}
}
}
2 changes: 1 addition & 1 deletion packages/sane/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ packages:
source: hosted
version: "0.12.16+1"
meta:
dependency: transitive
dependency: "direct main"
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
Expand Down
1 change: 1 addition & 0 deletions packages/sane/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ environment:

dependencies:
ffi: ^2.1.3
meta: ^1.16.0

dev_dependencies:
ffigen: ^14.0.1
Expand Down