├── .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 | --------------------------------------------------------------------------------