1 | | | import '../../exceptions/squadron_error.dart'; |
2 | | |
|
3 | | | class Transferables { |
4 | | | const Transferables._(); |
5 | | |
|
6 | | 9 | static List<Object>? get(List args) { |
7 | | 9 | final objects = _get(args, <Object>{}).toList(); |
8 | | 9 | return objects.isEmpty ? null : objects; |
9 | | 9 | } |
10 | | |
|
11 | | 9 | static bool _isBaseType(Object? data) => |
12 | | 9 | (data == null || data is String || data is num || data is bool); |
13 | | |
|
14 | | | static bool _isListOfBaseType(Object? data) => |
15 | | 9 | (data is List<String> || data is List<num> || data is List<bool>); |
16 | | |
|
17 | | 9 | static bool _isSafeForTransfer(Object? data) { |
18 | | 9 | if (_isBaseType(data)) return true; |
19 | | 0 | if (_isListOfBaseType(data)) return true; |
20 | | 9 | if (data is List && data.every(_isSafeForTransfer)) return true; |
21 | | 9 | return false; |
22 | | 9 | } |
23 | | |
|
24 | | 9 | static bool _isNotSafeForTransfer(Object? data) => !_isSafeForTransfer(data); |
25 | | |
|
26 | | | /// Excludes base type values from [list]. |
27 | | 9 | static Iterable<Object> _getObjects(Iterable list, Set<Object> seen) sync* { |
28 | | 9 | for (var o in list.where(_isNotSafeForTransfer)) { |
29 | | 9 | if (!seen.contains(o)) { |
30 | | 9 | seen.add(o); |
31 | | 9 | yield o as Object; |
32 | | | } |
33 | | | } |
34 | | 9 | } |
35 | | |
|
36 | | | static void _checkKeys(Map data) { |
37 | | 0 | if (!data.keys.every(_isBaseType)) { |
38 | | 0 | throw SquadronErrorExt.create( |
39 | | | 'Map keys must be strings, numbers or booleans.'); |
40 | | | } |
41 | | | } |
42 | | |
|
43 | | | /// Yields objects contained in [message]. Used to identify non-base type objects and provide |
44 | | | /// them to [Worker.postMessage]. [Worker.postMessage] will clone these objects. The code makes |
45 | | | /// no effort to ensure these objects really are transferable. |
46 | | 9 | static Iterable<Object> _get(List message, Set<Object> seen) sync* { |
47 | | 9 | if (_isSafeForTransfer(message)) return; |
48 | | 9 | final toBeInspected = _getObjects(message, seen).toList(); |
49 | | | var i = 0; |
50 | | 9 | while (i < toBeInspected.length) { |
51 | | 9 | final arg = toBeInspected[i++]; |
52 | | 9 | if (arg is Map) { |
53 | | | _checkKeys(arg); |
54 | | 0 | toBeInspected.addAll(_getObjects(arg.values, seen)); |
55 | | 9 | } else if (arg is Iterable) { |
56 | | 4 | toBeInspected.addAll(_getObjects(arg, seen)); |
57 | | | } else { |
58 | | 9 | yield arg; |
59 | | | } |
60 | | | } |
61 | | 9 | } |
62 | | | } |