├── .gitignore
├── .idea
├── modules.xml
└── vcs.xml
├── .metadata
├── .vscode
├── launch.json
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
├── app
│ └── src
│ │ └── main
│ │ └── java
│ │ └── io
│ │ └── flutter
│ │ └── plugins
│ │ └── GeneratedPluginRegistrant.java
└── local.properties
├── benchmarks.md
├── example
└── benchmark.dart
├── lib
├── msgpack_dart.dart
└── src
│ ├── common.dart
│ ├── data_writer.dart
│ ├── deserializer.dart
│ └── serializer.dart
├── msgpack_dart.iml
├── pubspec.yaml
└── test
└── msgpack_dart_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 | ios/.generated/
9 | ios/Flutter/Generated.xcconfig
10 | ios/Runner/GeneratedPluginRegistrant.*
11 |
12 | pubspec.lock
13 |
14 |
15 | # Created by https://www.toptal.com/developers/gitignore/api/phpstorm
16 | # Edit at https://www.toptal.com/developers/gitignore?templates=phpstorm
17 |
18 | ### PhpStorm ###
19 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
20 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
21 |
22 | # User-specific stuff
23 | .idea/**/workspace.xml
24 | .idea/**/tasks.xml
25 | .idea/**/usage.statistics.xml
26 | .idea/**/dictionaries
27 | .idea/**/shelf
28 |
29 | # Generated files
30 | .idea/**/contentModel.xml
31 |
32 | # Sensitive or high-churn files
33 | .idea/**/dataSources/
34 | .idea/**/dataSources.ids
35 | .idea/**/dataSources.local.xml
36 | .idea/**/sqlDataSources.xml
37 | .idea/**/dynamic.xml
38 | .idea/**/uiDesigner.xml
39 | .idea/**/dbnavigator.xml
40 |
41 | # Gradle
42 | .idea/**/gradle.xml
43 | .idea/**/libraries
44 |
45 | # Gradle and Maven with auto-import
46 | # When using Gradle or Maven with auto-import, you should exclude module files,
47 | # since they will be recreated, and may cause churn. Uncomment if using
48 | # auto-import.
49 | # .idea/artifacts
50 | # .idea/compiler.xml
51 | # .idea/jarRepositories.xml
52 | # .idea/modules.xml
53 | # .idea/*.iml
54 | # .idea/modules
55 | # *.iml
56 | # *.ipr
57 |
58 | # CMake
59 | cmake-build-*/
60 |
61 | # Mongo Explorer plugin
62 | .idea/**/mongoSettings.xml
63 |
64 | # File-based project format
65 | *.iws
66 |
67 | # IntelliJ
68 | out/
69 |
70 | # mpeltonen/sbt-idea plugin
71 | .idea_modules/
72 |
73 | # JIRA plugin
74 | atlassian-ide-plugin.xml
75 |
76 | # Cursive Clojure plugin
77 | .idea/replstate.xml
78 |
79 | # Crashlytics plugin (for Android Studio and IntelliJ)
80 | com_crashlytics_export_strings.xml
81 | crashlytics.properties
82 | crashlytics-build.properties
83 | fabric.properties
84 |
85 | # Editor-based Rest Client
86 | .idea/httpRequests
87 |
88 | # Android studio 3.1+ serialized cache file
89 | .idea/caches/build_file_checksums.ser
90 |
91 | ### PhpStorm Patch ###
92 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
93 |
94 | # *.iml
95 | # modules.xml
96 | # .idea/misc.xml
97 | # *.ipr
98 |
99 | # Sonarlint plugin
100 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
101 | .idea/**/sonarlint/
102 |
103 | # SonarQube Plugin
104 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
105 | .idea/**/sonarIssues.xml
106 |
107 | # Markdown Navigator plugin
108 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
109 | .idea/**/markdown-navigator.xml
110 | .idea/**/markdown-navigator-enh.xml
111 | .idea/**/markdown-navigator/
112 |
113 | # Cache file creation bug
114 | # See https://youtrack.jetbrains.com/issue/JBR-2257
115 | .idea/$CACHE_FILE$
116 |
117 | # CodeStream plugin
118 | # https://plugins.jetbrains.com/plugin/12206-codestream
119 | .idea/codestream.xml
120 |
121 | # End of https://www.toptal.com/developers/gitignore/api/phpstorm
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: d9ad220bbb17972913fb687f8d673d79b9f66dab
8 | channel: master
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Benchmark",
9 | "args": [
10 | "-a"
11 | ],
12 | "program": "example/benchmark.dart",
13 | "request": "launch",
14 | "type": "dart"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true
3 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [1.0.1] - 2023-01-12
2 |
3 | - Remove dependency on dart:io
4 |
5 | ## [1.0.0] - 2021-03-11
6 |
7 | - Migrated to null safety (thanks RootSoft)
8 |
9 | ## [0.0.7] - 2020-03-14
10 |
11 | - Fix wrong length when writing ext8 (0xc7)
12 |
13 | ## [0.0.6] - 2019-09-20
14 |
15 | - Accept any iterable when serializing, not just List
16 | - Accept ByteData when serializing (will be deserialized as Uint8List)
17 |
18 | ## [0.0.5] - 2019-05-19
19 |
20 | - Changed return value from `List` to `Uint8List`.
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Matej Knopp
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # msgpack_dart
2 |
3 | MessagePack implementation for dart.
4 |
5 | Clean, simple, fast and with sane API and implementation.
6 |
7 |
--------------------------------------------------------------------------------
/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java:
--------------------------------------------------------------------------------
1 | package io.flutter.plugins;
2 |
3 | import io.flutter.plugin.common.PluginRegistry;
4 |
5 | /**
6 | * Generated file. Do not edit.
7 | */
8 | public final class GeneratedPluginRegistrant {
9 | public static void registerWith(PluginRegistry registry) {
10 | if (alreadyRegisteredWith(registry)) {
11 | return;
12 | }
13 | }
14 |
15 | private static boolean alreadyRegisteredWith(PluginRegistry registry) {
16 | final String key = GeneratedPluginRegistrant.class.getCanonicalName();
17 | if (registry.hasPlugin(key)) {
18 | return true;
19 | }
20 | registry.registrarFor(key);
21 | return false;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/local.properties:
--------------------------------------------------------------------------------
1 | flutter.sdk=/Users/Matej/Projects/flutter/flutter
2 | flutter.versionName=0.0.1
--------------------------------------------------------------------------------
/benchmarks.md:
--------------------------------------------------------------------------------
1 | Warming Up...
2 | Serialize
3 | ===
4 | One
5 | ---
6 | Time | JSON | MsgPack2 | msgpack_dart |
7 | -----|------|---------|--------------|
8 | Total | 18047 μs (18.047ms) | 3825 μs (3.825ms) | 3306 μs (3.306ms)
9 | Average | 1.8047 μs (0.0018047ms) | 0.3825 μs (0.00038250000000000003ms) | 0.3306 μs (0.0003306ms)
10 | Longest | 50 μs (0.05ms) | 310 μs (0.31ms) | 788 μs (0.788ms)
11 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) | 0 μs (0.0ms)
12 | Size | 1 bytes | 1 bytes | 1 bytes
13 | Fastest | msgpack_dart
14 |
15 | Five Hundred Thousand
16 | ---
17 | Time | JSON | MsgPack2 | msgpack_dart |
18 | -----|------|---------|--------------|
19 | Total | 3554 μs (3.554ms) | 8758 μs (8.758ms) | 5710 μs (5.71ms)
20 | Average | 0.3554 μs (0.0003554ms) | 0.8758 μs (0.0008758ms) | 0.571 μs (0.000571ms)
21 | Longest | 336 μs (0.336ms) | 1306 μs (1.306ms) | 1503 μs (1.503ms)
22 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) | 0 μs (0.0ms)
23 | Size | 6 bytes | 5 bytes | 5 bytes
24 | Fastest | JSON
25 |
26 | List of Small Integers
27 | ---
28 | Time | JSON | MsgPack2 | msgpack_dart |
29 | -----|------|---------|--------------|
30 | Total | 20335 μs (20.335ms) | 4704 μs (4.704ms) | 3072 μs (3.072ms)
31 | Average | 2.0335 μs (0.0020335ms) | 0.4704 μs (0.0004704ms) | 0.3072 μs (0.0003072ms)
32 | Longest | 1536 μs (1.536ms) | 125 μs (0.125ms) | 37 μs (0.037ms)
33 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) | 0 μs (0.0ms)
34 | Size | 7 bytes | 4 bytes | 4 bytes
35 | Fastest | msgpack_dart
36 |
37 | Simple Map
38 | ---
39 | Time | JSON | MsgPack2 | msgpack_dart |
40 | -----|------|---------|--------------|
41 | Total | 7402 μs (7.402ms) | 8195 μs (8.195ms) | 5981 μs (5.981ms)
42 | Average | 0.7402 μs (0.0007402ms) | 0.8195 μs (0.0008195ms) | 0.5981 μs (0.0005981ms)
43 | Longest | 435 μs (0.435ms) | 308 μs (0.308ms) | 40 μs (0.04ms)
44 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) | 0 μs (0.0ms)
45 | Size | 17 bytes | 13 bytes | 13 bytes
46 | Fastest | msgpack_dart
47 |
48 | 5.02817472928
49 | ---
50 | Time | JSON | MsgPack2 | msgpack_dart |
51 | -----|------|---------|--------------|
52 | Total | 2238 μs (2.238ms) | 4321 μs (4.321ms) | 2861 μs (2.861ms)
53 | Average | 0.2238 μs (0.0002238ms) | 0.4321 μs (0.0004321ms) | 0.2861 μs (0.0002861ms)
54 | Longest | 55 μs (0.055ms) | 216 μs (0.216ms) | 49 μs (0.049ms)
55 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) | 0 μs (0.0ms)
56 | Size | 13 bytes | 9 bytes | 9 bytes
57 | Fastest | JSON
58 |
59 | Multiple Type Map
60 | ---
61 | Time | JSON | MsgPack2 | msgpack_dart |
62 | -----|------|---------|--------------|
63 | Total | 13455 μs (13.455ms) | 15366 μs (15.366ms) | 15436 μs (15.436ms)
64 | Average | 1.3455 μs (0.0013455ms) | 1.5366 μs (0.0015366ms) | 1.5436 μs (0.0015436ms)
65 | Longest | 133 μs (0.133ms) | 150 μs (0.15ms) | 117 μs (0.117ms)
66 | Shortest | 1 μs (0.001ms) | 1 μs (0.001ms) | 1 μs (0.001ms)
67 | Size | 76 bytes | 61 bytes | 61 bytes
68 | Fastest | JSON
69 |
70 | Medium Data
71 | ---
72 | Time | JSON | MsgPack2 | msgpack_dart |
73 | -----|------|---------|--------------|
74 | Total | 120183 μs (120.183ms) | 52318 μs (52.318ms) | 49790 μs (49.79ms)
75 | Average | 12.0183 μs (0.012018299999999999ms) | 5.2318 μs (0.0052318ms) | 4.979 μs (0.004979ms)
76 | Longest | 165 μs (0.165ms) | 223 μs (0.223ms) | 187 μs (0.187ms)
77 | Shortest | 11 μs (0.011ms) | 4 μs (0.004ms) | 4 μs (0.004ms)
78 | Size | 902 bytes | 587 bytes | 587 bytes
79 | Fastest | msgpack_dart
80 |
81 | Deserialize
82 | ===
83 | One
84 | ---
85 | Time | JSON | MsgPack2 | msgpack_dart |
86 | -----|------|----------|--------------|
87 | Total | 2646 μs (2.646ms) | 2114 μs (2.114ms) |2225 μs (2.225ms)
88 | Average | 0.2646 μs (0.0002646ms) | 0.2114 μs (0.00021140000000000002ms) |0.2225 μs (0.00022250000000000001ms)
89 | Longest | 51 μs (0.051ms) | 53 μs (0.053ms) |18 μs (0.018ms)
90 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) |0 μs (0.0ms)
91 | Fastest | MsgPack2
92 |
93 | Five Hundred Thousand
94 | ---
95 | Time | JSON | MsgPack2 | msgpack_dart |
96 | -----|------|----------|--------------|
97 | Total | 2933 μs (2.933ms) | 2514 μs (2.514ms) |1941 μs (1.941ms)
98 | Average | 0.2933 μs (0.00029330000000000003ms) | 0.2514 μs (0.00025140000000000004ms) |0.1941 μs (0.0001941ms)
99 | Longest | 71 μs (0.071ms) | 25 μs (0.025ms) |14 μs (0.014ms)
100 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) |0 μs (0.0ms)
101 | Fastest | msgpack_dart
102 |
103 | List of Small Integers
104 | ---
105 | Time | JSON | MsgPack2 | msgpack_dart |
106 | -----|------|----------|--------------|
107 | Total | 3297 μs (3.297ms) | 2279 μs (2.279ms) |2162 μs (2.162ms)
108 | Average | 0.3297 μs (0.0003297ms) | 0.2279 μs (0.00022789999999999998ms) |0.2162 μs (0.0002162ms)
109 | Longest | 149 μs (0.149ms) | 44 μs (0.044ms) |46 μs (0.046ms)
110 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) |0 μs (0.0ms)
111 | Fastest | msgpack_dart
112 |
113 | Simple Map
114 | ---
115 | Time | JSON | MsgPack2 | msgpack_dart |
116 | -----|------|----------|--------------|
117 | Total | 4120 μs (4.12ms) | 5848 μs (5.848ms) |4725 μs (4.725ms)
118 | Average | 0.412 μs (0.000412ms) | 0.5848 μs (0.0005848ms) |0.4725 μs (0.0004725ms)
119 | Longest | 61 μs (0.061ms) | 135 μs (0.135ms) |66 μs (0.066ms)
120 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) |0 μs (0.0ms)
121 | Fastest | JSON
122 |
123 | 5.02817472928
124 | ---
125 | Time | JSON | MsgPack2 | msgpack_dart |
126 | -----|------|----------|--------------|
127 | Total | 4727 μs (4.727ms) | 2181 μs (2.181ms) |2079 μs (2.079ms)
128 | Average | 0.4727 μs (0.0004727ms) | 0.2181 μs (0.0002181ms) |0.2079 μs (0.0002079ms)
129 | Longest | 142 μs (0.142ms) | 21 μs (0.021ms) |43 μs (0.043ms)
130 | Shortest | 0 μs (0.0ms) | 0 μs (0.0ms) |0 μs (0.0ms)
131 | Fastest | msgpack_dart
132 |
133 | Multiple Type Map
134 | ---
135 | Time | JSON | MsgPack2 | msgpack_dart |
136 | -----|------|----------|--------------|
137 | Total | 9284 μs (9.284ms) | 14321 μs (14.321ms) |8729 μs (8.729ms)
138 | Average | 0.9284 μs (0.0009284ms) | 1.4321 μs (0.0014321ms) |0.8729 μs (0.0008729ms)
139 | Longest | 137 μs (0.137ms) | 143 μs (0.143ms) |156 μs (0.156ms)
140 | Shortest | 0 μs (0.0ms) | 1 μs (0.001ms) |0 μs (0.0ms)
141 | Fastest | msgpack_dart
142 |
143 | Medium Data
144 | ---
145 | Time | JSON | MsgPack2 | msgpack_dart |
146 | -----|------|----------|--------------|
147 | Total | 54849 μs (54.849ms) | 39660 μs (39.66ms) |23987 μs (23.987ms)
148 | Average | 5.4849 μs (0.0054849ms) | 3.966 μs (0.003966ms) |2.3987 μs (0.0023986999999999997ms)
149 | Longest | 184 μs (0.184ms) | 129 μs (0.129ms) |134 μs (0.134ms)
150 | Shortest | 4 μs (0.004ms) | 3 μs (0.003ms) |1 μs (0.001ms)
151 | Fastest | msgpack_dart
152 |
153 |
--------------------------------------------------------------------------------
/example/benchmark.dart:
--------------------------------------------------------------------------------
1 | import "dart:convert";
2 | import "dart:io";
3 |
4 | import "package:msgpack_dart/msgpack_dart.dart" as m2;
5 |
6 | const int TIMES = 10000;
7 |
8 | gcd(num a, num b) => b != 0 ? gcd(b, a % b) : a;
9 |
10 | class Fraction {
11 | final num numerator;
12 | final num denominator;
13 |
14 | Fraction(this.numerator, this.denominator);
15 |
16 | Fraction reduce() {
17 | var cd = gcd(numerator, denominator);
18 | return new Fraction(numerator / cd, denominator / cd);
19 | }
20 |
21 | Fraction cross(Fraction other) => new Fraction(
22 | other.denominator * numerator, other.numerator * denominator);
23 |
24 | @override
25 | String toString() => "${numerator}/${denominator}";
26 |
27 | String toRatioString() => "${numerator}:${denominator}";
28 | }
29 |
30 | main(List args) async {
31 | print("Warming Up...");
32 | for (var i = 0; i < TIMES; i++) {
33 | var jsonStr = json.encode({"hello": "world"});
34 |
35 | json.encode(json.decode(jsonStr));
36 | }
37 |
38 | if (args.contains("--savings")) {
39 | var numbers = [];
40 | for (var i = 1; i <= 100000; i++) {
41 | numbers.add(i);
42 | }
43 |
44 | var jsonBytes = utf8.encode(json.encode(numbers)).length;
45 | var msgpack2Bytes = m2.serialize(numbers).length;
46 | print("JSON: ${jsonBytes} bytes, MSGPACK: ${msgpack2Bytes} bytes");
47 | exit(0);
48 | }
49 |
50 | var objects = {
51 | "One": 1,
52 | "Five Hundred Thousand": 500000,
53 | "List of Small Integers": [1, 2, 3],
54 | "Simple Map": {"hello": "world"},
55 | "5.02817472928": 5.02817472928,
56 | "Multiple Type Map": {
57 | "String": "Hello World",
58 | "Integer": 1,
59 | "Double": 2.0154,
60 | "Array": const [1, 2, 3, "Hello"]
61 | },
62 | "Medium Data": {
63 | "/downstream/wemo/CoffeeMaker-1_0-221421S0000731/Brew_Age": [
64 | [1440366101049, -123881],
65 | [1440366102047, -123882],
66 | [1440366103049, -123883],
67 | [1440366104046, -123884],
68 | [1440366105062, -123885],
69 | [1440366106050, -123886],
70 | [1440366107046, -123887],
71 | [1440366108045, -123888],
72 | [1440366109036, -123889],
73 | [1440366110048, -123890],
74 | [1440366111047, -123891],
75 | [1440366112037, -123892],
76 | [1440366113048, -123893],
77 | [1440366114048, -123894],
78 | [1440366115046, -123895],
79 | [1440366116044, -123896],
80 | [1440366117045, -123897],
81 | [1440366118049, -123898],
82 | [1440366119046, -123899],
83 | [1440366120042, -123900],
84 | [1440366121047, -123901],
85 | [1440366122048, -123902],
86 | [1440366123046, -123903],
87 | [1440366124055, -123904],
88 | [1440366126059, -123906],
89 | [1440366127054, -123907],
90 | [1440366128047, -123908],
91 | [1440366129051, -123909],
92 | [1440366130051, -123910],
93 | [1440366131048, -123911],
94 | [1440366132050, -123912],
95 | [1440366133032, -123913],
96 | [1440366134045, -123914],
97 | [1440366135050, -123915],
98 | [1440366136049, -123916]
99 | ]
100 | }
101 | };
102 |
103 | bool markdown = false;
104 | if (args.contains("-m")) markdown = true;
105 |
106 | if (args.contains("-u")) {
107 | if (markdown) {
108 | print("Deserialize\n===");
109 | } else {
110 | print("=== Deserialize ===");
111 | }
112 |
113 | for (var key in objects.keys) {
114 | testObjectDecode(key, objects[key], markdown);
115 | }
116 | } else if (args.contains("-a")) {
117 | if (markdown) {
118 | print("Serialize\n===");
119 | } else {
120 | print("=== Serialize ===");
121 | }
122 | for (var key in objects.keys) {
123 | testObjectEncode(key, objects[key], markdown);
124 | }
125 | if (markdown) {
126 | print("Deserialize\n===");
127 | } else {
128 | print("=== Deserialize ===");
129 | }
130 | for (var key in objects.keys) {
131 | testObjectDecode(key, objects[key], markdown);
132 | }
133 | } else {
134 | if (markdown) {
135 | print("Serialize\n===");
136 | } else {
137 | print("=== Serialize ===");
138 | }
139 |
140 | for (var key in objects.keys) {
141 | testObjectEncode(key, objects[key], markdown);
142 | }
143 | }
144 | }
145 |
146 | testObjectDecode(String desc, input, bool markdown) {
147 | if (markdown) {
148 | print('$desc\n---');
149 | } else {
150 | print("${desc}:");
151 | }
152 | var packedJson = json.encode(input);
153 |
154 | var watch = new Stopwatch();
155 | var watchTotal = new Stopwatch();
156 | var times = [];
157 | watchTotal.start();
158 | for (var i = 1; i <= TIMES; i++) {
159 | watch.reset();
160 | watch.start();
161 | json.decode(packedJson);
162 | watch.stop();
163 | times.add(watch.elapsedMicroseconds);
164 | }
165 | var totalTime = watchTotal.elapsedMicroseconds;
166 | var avgTime = totalTime / TIMES;
167 | times.sort((a, b) => a.compareTo(b));
168 |
169 | if (!markdown) {
170 | print(" JSON:");
171 | print(" Total Time: $totalTime microseconds (${totalTime / 1000}ms)");
172 | print(" Average Time: $avgTime microseconds (${avgTime / 1000}ms)");
173 | print(
174 | " Longest Time: ${times.last} microseconds (${times.last / 1000}ms)");
175 | print(
176 | " Shortest Time: ${times.first} microseconds (${times.first / 1000}ms)");
177 | }
178 | var jTotal = totalTime;
179 | var jAvg = avgTime;
180 | var jLong = times.last;
181 | var jShort = times.first;
182 |
183 | watch.reset();
184 | times.clear();
185 | watchTotal.reset();
186 | for (var i = 1; i <= TIMES; i++) {
187 | watch.reset();
188 | watch.start();
189 | watch.stop();
190 | times.add(watch.elapsedMicroseconds);
191 | }
192 | watch.stop();
193 | totalTime = watchTotal.elapsedMicroseconds;
194 | avgTime = totalTime / TIMES;
195 | times.sort((a, b) => a.compareTo(b));
196 | if (!markdown) {
197 | print(" MsgPack2:");
198 | print(" Total Time: ${totalTime} microseconds (${totalTime / 1000}ms)");
199 | print(" Average Time: ${avgTime} microseconds (${avgTime / 1000}ms)");
200 | print(
201 | " Longest Time: ${times.last} microseconds (${times.last / 1000}ms)");
202 | print(
203 | " Shortest Time: ${times.first} microseconds (${times.first / 1000}ms)");
204 | }
205 | var nTotal = totalTime;
206 | var nAvg = avgTime;
207 | var nLong = times.last;
208 | var nShort = times.first;
209 |
210 | watch.reset();
211 | times.clear();
212 | watchTotal.reset();
213 | for (var i = 1; i <= TIMES; i++) {
214 | watch.reset();
215 | watch.start();
216 | watch.stop();
217 | times.add(watch.elapsedMicroseconds);
218 | }
219 | watch.stop();
220 | totalTime = watchTotal.elapsedMicroseconds;
221 | avgTime = totalTime / TIMES;
222 | times.sort((a, b) => a.compareTo(b));
223 | if (!markdown) {
224 | print(" msgpack_dart");
225 | print(" Total Time: ${totalTime} microseconds (${totalTime / 1000}ms)");
226 | print(" Average Time: ${avgTime} microseconds (${avgTime / 1000}ms)");
227 | print(
228 | " Longest Time: ${times.last} microseconds (${times.last / 1000}ms)");
229 | print(
230 | " Shortest Time: ${times.first} microseconds (${times.first / 1000}ms)");
231 | }
232 | var n2Total = totalTime;
233 | var n2Avg = avgTime;
234 | var n2Long = times.last;
235 | var n2Short = times.first;
236 |
237 | if (markdown) {
238 | print("Time | JSON | MsgPack2 | msgpack_dart |");
239 | print("-----|------|----------|--------------|");
240 | print("Total | $jTotal μs (${jTotal / 1000}ms) | " +
241 | "$nTotal μs (${nTotal / 1000}ms) |" +
242 | "$n2Total μs (${n2Total / 1000}ms)");
243 | print("Average | $jAvg μs (${jAvg / 1000}ms) | " +
244 | "$nAvg μs (${nAvg / 1000}ms) |" +
245 | "$n2Avg μs (${n2Avg / 1000}ms)");
246 | print("Longest | $jLong μs (${jLong / 1000}ms) | " +
247 | "$nLong μs (${nLong / 1000}ms) |" +
248 | "$n2Long μs (${n2Long / 1000}ms)");
249 | print("Shortest | $jShort μs (${jShort / 1000}ms) | " +
250 | "$nShort μs (${nShort / 1000}ms) |" +
251 | "$n2Short μs (${n2Short / 1000}ms)");
252 | }
253 |
254 | var bestAvg = n2Avg;
255 | String fastest = "msgpack_dart";
256 | if (nAvg < bestAvg) {
257 | bestAvg = nAvg;
258 | fastest = "MsgPack2";
259 | }
260 | if (jAvg < bestAvg) {
261 | bestAvg = jAvg;
262 | fastest = "JSON";
263 | }
264 |
265 | if (markdown) {
266 | print("Fastest | $fastest\n");
267 | } else {
268 | print(" $fastest was fastest");
269 | }
270 | }
271 |
272 | testObjectEncode(String desc, input, bool markdown) {
273 | if (markdown) {
274 | print("$desc\n---");
275 | } else {
276 | print("${desc}:");
277 | }
278 | var watch = new Stopwatch();
279 | var watchTotal = new Stopwatch();
280 | var times = [];
281 |
282 | watchTotal.start();
283 | int size = utf8.encode(json.encode(input)).length;
284 | for (var i = 1; i <= TIMES; i++) {
285 | watch.reset();
286 | watch.start();
287 | json.encode(input);
288 | watch.stop();
289 | times.add(watch.elapsedMicroseconds);
290 | }
291 | var totalTime = watchTotal.elapsedMicroseconds;
292 | ;
293 | var avgTime = totalTime / TIMES;
294 | times.sort((a, b) => a.compareTo(b));
295 | if (!markdown) {
296 | print(" JSON:");
297 | print(" Total Time: $totalTime microseconds (${totalTime / 1000}ms)");
298 | print(" Average Time: $avgTime microseconds (${avgTime / 1000}ms)");
299 | print(
300 | " Longest Time: ${times.last} microseconds (${times.last / 1000}ms)");
301 | print(
302 | " Shortest Time: ${times.first} microseconds (${times.first / 1000}ms)");
303 | print(" Size: ${size} bytes");
304 | }
305 | var jTotal = totalTime;
306 | var jAvg = avgTime;
307 | var jLong = times.last;
308 | var jShort = times.first;
309 | var jSize = size;
310 |
311 | watch.reset();
312 | times.clear();
313 | watchTotal.reset();
314 | for (var i = 1; i <= TIMES; i++) {
315 | watch.reset();
316 | watch.start();
317 | watch.stop();
318 | times.add(watch.elapsedMicroseconds);
319 | }
320 | watch.stop();
321 | totalTime = watchTotal.elapsedMicroseconds;
322 | avgTime = totalTime / TIMES;
323 | times.sort((a, b) => a.compareTo(b));
324 | if (!markdown) {
325 | print(" MsgPack2:");
326 | print(" Total Time: ${totalTime} microseconds (${totalTime / 1000}ms)");
327 | print(" Average Time: ${avgTime} microseconds (${avgTime / 1000}ms)");
328 | print(
329 | " Longest Time: ${times.last} microseconds (${times.last / 1000}ms)");
330 | print(
331 | " Shortest Time: ${times.first} microseconds (${times.first / 1000}ms)");
332 | print(" Size: ${size} bytes");
333 | }
334 | var nTotal = totalTime;
335 | var nAvg = avgTime;
336 | var nLong = times.last;
337 | var nShort = times.first;
338 | var nSize = size;
339 |
340 | watch.reset();
341 | size = m2.serialize(input).length;
342 | times.clear();
343 | watchTotal.reset();
344 | for (var i = 1; i <= TIMES; i++) {
345 | watch.reset();
346 | watch.start();
347 | m2.serialize(input);
348 | watch.stop();
349 | times.add(watch.elapsedMicroseconds);
350 | }
351 | watch.stop();
352 | totalTime = watchTotal.elapsedMicroseconds;
353 | avgTime = totalTime / TIMES;
354 | times.sort((a, b) => a.compareTo(b));
355 | if (!markdown) {
356 | print(" msgpack_dart:");
357 | print(" Total Time: ${totalTime} microseconds (${totalTime / 1000}ms)");
358 | print(" Average Time: ${avgTime} microseconds (${avgTime / 1000}ms)");
359 | print(
360 | " Longest Time: ${times.last} microseconds (${times.last / 1000}ms)");
361 | print(
362 | " Shortest Time: ${times.first} microseconds (${times.first / 1000}ms)");
363 | print(" Size: ${size} bytes");
364 | }
365 | var n2Total = totalTime;
366 | var n2Avg = avgTime;
367 | var n2Long = times.last;
368 | var n2Short = times.first;
369 | var n2Size = size;
370 |
371 | if (markdown) {
372 | print("Time | JSON | MsgPack2 | msgpack_dart |");
373 | print("-----|------|---------|--------------|");
374 | print("Total | $jTotal μs (${jTotal / 1000}ms) | " +
375 | "$nTotal μs (${nTotal / 1000}ms) | " +
376 | "$n2Total μs (${n2Total / 1000}ms)");
377 | print("Average | $jAvg μs (${jAvg / 1000}ms) | " +
378 | "$nAvg μs (${nAvg / 1000}ms) | " +
379 | "$n2Avg μs (${n2Avg / 1000}ms)");
380 | print("Longest | $jLong μs (${jLong / 1000}ms) | " +
381 | "$nLong μs (${nLong / 1000}ms) | " +
382 | "$n2Long μs (${n2Long / 1000}ms)");
383 | print("Shortest | $jShort μs (${jShort / 1000}ms) | " +
384 | "$nShort μs (${nShort / 1000}ms) | " +
385 | "$n2Short μs (${n2Short / 1000}ms)");
386 | print("Size | $jSize bytes | $nSize bytes | $n2Size bytes");
387 | }
388 |
389 | var bestAvg = n2Avg;
390 | String fastest = "msgpack_dart";
391 | if (nAvg < bestAvg) {
392 | bestAvg = nAvg;
393 | fastest = "MsgPack2";
394 | }
395 | if (jAvg < bestAvg) {
396 | bestAvg = jAvg;
397 | fastest = "JSON";
398 | }
399 |
400 | if (markdown) {
401 | print("Fastest | $fastest\n");
402 | } else {
403 | print(" $fastest was fastest");
404 | }
405 | }
406 |
--------------------------------------------------------------------------------
/lib/msgpack_dart.dart:
--------------------------------------------------------------------------------
1 | library msgpack_dart;
2 |
3 | import 'dart:convert';
4 | import 'dart:typed_data';
5 |
6 | part 'src/common.dart';
7 | part 'src/data_writer.dart';
8 | part 'src/deserializer.dart';
9 | part 'src/serializer.dart';
10 |
11 | Uint8List serialize(
12 | dynamic value, {
13 | ExtEncoder? extEncoder,
14 | }) {
15 | final s = Serializer(extEncoder: extEncoder);
16 | s.encode(value);
17 | return s.takeBytes();
18 | }
19 |
20 | dynamic deserialize(
21 | Uint8List list, {
22 | ExtDecoder? extDecoder,
23 | bool copyBinaryData = false,
24 | }) {
25 | final d = Deserializer(
26 | list,
27 | extDecoder: extDecoder,
28 | copyBinaryData: copyBinaryData,
29 | );
30 | return d.decode();
31 | }
32 |
--------------------------------------------------------------------------------
/lib/src/common.dart:
--------------------------------------------------------------------------------
1 | part of msgpack_dart;
2 |
3 | class FormatError implements Exception {
4 | FormatError(this.message);
5 | final String message;
6 |
7 | String toString() {
8 | return "FormatError: $message";
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/src/data_writer.dart:
--------------------------------------------------------------------------------
1 | part of msgpack_dart;
2 |
3 | final int _kScratchSizeInitial = 64;
4 | final int _kScratchSizeRegular = 1024;
5 |
6 | class DataWriter {
7 | Uint8List? _scratchBuffer;
8 | ByteData? _scratchData;
9 | int _scratchOffset = 0;
10 |
11 | void writeUint8(int i) {
12 | _ensureSize(1);
13 | _scratchData?.setUint8(_scratchOffset, i);
14 | _scratchOffset += 1;
15 | }
16 |
17 | void writeInt8(int i) {
18 | _ensureSize(1);
19 | _scratchData?.setInt8(_scratchOffset, i);
20 | _scratchOffset += 1;
21 | }
22 |
23 | void writeUint16(int i, [Endian endian = Endian.big]) {
24 | _ensureSize(2);
25 | _scratchData?.setUint16(_scratchOffset, i, endian);
26 | _scratchOffset += 2;
27 | }
28 |
29 | void writeInt16(int i, [Endian endian = Endian.big]) {
30 | _ensureSize(2);
31 | _scratchData?.setInt16(_scratchOffset, i, endian);
32 | _scratchOffset += 2;
33 | }
34 |
35 | void writeUint32(int i, [Endian endian = Endian.big]) {
36 | _ensureSize(4);
37 | _scratchData?.setUint32(_scratchOffset, i, endian);
38 | _scratchOffset += 4;
39 | }
40 |
41 | void writeInt32(int i, [Endian endian = Endian.big]) {
42 | _ensureSize(4);
43 | _scratchData?.setInt32(_scratchOffset, i, endian);
44 | _scratchOffset += 4;
45 | }
46 |
47 | void writeUint64(int i, [Endian endian = Endian.big]) {
48 | _ensureSize(8);
49 | _scratchData?.setUint64(_scratchOffset, i, endian);
50 | _scratchOffset += 8;
51 | }
52 |
53 | void writeInt64(int i, [Endian endian = Endian.big]) {
54 | _ensureSize(8);
55 | _scratchData?.setInt64(_scratchOffset, i, endian);
56 | _scratchOffset += 8;
57 | }
58 |
59 | void writeFloat32(double f, [Endian endian = Endian.big]) {
60 | _ensureSize(4);
61 | _scratchData?.setFloat32(_scratchOffset, f, endian);
62 | _scratchOffset += 4;
63 | }
64 |
65 | void writeFloat64(double f, [Endian endian = Endian.big]) {
66 | _ensureSize(8);
67 | _scratchData?.setFloat64(_scratchOffset, f, endian);
68 | _scratchOffset += 8;
69 | }
70 |
71 | // The list may be retained until takeBytes is called
72 | void writeBytes(List bytes) {
73 | final length = bytes.length;
74 | if (length == 0) {
75 | return;
76 | }
77 | _ensureSize(length);
78 | if (_scratchOffset == 0) {
79 | // we can add it directly
80 | _builder.add(bytes);
81 | } else {
82 | // there is enough room in _scratchBuffer, otherwise _ensureSize
83 | // would have added _scratchBuffer to _builder and _scratchOffset would
84 | // be 0
85 | if (bytes is Uint8List) {
86 | _scratchBuffer?.setRange(
87 | _scratchOffset, _scratchOffset + length, bytes);
88 | } else {
89 | for (int i = 0; i < length; i++) {
90 | _scratchBuffer?[_scratchOffset + i] = bytes[i];
91 | }
92 | }
93 | _scratchOffset += length;
94 | }
95 | }
96 |
97 | Uint8List takeBytes() {
98 | if (_builder.isEmpty) {
99 | // Just take scratch data
100 | final res = Uint8List.view(
101 | _scratchBuffer!.buffer,
102 | _scratchBuffer!.offsetInBytes,
103 | _scratchOffset,
104 | );
105 | _scratchOffset = 0;
106 | _scratchBuffer = null;
107 | _scratchData = null;
108 | return res;
109 | } else {
110 | _appendScratchBuffer();
111 | return _builder.takeBytes();
112 | }
113 | }
114 |
115 | void _ensureSize(int size) {
116 | if (_scratchBuffer == null) {
117 | // start with small scratch buffer, expand to regular later if needed
118 | _scratchBuffer = Uint8List(_kScratchSizeInitial);
119 | _scratchData =
120 | ByteData.view(_scratchBuffer!.buffer, _scratchBuffer!.offsetInBytes);
121 | }
122 | final remaining = _scratchBuffer!.length - _scratchOffset;
123 | if (remaining < size) {
124 | _appendScratchBuffer();
125 | }
126 | }
127 |
128 | void _appendScratchBuffer() {
129 | if (_scratchOffset > 0) {
130 | if (_builder.isEmpty) {
131 | // We're still on small scratch buffer, move it to _builder
132 | // and create regular one
133 | _builder.add(Uint8List.view(
134 | _scratchBuffer!.buffer,
135 | _scratchBuffer!.offsetInBytes,
136 | _scratchOffset,
137 | ));
138 | _scratchBuffer = Uint8List(_kScratchSizeRegular);
139 | _scratchData = ByteData.view(
140 | _scratchBuffer!.buffer, _scratchBuffer!.offsetInBytes);
141 | } else {
142 | _builder.add(
143 | Uint8List.fromList(
144 | Uint8List.view(
145 | _scratchBuffer!.buffer,
146 | _scratchBuffer!.offsetInBytes,
147 | _scratchOffset,
148 | ),
149 | ),
150 | );
151 | }
152 | _scratchOffset = 0;
153 | }
154 | }
155 |
156 | final _builder = BytesBuilder(copy: false);
157 | }
158 |
--------------------------------------------------------------------------------
/lib/src/deserializer.dart:
--------------------------------------------------------------------------------
1 | part of msgpack_dart;
2 |
3 | abstract class ExtDecoder {
4 | dynamic decodeObject(int extType, Uint8List data);
5 | }
6 |
7 | class Deserializer {
8 | final ExtDecoder? _extDecoder;
9 | final codec = Utf8Codec();
10 | final Uint8List _list;
11 | final ByteData _data;
12 | int _offset = 0;
13 |
14 | Deserializer(
15 | Uint8List list, {
16 | ExtDecoder? extDecoder,
17 | this.copyBinaryData = false,
18 | }) : _list = list,
19 | _data = ByteData.view(list.buffer, list.offsetInBytes),
20 | _extDecoder = extDecoder;
21 |
22 | /// If false, decoded binary data buffers will reference underlying input
23 | /// buffer and thus may change when the content of input buffer changes.
24 | ///
25 | /// If true, decoded buffers are copies and the underlying input buffer is
26 | /// free to change after decoding.
27 | final bool copyBinaryData;
28 |
29 | dynamic decode() {
30 | final u = _list[_offset++];
31 | if (u <= 127) {
32 | return u;
33 | } else if ((u & 0xE0) == 0xE0) {
34 | // negative small integer
35 | return u - 256;
36 | } else if ((u & 0xE0) == 0xA0) {
37 | return _readString(u & 0x1F);
38 | } else if ((u & 0xF0) == 0x90) {
39 | return _readArray(u & 0xF);
40 | } else if ((u & 0xF0) == 0x80) {
41 | return _readMap(u & 0xF);
42 | }
43 | switch (u) {
44 | case 0xc0:
45 | return null;
46 | case 0xc2:
47 | return false;
48 | case 0xc3:
49 | return true;
50 | case 0xcc:
51 | return _readUInt8();
52 | case 0xcd:
53 | return _readUInt16();
54 | case 0xce:
55 | return _readUInt32();
56 | case 0xcf:
57 | return _readUInt64();
58 | case 0xd0:
59 | return _readInt8();
60 | case 0xd1:
61 | return _readInt16();
62 | case 0xd2:
63 | return _readInt32();
64 | case 0xd3:
65 | return _readInt64();
66 | case 0xca:
67 | return _readFloat();
68 | case 0xcb:
69 | return _readDouble();
70 | case 0xd9:
71 | return _readString(_readUInt8());
72 | case 0xda:
73 | return _readString(_readUInt16());
74 | case 0xdb:
75 | return _readString(_readUInt32());
76 | case 0xc4:
77 | return _readBuffer(_readUInt8());
78 | case 0xc5:
79 | return _readBuffer(_readUInt16());
80 | case 0xc6:
81 | return _readBuffer(_readUInt32());
82 | case 0xdc:
83 | return _readArray(_readUInt16());
84 | case 0xdd:
85 | return _readArray(_readUInt32());
86 | case 0xde:
87 | return _readMap(_readUInt16());
88 | case 0xdf:
89 | return _readMap(_readUInt32());
90 | case 0xd4:
91 | return _readExt(1);
92 | case 0xd5:
93 | return _readExt(2);
94 | case 0xd6:
95 | return _readExt(4);
96 | case 0xd7:
97 | return _readExt(8);
98 | case 0xd8:
99 | return _readExt(16);
100 | case 0xc7:
101 | return _readExt(_readUInt8());
102 | case 0xc8:
103 | return _readExt(_readUInt16());
104 | case 0xc9:
105 | return _readExt(_readUInt32());
106 | default:
107 | throw FormatError("Invalid MessagePack format");
108 | }
109 | }
110 |
111 | int _readInt8() {
112 | return _data.getInt8(_offset++);
113 | }
114 |
115 | int _readUInt8() {
116 | return _data.getUint8(_offset++);
117 | }
118 |
119 | int _readUInt16() {
120 | final res = _data.getUint16(_offset);
121 | _offset += 2;
122 | return res;
123 | }
124 |
125 | int _readInt16() {
126 | final res = _data.getInt16(_offset);
127 | _offset += 2;
128 | return res;
129 | }
130 |
131 | int _readUInt32() {
132 | final res = _data.getUint32(_offset);
133 | _offset += 4;
134 | return res;
135 | }
136 |
137 | int _readInt32() {
138 | final res = _data.getInt32(_offset);
139 | _offset += 4;
140 | return res;
141 | }
142 |
143 | int _readUInt64() {
144 | final res = _data.getUint64(_offset);
145 | _offset += 8;
146 | return res;
147 | }
148 |
149 | int _readInt64() {
150 | final res = _data.getInt64(_offset);
151 | _offset += 8;
152 | return res;
153 | }
154 |
155 | double _readFloat() {
156 | final res = _data.getFloat32(_offset);
157 | _offset += 4;
158 | return res;
159 | }
160 |
161 | double _readDouble() {
162 | final res = _data.getFloat64(_offset);
163 | _offset += 8;
164 | return res;
165 | }
166 |
167 | Uint8List _readBuffer(int length) {
168 | final res =
169 | Uint8List.view(_list.buffer, _list.offsetInBytes + _offset, length);
170 | _offset += length;
171 | return copyBinaryData ? Uint8List.fromList(res) : res;
172 | }
173 |
174 | String _readString(int length) {
175 | final list = _readBuffer(length);
176 | final len = list.length;
177 | for (int i = 0; i < len; ++i) {
178 | if (list[i] > 127) {
179 | return codec.decode(list);
180 | }
181 | }
182 | return String.fromCharCodes(list);
183 | }
184 |
185 | List _readArray(int length) {
186 | final res = List.filled(length, null, growable: false);
187 | for (int i = 0; i < length; ++i) {
188 | res[i] = decode();
189 | }
190 | return res;
191 | }
192 |
193 | Map _readMap(int length) {
194 | final res = Map();
195 | while (length > 0) {
196 | res[decode()] = decode();
197 | --length;
198 | }
199 | return res;
200 | }
201 |
202 | dynamic _readExt(int length) {
203 | final extType = _readUInt8();
204 | final data = _readBuffer(length);
205 | return _extDecoder?.decodeObject(extType, data);
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/lib/src/serializer.dart:
--------------------------------------------------------------------------------
1 | part of msgpack_dart;
2 |
3 | abstract class ExtEncoder {
4 | // Return null if object can't be encoded
5 | int extTypeForObject(dynamic object);
6 |
7 | Uint8List encodeObject(dynamic object);
8 | }
9 |
10 | class Float {
11 | Float(this.value);
12 |
13 | final double value;
14 |
15 | @override
16 | String toString() => value.toString();
17 | }
18 |
19 | class Serializer {
20 | final _codec = Utf8Codec();
21 | final DataWriter _writer;
22 | final ExtEncoder? _extEncoder;
23 |
24 | Serializer({
25 | DataWriter? dataWriter,
26 | ExtEncoder? extEncoder,
27 | }) : _writer = dataWriter ?? DataWriter(),
28 | _extEncoder = extEncoder;
29 |
30 | void encode(dynamic d) {
31 | if (d == null) return _writer.writeUint8(0xc0);
32 | if (d is bool) return _writer.writeUint8(d == true ? 0xc3 : 0xc2);
33 | if (d is int) return d >= 0 ? _writePositiveInt(d) : _writeNegativeInt(d);
34 | if (d is Float) return _writeFloat(d);
35 | if (d is double) return _writeDouble(d);
36 | if (d is String) return _writeString(d);
37 | if (d is Uint8List) return _writeBinary(d);
38 | if (d is Iterable) return _writeIterable(d);
39 | if (d is ByteData)
40 | return _writeBinary(
41 | d.buffer.asUint8List(d.offsetInBytes, d.lengthInBytes));
42 | if (d is Map) return _writeMap(d);
43 | if (_extEncoder != null && _writeExt(d)) {
44 | return;
45 | }
46 | throw FormatError("Don't know how to serialize $d");
47 | }
48 |
49 | Uint8List takeBytes() {
50 | return _writer.takeBytes();
51 | }
52 |
53 | void _writeNegativeInt(int n) {
54 | if (n >= -32) {
55 | this._writer.writeInt8(n);
56 | } else if (n >= -128) {
57 | this._writer.writeUint8(0xd0);
58 | this._writer.writeInt8(n);
59 | } else if (n >= -32768) {
60 | this._writer.writeUint8(0xd1);
61 | this._writer.writeInt16(n);
62 | } else if (n >= -2147483648) {
63 | this._writer.writeUint8(0xd2);
64 | this._writer.writeInt32(n);
65 | } else {
66 | this._writer.writeUint8(0xd3);
67 | this._writer.writeInt64(n);
68 | }
69 | }
70 |
71 | void _writePositiveInt(int n) {
72 | if (n <= 127) {
73 | this._writer.writeUint8(n);
74 | } else if (n <= 0xFF) {
75 | this._writer.writeUint8(0xcc);
76 | this._writer.writeUint8(n);
77 | } else if (n <= 0xFFFF) {
78 | this._writer.writeUint8(0xcd);
79 | this._writer.writeUint16(n);
80 | } else if (n <= 0xFFFFFFFF) {
81 | this._writer.writeUint8(0xce);
82 | this._writer.writeUint32(n);
83 | } else {
84 | this._writer.writeUint8(0xcf);
85 | this._writer.writeUint64(n);
86 | }
87 | }
88 |
89 | void _writeFloat(Float n) {
90 | _writer.writeUint8(0xca);
91 | _writer.writeFloat32(n.value);
92 | }
93 |
94 | void _writeDouble(double n) {
95 | _writer.writeUint8(0xcb);
96 | _writer.writeFloat64(n);
97 | }
98 |
99 | void _writeString(String s) {
100 | final encoded = _codec.encode(s);
101 | final length = encoded.length;
102 | if (length <= 31) {
103 | _writer.writeUint8(0xA0 | length);
104 | } else if (length <= 0xFF) {
105 | _writer.writeUint8(0xd9);
106 | _writer.writeUint8(length);
107 | } else if (length <= 0xFFFF) {
108 | _writer.writeUint8(0xda);
109 | _writer.writeUint16(length);
110 | } else if (length <= 0xFFFFFFFF) {
111 | _writer.writeUint8(0xdb);
112 | _writer.writeUint32(length);
113 | } else {
114 | throw FormatError("String is too long to be serialized with msgpack.");
115 | }
116 | _writer.writeBytes(encoded);
117 | }
118 |
119 | void _writeBinary(Uint8List buffer) {
120 | final length = buffer.length;
121 | if (length <= 0xFF) {
122 | _writer.writeUint8(0xc4);
123 | _writer.writeUint8(length);
124 | } else if (length <= 0xFFFF) {
125 | _writer.writeUint8(0xc5);
126 | _writer.writeUint16(length);
127 | } else if (length <= 0xFFFFFFFF) {
128 | _writer.writeUint8(0xc6);
129 | _writer.writeUint32(length);
130 | } else {
131 | throw FormatError("Data is too long to be serialized with msgpack.");
132 | }
133 | _writer.writeBytes(buffer);
134 | }
135 |
136 | void _writeIterable(Iterable iterable) {
137 | final length = iterable.length;
138 |
139 | if (length <= 0xF) {
140 | _writer.writeUint8(0x90 | length);
141 | } else if (length <= 0xFFFF) {
142 | _writer.writeUint8(0xdc);
143 | _writer.writeUint16(length);
144 | } else if (length <= 0xFFFFFFFF) {
145 | _writer.writeUint8(0xdd);
146 | _writer.writeUint32(length);
147 | } else {
148 | throw FormatError("Array is too big to be serialized with msgpack");
149 | }
150 |
151 | for (final item in iterable) {
152 | encode(item);
153 | }
154 | }
155 |
156 | void _writeMap(Map map) {
157 | final length = map.length;
158 |
159 | if (length <= 0xF) {
160 | _writer.writeUint8(0x80 | length);
161 | } else if (length <= 0xFFFF) {
162 | _writer.writeUint8(0xde);
163 | _writer.writeUint16(length);
164 | } else if (length <= 0xFFFFFFFF) {
165 | _writer.writeUint8(0xdf);
166 | _writer.writeUint32(length);
167 | } else {
168 | throw FormatError("Map is too big to be serialized with msgpack");
169 | }
170 |
171 | for (final item in map.entries) {
172 | encode(item.key);
173 | encode(item.value);
174 | }
175 | }
176 |
177 | bool _writeExt(dynamic object) {
178 | int? type = _extEncoder?.extTypeForObject(object);
179 | if (type != null) {
180 | if (type < 0) {
181 | throw FormatError("Negative ext type is reserved");
182 | }
183 | final encoded = _extEncoder?.encodeObject(object);
184 | if (encoded == null)
185 | throw FormatError('Unable to encode object. No Encoder specified.');
186 |
187 | final length = encoded.length;
188 | if (length == 1) {
189 | _writer.writeUint8(0xd4);
190 | } else if (length == 2) {
191 | _writer.writeUint8(0xd5);
192 | } else if (length == 4) {
193 | _writer.writeUint8(0xd6);
194 | } else if (length == 8) {
195 | _writer.writeUint8(0xd7);
196 | } else if (length == 16) {
197 | _writer.writeUint8(0xd8);
198 | } else if (length <= 0xFF) {
199 | _writer.writeUint8(0xc7);
200 | _writer.writeUint8(length);
201 | } else if (length <= 0xFFFF) {
202 | _writer.writeUint8(0xc8);
203 | _writer.writeUint16(length);
204 | } else if (length <= 0xFFFFFFFF) {
205 | _writer.writeUint8(0xc9);
206 | _writer.writeUint32(length);
207 | } else {
208 | throw FormatError("Size must be at most 0xFFFFFFFF");
209 | }
210 | this._writer.writeUint8(type);
211 | this._writer.writeBytes(encoded);
212 | return true;
213 | }
214 | return false;
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/msgpack_dart.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: msgpack_dart
2 | description: Message Pack implementation for dart
3 | version: 1.0.1
4 | homepage: https://github.com/knopp/msgpack_dart
5 |
6 | environment:
7 | sdk: ">=2.12.0 <3.0.0"
8 |
9 | dev_dependencies:
10 | test: ^1.3.0
11 |
--------------------------------------------------------------------------------
/test/msgpack_dart_test.dart:
--------------------------------------------------------------------------------
1 | import 'dart:typed_data';
2 |
3 | import "package:msgpack_dart/msgpack_dart.dart";
4 | import 'package:test/test.dart';
5 |
6 | //
7 | // Tests taken from msgpack2 (https://github.com/butlermatt/msgpack2)
8 | //
9 |
10 | var isString = predicate((e) => e is String, 'is a String');
11 | var isInt = predicate((e) => e is int, 'is an int');
12 | var isMap = predicate((e) => e is Map, 'is a Map');
13 | var isList = predicate((e) => e is List, 'is a List');
14 |
15 | void main() {
16 | test("Test Pack null", packNull);
17 |
18 | group("Test Pack Boolean", () {
19 | test("Pack boolean false", packFalse);
20 | test("Pack boolean true", packTrue);
21 | });
22 |
23 | group("Test Pack Ints", () {
24 | test("Pack Positive FixInt", packPositiveFixInt);
25 | test("Pack Negative FixInt", packFixedNegative);
26 | test("Pack Uint8", packUint8);
27 | test("Pack Uint16", packUint16);
28 | test("Pack Uint32", packUint32);
29 | test("Pack Uint64", packUint64);
30 | test("Pack Int8", packInt8);
31 | test("Pack Int16", packInt16);
32 | test("Pack Int32", packInt32);
33 | test("Pack Int64", packInt64);
34 | });
35 |
36 | group("Test Pack Floats", () {
37 | test("Pack Float32", packFloat32);
38 | test("Pack Float64 (double)", packDouble);
39 | });
40 |
41 | test("Pack 5-character string", packString5);
42 | test("Pack 22-character string", packString22);
43 | test("Pack 256-character string", packString256);
44 | test("Pack string array", packStringArray);
45 | test("Pack int-to-string map", packIntToStringMap);
46 |
47 | group("Test Pack Binary", () {
48 | test("Pack Bin8", packBin8);
49 | test("Pack Bin16", packBin16);
50 | test("Pack Bin32", packBin32);
51 | test("Pack ByteData", packByteData);
52 | });
53 |
54 | test("Test Unpack Null", unpackNull);
55 |
56 | group("Test Unpack boolean", () {
57 | test("Unpack boolean false", unpackFalse);
58 | test("Unpack boolean true", unpackTrue);
59 | });
60 |
61 | group("Test Unpack Ints", () {
62 | test("Unpack Positive FixInt", unpackPositiveFixInt);
63 | test("Unpack Negative FixInt", unpackNegativeFixInt);
64 | test("Unpack Uint8", unpackUint8);
65 | test("Unpack Uint16", unpackUint16);
66 | test("Unpack Uint32", unpackUint32);
67 | test("Unpack Uint64", unpackUint64);
68 | test("Unpack Int8", unpackInt8);
69 | test("Unpack Int16", unpackInt16);
70 | test("Unpack Int32", unpackInt32);
71 | test("Unpack Int64", unpackInt64);
72 | });
73 |
74 | group("Test Unpack Floats", () {
75 | test("Unpack Float32", unpackFloat32);
76 | test("Unpack Float64 (double)", unpackDouble);
77 | });
78 |
79 | test("Unpack 5-character string", unpackString5);
80 | test("Unpack 22-character string", unpackString22);
81 | test("Unpack 256-character string", unpackString256);
82 | test("Unpack string array", unpackStringArray);
83 | test("Unpack int-to-string map", unpackIntToStringMap);
84 |
85 | group("Test Large Array and Map", () {
86 | test("Large Array", largeArray);
87 | test("Very Large Array", veryLargeArray);
88 | test("Large Map", largeMap);
89 | test("Very Large Map", veryLargeMap);
90 | });
91 | }
92 |
93 | void largeArray() {
94 | final list = [];
95 | for (int i = 0; i < 16; ++i) {
96 | list.add("Item $i");
97 | }
98 |
99 | final serialized = serialize(list);
100 | List deserialized = deserialize(serialized);
101 | expect(deserialized, list);
102 | }
103 |
104 | void veryLargeArray() {
105 | final list = [];
106 | for (int i = 0; i < 65536; ++i) {
107 | list.add("Item $i");
108 | }
109 |
110 | final serialized = serialize(list);
111 | List deserialized = deserialize(serialized);
112 | expect(deserialized, list);
113 | }
114 |
115 | void largeMap() {
116 | final map = Map();
117 | for (int i = 0; i < 16; ++i) {
118 | map[i] = "Item $i";
119 | }
120 | final serialized = serialize(map);
121 | Map deserialized = deserialize(serialized);
122 | expect(deserialized, map);
123 | }
124 |
125 | void veryLargeMap() {
126 | final map = Map();
127 | for (int i = 0; i < 65536; ++i) {
128 | map[i] = "Item $i";
129 | }
130 | final serialized = serialize(map);
131 | Map deserialized = deserialize(serialized);
132 | expect(deserialized, map);
133 | }
134 |
135 | void packNull() {
136 | List encoded = serialize(null);
137 | expect(encoded, orderedEquals([0xc0]));
138 | }
139 |
140 | void packFalse() {
141 | List encoded = serialize(false);
142 | expect(encoded, orderedEquals([0xc2]));
143 | }
144 |
145 | void packTrue() {
146 | List encoded = serialize(true);
147 | expect(encoded, orderedEquals([0xc3]));
148 | }
149 |
150 | void packPositiveFixInt() {
151 | List encoded = serialize(1);
152 | expect(encoded, orderedEquals([1]));
153 | }
154 |
155 | void packFixedNegative() {
156 | List encoded = serialize(-16);
157 | expect(encoded, orderedEquals([240]));
158 | }
159 |
160 | void packUint8() {
161 | List encoded = serialize(128);
162 | expect(encoded, orderedEquals([204, 128]));
163 | }
164 |
165 | void packUint16() {
166 | List encoded = serialize(32768);
167 | expect(encoded, orderedEquals([205, 128, 0]));
168 | }
169 |
170 | void packUint32() {
171 | List encoded = serialize(2147483648);
172 | expect(encoded, orderedEquals([206, 128, 0, 0, 0]));
173 | }
174 |
175 | void packUint64() {
176 | List encoded = serialize(9223372036854775807);
177 | expect(encoded, orderedEquals([207, 127, 255, 255, 255, 255, 255, 255, 255]));
178 | }
179 |
180 | void packInt8() {
181 | List encoded = serialize(-128);
182 | expect(encoded, orderedEquals([208, 128]));
183 | }
184 |
185 | void packInt16() {
186 | List encoded = serialize(-32768);
187 | expect(encoded, orderedEquals([209, 128, 0]));
188 | }
189 |
190 | void packInt32() {
191 | List encoded = serialize(-2147483648);
192 | expect(encoded, orderedEquals([210, 128, 0, 0, 0]));
193 | }
194 |
195 | void packInt64() {
196 | List encoded = serialize(-9223372036854775808);
197 | expect(encoded, orderedEquals([211, 128, 0, 0, 0, 0, 0, 0, 0]));
198 | }
199 |
200 | void packFloat32() {
201 | List encoded = serialize(Float(3.14));
202 | expect(encoded, orderedEquals([202, 64, 72, 245, 195]));
203 | }
204 |
205 | void packDouble() {
206 | List encoded = serialize(3.14);
207 | expect(encoded,
208 | orderedEquals([0xcb, 0x40, 0x09, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f]));
209 | }
210 |
211 | void packString5() {
212 | List encoded = serialize("hello");
213 | expect(encoded, orderedEquals([165, 104, 101, 108, 108, 111]));
214 | }
215 |
216 | void packString22() {
217 | List encoded = serialize("hello there, everyone!");
218 | expect(
219 | encoded,
220 | orderedEquals([
221 | 182,
222 | 104,
223 | 101,
224 | 108,
225 | 108,
226 | 111,
227 | 32,
228 | 116,
229 | 104,
230 | 101,
231 | 114,
232 | 101,
233 | 44,
234 | 32,
235 | 101,
236 | 118,
237 | 101,
238 | 114,
239 | 121,
240 | 111,
241 | 110,
242 | 101,
243 | 33
244 | ]));
245 | }
246 |
247 | void packString256() {
248 | List encoded = serialize(
249 | "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
250 | expect(encoded, hasLength(259));
251 | expect(encoded.sublist(0, 3), orderedEquals([218, 1, 0]));
252 | expect(encoded.sublist(3, 259), everyElement(65));
253 | }
254 |
255 | void packBin8() {
256 | var data = Uint8List.fromList(List.filled(32, 65));
257 | List encoded = serialize(data);
258 | expect(encoded.length, equals(34));
259 | expect(encoded.getRange(0, 2), orderedEquals([0xc4, 32]));
260 | expect(encoded.getRange(2, encoded.length), orderedEquals(data));
261 | }
262 |
263 | void packBin16() {
264 | var data = Uint8List.fromList(List.filled(256, 65));
265 | List encoded = serialize(data);
266 | expect(encoded.length, equals(256 + 3));
267 | expect(encoded.getRange(0, 3), orderedEquals([0xc5, 1, 0]));
268 | expect(encoded.getRange(3, encoded.length), orderedEquals(data));
269 | }
270 |
271 | void packBin32() {
272 | var data = Uint8List.fromList(List.filled(65536, 65));
273 | List encoded = serialize(data);
274 | expect(encoded.length, equals(65536 + 5));
275 | expect(encoded.getRange(0, 5), orderedEquals([0xc6, 0, 1, 0, 0]));
276 | expect(encoded.getRange(5, encoded.length), orderedEquals(data));
277 | }
278 |
279 | void packByteData() {
280 | var data = ByteData.view(Uint8List.fromList(List.filled(32, 65)).buffer);
281 | List encoded = serialize(data);
282 | expect(encoded.length, equals(34));
283 | expect(encoded.getRange(0, 2), orderedEquals([0xc4, 32]));
284 | expect(encoded.getRange(2, encoded.length),
285 | orderedEquals(data.buffer.asUint8List()));
286 | }
287 |
288 | void packStringArray() {
289 | List encoded = serialize(["one", "two", "three"]);
290 | expect(
291 | encoded,
292 | orderedEquals([
293 | 147,
294 | 163,
295 | 111,
296 | 110,
297 | 101,
298 | 163,
299 | 116,
300 | 119,
301 | 111,
302 | 165,
303 | 116,
304 | 104,
305 | 114,
306 | 101,
307 | 101
308 | ]));
309 | }
310 |
311 | void packIntToStringMap() {
312 | List encoded = serialize({1: "one", 2: "two"});
313 | expect(encoded,
314 | orderedEquals([130, 1, 163, 111, 110, 101, 2, 163, 116, 119, 111]));
315 | }
316 |
317 | // Test unpacking
318 | void unpackNull() {
319 | Uint8List data = new Uint8List.fromList([0xc0]);
320 | var value = deserialize(data);
321 | expect(value, isNull);
322 | }
323 |
324 | void unpackFalse() {
325 | Uint8List data = Uint8List.fromList([0xc2]);
326 | var value = deserialize(data);
327 | expect(value, isFalse);
328 | }
329 |
330 | void unpackTrue() {
331 | Uint8List data = Uint8List.fromList([0xc3]);
332 | var value = deserialize(data);
333 | expect(value, isTrue);
334 | }
335 |
336 | void unpackString5() {
337 | Uint8List data = new Uint8List.fromList([165, 104, 101, 108, 108, 111]);
338 | var value = deserialize(data);
339 | expect(value, isString);
340 | expect(value, equals("hello"));
341 | }
342 |
343 | void unpackString22() {
344 | Uint8List data = new Uint8List.fromList([
345 | 182,
346 | 104,
347 | 101,
348 | 108,
349 | 108,
350 | 111,
351 | 32,
352 | 116,
353 | 104,
354 | 101,
355 | 114,
356 | 101,
357 | 44,
358 | 32,
359 | 101,
360 | 118,
361 | 101,
362 | 114,
363 | 121,
364 | 111,
365 | 110,
366 | 101,
367 | 33
368 | ]);
369 | var value = deserialize(data);
370 | expect(value, isString);
371 | expect(value, equals("hello there, everyone!"));
372 | }
373 |
374 | void unpackPositiveFixInt() {
375 | Uint8List data = Uint8List.fromList([1]);
376 | var value = deserialize(data);
377 | expect(value, isInt);
378 | expect(value, equals(1));
379 | }
380 |
381 | void unpackNegativeFixInt() {
382 | Uint8List data = Uint8List.fromList([240]);
383 | var value = deserialize(data);
384 | expect(value, isInt);
385 | expect(value, equals(-16));
386 | }
387 |
388 | void unpackUint8() {
389 | Uint8List data = Uint8List.fromList([204, 128]);
390 | var value = deserialize(data);
391 | expect(value, isInt);
392 | expect(value, equals(128));
393 | }
394 |
395 | void unpackUint16() {
396 | Uint8List data = Uint8List.fromList([205, 128, 0]);
397 | var value = deserialize(data);
398 | expect(value, isInt);
399 | expect(value, equals(32768));
400 | }
401 |
402 | void unpackUint32() {
403 | Uint8List data = Uint8List.fromList([206, 128, 0, 0, 0]);
404 | var value = deserialize(data);
405 | expect(value, isInt);
406 | expect(value, equals(2147483648));
407 | }
408 |
409 | void unpackUint64() {
410 | // Dart 2 doesn't support true Uint64 without using BigInt
411 | Uint8List data =
412 | Uint8List.fromList([207, 127, 255, 255, 255, 255, 255, 255, 255]);
413 | var value = deserialize(data);
414 | expect(value, isInt);
415 | expect(value, equals(9223372036854775807));
416 | }
417 |
418 | void unpackInt8() {
419 | Uint8List data = Uint8List.fromList([208, 128]);
420 | var value = deserialize(data);
421 | expect(value, isInt);
422 | expect(value, equals(-128));
423 | }
424 |
425 | void unpackInt16() {
426 | Uint8List data = Uint8List.fromList([209, 128, 0]);
427 | var value = deserialize(data);
428 | expect(value, isInt);
429 | expect(value, equals(-32768));
430 | data = Uint8List.fromList([0xd1, 0x04, 0xd2]);
431 | print(deserialize(data));
432 | }
433 |
434 | void unpackInt32() {
435 | Uint8List data = Uint8List.fromList([210, 128, 0, 0, 0]);
436 | var value = deserialize(data);
437 | expect(value, isInt);
438 | expect(value, equals(-2147483648));
439 | }
440 |
441 | void unpackInt64() {
442 | Uint8List data = Uint8List.fromList([211, 128, 0, 0, 0, 0, 0, 0, 0]);
443 | var value = deserialize(data);
444 | expect(value, isInt);
445 | expect(value, equals(-9223372036854775808));
446 | }
447 |
448 | void unpackFloat32() {
449 | Uint8List data = Uint8List.fromList([202, 64, 72, 245, 195]);
450 | var value = deserialize(data);
451 | expect((value as double).toStringAsPrecision(3), equals('3.14'));
452 | }
453 |
454 | void unpackDouble() {
455 | Uint8List data = Uint8List.fromList(
456 | [0xcb, 0x40, 0x09, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f]);
457 | var value = deserialize(data);
458 | expect(value, equals(3.14));
459 | }
460 |
461 | void unpackString256() {
462 | Uint8List data =
463 | new Uint8List.fromList([218, 1, 0]..addAll(new List.filled(256, 65)));
464 | var value = deserialize(data);
465 | expect(value, isString);
466 | expect(
467 | value,
468 | equals(
469 | "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
470 | }
471 |
472 | void unpackStringArray() {
473 | Uint8List data = new Uint8List.fromList([
474 | 147,
475 | 163,
476 | 111,
477 | 110,
478 | 101,
479 | 163,
480 | 116,
481 | 119,
482 | 111,
483 | 165,
484 | 116,
485 | 104,
486 | 114,
487 | 101,
488 | 101
489 | ]);
490 | var value = deserialize(data);
491 | expect(value, isList);
492 | expect(value, orderedEquals(["one", "two", "three"]));
493 | }
494 |
495 | void unpackIntToStringMap() {
496 | Uint8List data = new Uint8List.fromList(
497 | [130, 1, 163, 111, 110, 101, 2, 163, 116, 119, 111]);
498 | var value = deserialize(data);
499 | expect(value, isMap);
500 | expect(value[1], equals("one"));
501 | expect(value[2], equals("two"));
502 | }
503 |
504 | void unpackSmallDateTime() {
505 | var data = [0xd7, 0xff, 0, 0, 0, 0, 0, 0, 0, 0];
506 | var value = deserialize(Uint8List.fromList(data));
507 | expect(value, equals(DateTime.fromMillisecondsSinceEpoch(0)));
508 | data = [0xd7, 0xff, 47, 175, 8, 0, 91, 124, 180, 16];
509 | value = deserialize(Uint8List.fromList(data));
510 | expect((value as DateTime).toUtc(),
511 | equals(DateTime.utc(2018, 8, 22, 0, 56, 56, 200)));
512 | }
513 |
514 | void unpackPastDate() {
515 | var data = [
516 | 0xc7,
517 | 12,
518 | 0xff,
519 | 29,
520 | 205,
521 | 101,
522 | 0,
523 | 255,
524 | 255,
525 | 255,
526 | 255,
527 | 184,
528 | 204,
529 | 121,
530 | 158
531 | ];
532 |
533 | var value = deserialize(Uint8List.fromList(data)) as DateTime;
534 | expect(value.toUtc(), equals(DateTime.utc(1932, 2, 24, 1, 53, 45, 500)));
535 |
536 | data = [
537 | 199,
538 | 12,
539 | 255,
540 | 0,
541 | 0,
542 | 0,
543 | 0,
544 | 255,
545 | 255,
546 | 255,
547 | 255,
548 | 255,
549 | 255,
550 | 248,
551 | 248
552 | ];
553 | value = deserialize(Uint8List.fromList(data));
554 | expect(value.toUtc(), equals(DateTime.utc(1969, 12, 31, 23, 30)));
555 | }
556 |
--------------------------------------------------------------------------------