├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── review-assign-bot.yml └── workflows │ └── main.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── rust-toolchain.toml ├── rustfmt.toml ├── serde-generate-bin ├── Cargo.toml ├── README.md ├── src │ └── main.rs └── tests │ └── cli.rs ├── serde-generate ├── .gitignore ├── Cargo.toml ├── README.md ├── README.tpl ├── runtime │ ├── cpp │ │ ├── bcs.hpp │ │ ├── binary.hpp │ │ ├── bincode.hpp │ │ └── serde.hpp │ ├── csharp │ │ ├── Bcs │ │ │ ├── Bcs.csproj │ │ │ ├── BcsDeserializer.cs │ │ │ └── BcsSerializer.cs │ │ ├── Bincode │ │ │ ├── Bincode.csproj │ │ │ ├── BincodeDeserializer.cs │ │ │ └── BincodeSerializer.cs │ │ ├── Serde.Tests │ │ │ ├── Serde.Tests.csproj │ │ │ └── TestBcs.cs │ │ └── Serde │ │ │ ├── BinaryDeserializer.cs │ │ │ ├── BinarySerializer.cs │ │ │ ├── DeserializationException.cs │ │ │ ├── IDeserializer.cs │ │ │ ├── ISerializer.cs │ │ │ ├── Option.cs │ │ │ ├── Range.cs │ │ │ ├── Serde.csproj │ │ │ ├── SerializationException.cs │ │ │ ├── Unit.cs │ │ │ ├── ValueArray.cs │ │ │ ├── ValueDictionary.cs │ │ │ └── Verification.cs │ ├── dart │ │ ├── bcs │ │ │ ├── bcs.dart │ │ │ ├── bcs_deserializer.dart │ │ │ └── bcs_serializer.dart │ │ ├── bincode │ │ │ ├── bincode.dart │ │ │ ├── bincode_deserializer.dart │ │ │ └── bincode_serializer.dart │ │ ├── pubspec.yaml │ │ ├── serde │ │ │ ├── binary_deserializer.dart │ │ │ ├── binary_serializer.dart │ │ │ ├── bytes.dart │ │ │ ├── hash_utils.dart │ │ │ ├── int_128.dart │ │ │ ├── serde.dart │ │ │ ├── slice.dart │ │ │ ├── uint_128.dart │ │ │ ├── uint_64.dart │ │ │ └── unit.dart │ │ └── test │ │ │ ├── bcs_test.dart │ │ │ ├── bincode_test.dart │ │ │ └── serde_test.dart │ ├── golang │ │ ├── bcs │ │ │ ├── bcs_test.go │ │ │ ├── deserializer.go │ │ │ └── serializer.go │ │ ├── bincode │ │ │ ├── deserializer.go │ │ │ └── serializer.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── serde │ │ │ ├── binary_deserializer.go │ │ │ ├── binary_serializer.go │ │ │ ├── interfaces.go │ │ │ └── types.go │ ├── java │ │ └── com │ │ │ └── novi │ │ │ ├── bcs │ │ │ ├── BcsDeserializer.java │ │ │ ├── BcsSerializer.java │ │ │ └── BcsTest.java │ │ │ ├── bincode │ │ │ ├── BincodeDeserializer.java │ │ │ └── BincodeSerializer.java │ │ │ └── serde │ │ │ ├── ArrayLen.java │ │ │ ├── BinaryDeserializer.java │ │ │ ├── BinarySerializer.java │ │ │ ├── Bytes.java │ │ │ ├── DeserializationError.java │ │ │ ├── Deserializer.java │ │ │ ├── Int128.java │ │ │ ├── SerializationError.java │ │ │ ├── Serializer.java │ │ │ ├── Slice.java │ │ │ ├── Tuple2.java │ │ │ ├── Tuple3.java │ │ │ ├── Tuple4.java │ │ │ ├── Tuple5.java │ │ │ ├── Tuple6.java │ │ │ ├── Unit.java │ │ │ └── Unsigned.java │ ├── ocaml │ │ ├── bcs │ │ │ ├── deserialize.ml │ │ │ ├── dune │ │ │ ├── runtime.ml │ │ │ └── serialize.ml │ │ ├── bincode │ │ │ ├── deserialize.ml │ │ │ ├── dune │ │ │ ├── runtime.ml │ │ │ └── serialize.ml │ │ ├── common │ │ │ ├── deserialize.ml │ │ │ ├── dune │ │ │ ├── map.ml │ │ │ ├── misc.ml │ │ │ ├── serde.ml │ │ │ └── serialize.ml │ │ ├── dune │ │ ├── dune-project │ │ ├── ppx │ │ │ ├── dune │ │ │ └── ppx.ml │ │ ├── serde │ │ │ ├── deserialize.ml │ │ │ ├── dune │ │ │ ├── runtime.ml │ │ │ └── serialize.ml │ │ ├── test │ │ │ ├── dune │ │ │ ├── test_bcs.ml │ │ │ └── test_bincode.ml │ │ └── virtual │ │ │ ├── deserialize.mli │ │ │ ├── dune │ │ │ ├── runtime.mli │ │ │ └── serialize.mli │ ├── python │ │ ├── bcs │ │ │ ├── __init__.py │ │ │ └── test_bcs.py │ │ ├── bincode │ │ │ ├── __init__.py │ │ │ └── test_bincode.py │ │ ├── serde_binary │ │ │ └── __init__.py │ │ └── serde_types │ │ │ ├── __init__.py │ │ │ └── test_serde_types.py │ ├── swift │ │ ├── .gitignore │ │ ├── Package.swift │ │ ├── README.md │ │ ├── Sources │ │ │ └── Serde │ │ │ │ ├── BcsDeserializer.swift │ │ │ │ ├── BcsSerializer.swift │ │ │ │ ├── BinaryDeserializer.swift │ │ │ │ ├── BinarySerializer.swift │ │ │ │ ├── BincodeDeserializer.swift │ │ │ │ ├── BincodeSerializer.swift │ │ │ │ ├── Deserializer.swift │ │ │ │ ├── Indirect.swift │ │ │ │ ├── Int128.swift │ │ │ │ ├── Serializer.swift │ │ │ │ ├── Slice.swift │ │ │ │ ├── Tuple2.swift │ │ │ │ ├── Tuple3.swift │ │ │ │ ├── Tuple4.swift │ │ │ │ ├── Tuple5.swift │ │ │ │ ├── Tuple6.swift │ │ │ │ ├── UInt128.swift │ │ │ │ └── Unit.swift │ │ └── Tests │ │ │ ├── LinuxMain.swift │ │ │ └── SerdeTests │ │ │ ├── SerdeTests.swift │ │ │ └── XCTestManifests.swift │ └── typescript │ │ ├── bcs │ │ ├── bcsDeserializer.ts │ │ ├── bcsSerializer.ts │ │ └── mod.ts │ │ ├── bincode │ │ ├── bincodeDeserializer.ts │ │ ├── bincodeSerializer.ts │ │ └── mod.ts │ │ └── serde │ │ ├── binaryDeserializer.ts │ │ ├── binarySerializer.ts │ │ ├── deserializer.ts │ │ ├── mod.ts │ │ ├── serializer.ts │ │ └── types.ts ├── src │ ├── analyzer.rs │ ├── common.rs │ ├── config.rs │ ├── cpp.rs │ ├── csharp.rs │ ├── dart.rs │ ├── golang.rs │ ├── indent.rs │ ├── java.rs │ ├── lib.rs │ ├── ocaml.rs │ ├── python3.rs │ ├── rust.rs │ ├── solidity.rs │ ├── swift.rs │ └── typescript.rs └── tests │ ├── analyzer.rs │ ├── cpp_generation.rs │ ├── cpp_runtime.rs │ ├── csharp_generation.rs │ ├── csharp_runtime.rs │ ├── dart_generation.rs │ ├── dart_runtime.rs │ ├── golang_generation.rs │ ├── golang_runtime.rs │ ├── java_generation.rs │ ├── java_runtime.rs │ ├── lib.rs │ ├── ocaml_generation.rs │ ├── ocaml_runtime.rs │ ├── python_generation.rs │ ├── python_runtime.rs │ ├── rust_generation.rs │ ├── rust_runtime.rs │ ├── solidity_generation.rs │ ├── solidity_runtime.rs │ ├── swift_generation.rs │ ├── swift_runtime.rs │ ├── test_utils.rs │ ├── typescript_generation.rs │ └── typescript_runtime.rs ├── serde-name ├── Cargo.toml ├── README.md ├── README.tpl ├── src │ ├── de_adapter.rs │ ├── lib.rs │ ├── ser_adapter.rs │ └── trace.rs └── tests │ ├── de_adapter.rs │ ├── ser_adapter.rs │ └── trace.rs └── serde-reflection ├── Cargo.toml ├── README.md ├── README.tpl ├── src ├── de.rs ├── error.rs ├── format.rs ├── lib.rs ├── ser.rs ├── trace.rs └── value.rs └── tests ├── format.rs └── serde.rs /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Subscribe to changes 2 | * @ma2bd 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a bug report to help improve Serde Reflection 4 | title: "[Bug]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🐛 Bug 11 | 12 | 14 | 15 | ## To reproduce 16 | 17 | **Code snippet to reproduce** 18 | ```rust 19 | # Your code goes here 20 | # Please make sure it does not require any external dependencies 21 | ``` 22 | 23 | **Stack trace/error message** 24 | ``` 25 | // Paste the output here 26 | ``` 27 | 28 | ## Expected Behavior 29 | 30 | 31 | 32 | ## System information 33 | 34 | **Please complete the following information:** 35 | - 36 | - 37 | 38 | 39 | ## Additional context 40 | 41 | Add any other context about the problem here. 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature request" 3 | about: Suggest a new feature in Serde Reflection 4 | title: "[Feature Request]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🚀 Feature Request 11 | 12 | 13 | 14 | ## Motivation 15 | 16 | **Is your feature request related to a problem? Please describe.** 17 | 18 | 19 | 20 | ## Pitch 21 | 22 | **Describe the solution you'd like** 23 | 24 | 25 | **Describe alternatives you've considered** 26 | 27 | 28 | **Are you willing to open a pull request?** (See [CONTRIBUTING](../../CONTRIBUTING.md)) 29 | 30 | ## Additional context 31 | 32 | 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | (Write a summary for proposed changes here including the motivation.) 4 | 5 | ## Test Plan 6 | 7 | (Share your test plan here. If you changed code, please provide us with clear instructions for verifying that your changes work.) 8 | -------------------------------------------------------------------------------- /.github/review-assign-bot.yml: -------------------------------------------------------------------------------- 1 | reviewers: 2 | - ma2bd 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | __pycache__ 3 | **/*.rs.bk 4 | .class 5 | .o 6 | .idea 7 | obj/ 8 | bin/ 9 | .vs/ 10 | .vscode/ 11 | _build/ -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Please see Libra's [Code of Conduct](https://developers.libra.org/docs/policies/code-of-conduct), which describes the expectations for interactions within the community. 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to serde-reflection 2 | 3 | Development for `serde-reflection` happens in the open on GitHub. 4 | 5 | ## Pull Requests 6 | 7 | We actively welcome your pull requests. If you have a new feature in mind, please discuss the feature in an issue to 8 | ensure that your contributions will be accepted. 9 | 10 | 1. Fork the repo and create your branch from `main`. 11 | 2. If you've added code that should be tested, add tests. 12 | 3. If you've changed APIs, update the documentation. 13 | 4. Ensure the test suite passes with `cargo test --all-features`. 14 | 5. Run `cargo fmt` to automatically format your changes (CI will let you know if you missed this). 15 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 16 | 17 | ## Contributor License Agreement ("CLA") 18 | 19 | In order to accept your pull request, we need you to submit a CLA. You only need to do this once to work on any of 20 | Facebook's open source projects. 21 | 22 | Complete your CLA here: 23 | 24 | ## Issues 25 | 26 | We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be 27 | able to reproduce the issue. 28 | 29 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. In those 30 | cases, please go through the process outlined on that page and do not file a public issue. 31 | 32 | ## License 33 | 34 | By contributing to `serde-reflection`, you agree that your contributions will be dual-licensed under the terms of the 35 | [`LICENSE-MIT`](LICENSE-MIT) and [`LICENSE-APACHE`](LICENSE-APACHE) files in the root directory of this source 36 | tree. 37 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "serde-name", 4 | "serde-reflection", 5 | "serde-generate", 6 | "serde-generate-bin", 7 | ] 8 | resolver = "2" 9 | 10 | [profile.release] 11 | debug = true 12 | lto = 'thin' 13 | 14 | [profile.bench] 15 | debug = true 16 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.81.0" 3 | profile = "default" 4 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | use_field_init_shorthand = true 3 | -------------------------------------------------------------------------------- /serde-generate-bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-generate-bin" 3 | version = "0.7.0" 4 | description = "Tool to generate (de)serialization code in multiple languages" 5 | documentation = "https://docs.rs/serde-generate" 6 | repository = "https://github.com/zefchain/serde-reflection" 7 | authors = ["Mathieu Baudet "] 8 | license = "MIT OR Apache-2.0" 9 | readme = "README.md" 10 | keywords = ["data-structures", "serialization", "serde"] 11 | categories = ["encoding", "development-tools"] 12 | edition = "2021" 13 | rust-version = "1.60" 14 | 15 | [dependencies] 16 | serde-generate = { path = "../serde-generate", version = "0.31.0" } 17 | structopt = "0.3.21" 18 | serde-reflection = { path = "../serde-reflection", version = "0.5.0" } 19 | serde_yaml = "0.8.17" 20 | 21 | [dev-dependencies] 22 | tempfile = "3.2" 23 | serde = { version = "1.0.126", features = ["derive"] } 24 | serde_bytes = "0.11.5" 25 | 26 | [[bin]] 27 | name = "serdegen" 28 | path = "src/main.rs" 29 | test = false 30 | -------------------------------------------------------------------------------- /serde-generate-bin/README.md: -------------------------------------------------------------------------------- 1 | # serde-generate-bin 2 | 3 | [![serde-generate-bin on crates.io](https://img.shields.io/crates/v/serde-generate-bin)](https://crates.io/crates/serde-generate-bin) 4 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](../LICENSE-APACHE) 5 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](../LICENSE-MIT) 6 | 7 | This crate provide a binary tool `serdegen` on top of the library [`serde-generate`](https://crates.io/crates/serde-generate). 8 | 9 | See the documentation of the library for more details. 10 | -------------------------------------------------------------------------------- /serde-generate/.gitignore: -------------------------------------------------------------------------------- 1 | runtime/dart/.dart_tool/ 2 | runtime/dart/.packages 3 | runtime/dart/pubspec.lock 4 | -------------------------------------------------------------------------------- /serde-generate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-generate" 3 | version = "0.31.0" 4 | description = "Library to generate (de)serialization code in multiple languages" 5 | documentation = "https://docs.rs/serde-generate" 6 | repository = "https://github.com/zefchain/serde-reflection" 7 | authors = ["Mathieu Baudet "] 8 | license = "MIT OR Apache-2.0" 9 | readme = "README.md" 10 | keywords = ["data-structures", "serialization", "serde"] 11 | categories = ["encoding", "development-tools"] 12 | edition = "2021" 13 | rust-version = "1.60" 14 | exclude = [ 15 | # Readme template that doesn't need to be included. 16 | "README.tpl", 17 | ] 18 | autotests = false 19 | 20 | [dependencies] 21 | anyhow = "1.0.95" 22 | heck = "0.3.2" 23 | include_dir = { version = "0.6.0", optional = true } 24 | serde = { version = "1.0.126", features = ["derive"] } 25 | textwrap = "0.13.4" 26 | phf = { version = "0.10", features = ["macros"], optional = true } 27 | serde-reflection = { path = "../serde-reflection", version = "0.5.0" } 28 | 29 | [dev-dependencies] 30 | alloy-sol-types = "0.8.18" 31 | hex = "0.4.3" 32 | lazy_static = "1.4.0" 33 | regex = "1.5.5" 34 | tempfile = "3.2.0" 35 | which = "4.1.0" 36 | serde_bytes = "0.11.5" 37 | serde_yaml = "0.8.17" 38 | bincode = "1.3.3" 39 | bcs = "0.1.3" 40 | maplit = "1.0.2" 41 | revm = "19.2.0" 42 | serde_json = "1.0.115" 43 | 44 | [features] 45 | default = ["cpp", "csharp", "dart", "golang", "java", "ocaml", "python3", "rust", "swift", "typescript", "solidity"] 46 | cpp = [] 47 | csharp = ["include_dir"] 48 | dart = ["include_dir"] 49 | golang = [] 50 | java = ["include_dir"] 51 | ocaml = ["phf", "include_dir"] 52 | python3 = [] 53 | rust = [] 54 | solidity = [] 55 | swift = ["include_dir"] 56 | typescript = ["include_dir"] 57 | 58 | [[test]] 59 | name = "integration_tests" 60 | path = "tests/lib.rs" 61 | harness = true 62 | -------------------------------------------------------------------------------- /serde-generate/README.tpl: -------------------------------------------------------------------------------- 1 | # {{crate}} 2 | 3 | [![serde-generate on crates.io](https://img.shields.io/crates/v/serde-generate)](https://crates.io/crates/serde-generate) 4 | [![Documentation (latest release)](https://docs.rs/serde-generate/badge.svg)](https://docs.rs/serde-generate/) 5 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](../LICENSE-APACHE) 6 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](../LICENSE-MIT) 7 | 8 | {{readme}} 9 | 10 | ## Contributing 11 | 12 | See the [CONTRIBUTING](../CONTRIBUTING.md) file for how to help out. 13 | 14 | ## License 15 | 16 | This project is available under the terms of either the [Apache 2.0 license](../LICENSE-APACHE) or the [MIT 17 | license](../LICENSE-MIT). 18 | 19 | 25 | -------------------------------------------------------------------------------- /serde-generate/runtime/cpp/bincode.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include "binary.hpp" 10 | #include "serde.hpp" 11 | 12 | // Maximum length supported in practice (e.g. Java). 13 | constexpr size_t BINCODE_MAX_LENGTH = (1ull << 31) - 1; 14 | 15 | namespace serde { 16 | 17 | class BincodeSerializer : public BinarySerializer { 18 | using Parent = BinarySerializer; 19 | 20 | public: 21 | BincodeSerializer() : Parent(SIZE_MAX) {} 22 | 23 | void serialize_f32(float value); 24 | void serialize_f64(double value); 25 | void serialize_len(size_t value); 26 | void serialize_variant_index(uint32_t value); 27 | 28 | static constexpr bool enforce_strict_map_ordering = false; 29 | }; 30 | 31 | class BincodeDeserializer : public BinaryDeserializer { 32 | using Parent = BinaryDeserializer; 33 | 34 | public: 35 | BincodeDeserializer(std::vector bytes) 36 | : Parent(std::move(bytes), SIZE_MAX) {} 37 | 38 | float deserialize_f32(); 39 | double deserialize_f64(); 40 | size_t deserialize_len(); 41 | uint32_t deserialize_variant_index(); 42 | 43 | static constexpr bool enforce_strict_map_ordering = false; 44 | }; 45 | 46 | // Native floats and doubles must be IEEE-754 values of the expected size. 47 | static_assert(std::numeric_limits::is_iec559); 48 | static_assert(std::numeric_limits::is_iec559); 49 | static_assert(sizeof(float) == sizeof(uint32_t)); 50 | static_assert(sizeof(double) == sizeof(uint64_t)); 51 | 52 | inline void BincodeSerializer::serialize_f32(float value) { 53 | Parent::serialize_u32(*reinterpret_cast(&value)); 54 | } 55 | 56 | inline void BincodeSerializer::serialize_f64(double value) { 57 | Parent::serialize_u64(*reinterpret_cast(&value)); 58 | } 59 | 60 | inline void BincodeSerializer::serialize_len(size_t value) { 61 | if (value > BINCODE_MAX_LENGTH) { 62 | throw serde::serialization_error("Length is too large"); 63 | } 64 | Parent::serialize_u64((uint64_t)value); 65 | } 66 | 67 | inline void BincodeSerializer::serialize_variant_index(uint32_t value) { 68 | Parent::serialize_u32((uint32_t)value); 69 | } 70 | 71 | inline float BincodeDeserializer::deserialize_f32() { 72 | auto value = Parent::deserialize_u32(); 73 | return *reinterpret_cast(&value); 74 | } 75 | 76 | inline double BincodeDeserializer::deserialize_f64() { 77 | auto value = Parent::deserialize_u64(); 78 | return *reinterpret_cast(&value); 79 | } 80 | 81 | inline size_t BincodeDeserializer::deserialize_len() { 82 | auto value = (size_t)Parent::deserialize_u64(); 83 | if (value > BINCODE_MAX_LENGTH) { 84 | throw serde::deserialization_error("Length is too large"); 85 | } 86 | return (size_t)value; 87 | } 88 | 89 | inline uint32_t BincodeDeserializer::deserialize_variant_index() { 90 | return Parent::deserialize_u32(); 91 | } 92 | 93 | } // end of namespace serde 94 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Bcs/Bcs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 7.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Bcs/BcsDeserializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using Serde; 5 | using System; 6 | 7 | namespace Bcs 8 | { 9 | public class BcsDeserializer : BinaryDeserializer 10 | { 11 | public BcsDeserializer(byte[] input) : base(input, BcsSerializer.MAX_CONTAINER_DEPTH) { } 12 | public BcsDeserializer(ArraySegment input) : base(input, BcsSerializer.MAX_CONTAINER_DEPTH) { } 13 | 14 | private int deserialize_uleb128_as_u32() 15 | { 16 | long value = 0; 17 | for (int shift = 0; shift < 32; shift += 7) 18 | { 19 | byte x = reader.ReadByte(); 20 | byte digit = (byte)(x & 0x7F); 21 | value |= ((long)digit << shift); 22 | if ((value < 0) || (value > int.MaxValue)) 23 | { 24 | throw new DeserializationException("Overflow while parsing uleb128-encoded uint32 value"); 25 | } 26 | if (digit == x) 27 | { 28 | if (shift > 0 && digit == 0) 29 | { 30 | throw new DeserializationException("Invalid uleb128 number (unexpected zero digit)"); 31 | } 32 | return (int)value; 33 | } 34 | } 35 | throw new DeserializationException("Overflow while parsing uleb128-encoded uint32 value"); 36 | } 37 | 38 | public override long deserialize_len() => deserialize_uleb128_as_u32(); 39 | 40 | public override int deserialize_variant_index() => deserialize_uleb128_as_u32(); 41 | 42 | public override void check_that_key_slices_are_increasing(Range key1, Range key2) 43 | { 44 | if (Verification.CompareLexicographic(input.Slice(key1), input.Slice(key2)) >= 0) 45 | { 46 | throw new DeserializationException("Error while decoding map: keys are not serialized in the expected order"); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Bcs/BcsSerializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using Serde; 5 | using System; 6 | using System.IO; 7 | 8 | namespace Bcs 9 | { 10 | public class BcsSerializer : BinarySerializer 11 | { 12 | public const long MAX_LENGTH = int.MaxValue; 13 | public const long MAX_CONTAINER_DEPTH = 500; 14 | 15 | public BcsSerializer() : base(MAX_CONTAINER_DEPTH) { } 16 | public BcsSerializer(byte[] buffer) : base(buffer, MAX_CONTAINER_DEPTH) { } 17 | public BcsSerializer(ArraySegment buffer) : base(buffer, MAX_CONTAINER_DEPTH) { } 18 | 19 | 20 | private void serialize_u32_as_uleb128(uint value) 21 | { 22 | while ((value >> 7) != 0) 23 | { 24 | output.Write((byte)((value & 0x7f) | 0x80)); 25 | value >>= 7; 26 | } 27 | output.Write((byte)value); 28 | } 29 | 30 | public override void serialize_len(long value) 31 | { 32 | if ((value < 0) || (value > MAX_LENGTH)) 33 | { 34 | throw new SerializationException("length value doesn't fit in uint32"); 35 | } 36 | serialize_u32_as_uleb128((uint)value); 37 | } 38 | 39 | public override void serialize_variant_index(int value) => serialize_u32_as_uleb128((uint)value); 40 | 41 | static ReadOnlySpan Slice(byte[] array, (int start, int end) tup) => 42 | new ReadOnlySpan(array, tup.start, tup.end - tup.start); 43 | 44 | public override void sort_map_entries(int[] offsets) 45 | { 46 | if (offsets.Length <= 1) 47 | { 48 | return; 49 | } 50 | int offset0 = offsets[0]; 51 | var ranges = new (int start, int end)[offsets.Length]; 52 | for (int i = 0; i < offsets.Length - 1; i++) 53 | { 54 | ranges[i] = (offsets[i] - offset0, offsets[i + 1] - offset0); 55 | } 56 | ranges[ranges.Length - 1] = (offsets[offsets.Length - 1] - offset0, (int)buffer.Length - offset0); 57 | 58 | byte[] data = new byte[buffer.Length - offset0]; 59 | buffer.Seek(offset0, SeekOrigin.Begin); 60 | buffer.Read(data, 0, data.Length); 61 | 62 | Array.Sort(ranges, (l, r) => Verification.CompareLexicographic(Slice(data, l), Slice(data, r))); 63 | 64 | buffer.Seek(offset0, SeekOrigin.Begin); 65 | foreach (var range in ranges) 66 | { 67 | buffer.Write(data, range.start, range.end - range.start); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Bincode/Bincode.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 7.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Bincode/BincodeDeserializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using Serde; 5 | using System; 6 | 7 | namespace Bincode 8 | { 9 | public class BincodeDeserializer : BinaryDeserializer 10 | { 11 | public BincodeDeserializer(byte[] input) : base(input, long.MaxValue) { } 12 | public BincodeDeserializer(ArraySegment input) : base(input, long.MaxValue) { } 13 | 14 | public override long deserialize_len() 15 | { 16 | long value = reader.ReadInt64(); 17 | if (value < 0 || value > int.MaxValue) 18 | { 19 | throw new DeserializationException("Incorrect length value"); 20 | } 21 | return value; 22 | } 23 | 24 | public override int deserialize_variant_index() => reader.ReadInt32(); 25 | 26 | public override void check_that_key_slices_are_increasing(Range key1, Range key2) 27 | { 28 | // Not required by the format. 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Bincode/BincodeSerializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using Serde; 5 | using System; 6 | 7 | namespace Bincode 8 | { 9 | public class BincodeSerializer : BinarySerializer 10 | { 11 | public BincodeSerializer() : base(long.MaxValue) { } 12 | public BincodeSerializer(byte[] buffer) : base(buffer, long.MaxValue) { } 13 | public BincodeSerializer(ArraySegment buffer) : base(buffer, long.MaxValue) { } 14 | 15 | public override void serialize_len(long value) => output.Write(value); 16 | 17 | public override void serialize_variant_index(int value) => output.Write(value); 18 | 19 | public override void sort_map_entries(int[] offsets) 20 | { 21 | // Not required by the format. 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde.Tests/Serde.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6 5 | false 6 | 7.2 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde.Tests/TestBcs.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | using System.Numerics; 6 | using NUnit.Framework; 7 | using Bcs; 8 | 9 | namespace Serde.Tests 10 | { 11 | [TestFixture] 12 | public class TestBcs 13 | { 14 | [Test] 15 | public void TestSerializeU128() 16 | { 17 | BcsSerializer serializer = new BcsSerializer(); 18 | serializer.serialize_u128((BigInteger.One << 128) - 1); 19 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }); 20 | 21 | serializer = new BcsSerializer(); 22 | serializer.serialize_u128(BigInteger.One); 23 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); 24 | 25 | serializer = new BcsSerializer(); 26 | serializer.serialize_u128(BigInteger.Zero); 27 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); 28 | 29 | Assert.Throws(() => serializer.serialize_u128(BigInteger.MinusOne)); 30 | 31 | Assert.Throws(() => serializer.serialize_u128((BigInteger.One << 128) + 1)); 32 | } 33 | 34 | [Test] 35 | public void TestSerializeI128() 36 | { 37 | BcsSerializer serializer = new BcsSerializer(); 38 | serializer.serialize_i128(BigInteger.MinusOne); 39 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }); 40 | 41 | serializer = new BcsSerializer(); 42 | serializer.serialize_i128(BigInteger.One); 43 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); 44 | 45 | serializer = new BcsSerializer(); 46 | serializer.serialize_i128((BigInteger.One << 127) - 1); 47 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127 }); 48 | 49 | serializer = new BcsSerializer(); 50 | serializer.serialize_i128(-(BigInteger.One << 127)); 51 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80 }); 52 | 53 | Assert.Throws(() => serializer.serialize_i128(BigInteger.One << 127)); 54 | 55 | Assert.Throws(() => serializer.serialize_i128(-((BigInteger.One << 127) + 1))); 56 | } 57 | 58 | [Test] 59 | public void TestSliceOrdering() 60 | { 61 | BcsSerializer serializer = new BcsSerializer(); 62 | serializer.serialize_u8(255); 63 | serializer.serialize_u32(1); 64 | serializer.serialize_u32(1); 65 | serializer.serialize_u32(2); 66 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 255, /**/ 1, /**/ 0, 0, /**/ 0, 1, 0, /**/ 0, /**/ 0, /**/ 2, 0, 0, 0 }); 67 | 68 | int[] offsets = { 1, 2, 4, 7, 8, 9 }; 69 | serializer.sort_map_entries(offsets); 70 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 255, /**/ 0, /**/ 0, /**/ 0, 0, /**/ 0, 1, 0, /**/ 1, /**/ 2, 0, 0, 0 }); 71 | } 72 | 73 | [Test] 74 | public void TestULEB128Encoding() 75 | { 76 | BcsSerializer serializer = new BcsSerializer(); 77 | serializer.serialize_len(0); 78 | serializer.serialize_len(1); 79 | serializer.serialize_len(127); 80 | serializer.serialize_len(128); 81 | serializer.serialize_len(3000); 82 | CollectionAssert.AreEqual(serializer.get_bytes(), new byte[] { 0, 1, 127, 128, 1, 184, 23 }); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/DeserializationException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | 6 | namespace Serde 7 | { 8 | public sealed class DeserializationException : Exception 9 | { 10 | public DeserializationException(string message) : base(message) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/IDeserializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System.Numerics; 5 | 6 | namespace Serde 7 | { 8 | public interface IDeserializer 9 | { 10 | string deserialize_str(); 11 | 12 | ValueArray deserialize_bytes(); 13 | 14 | bool deserialize_bool(); 15 | 16 | Unit deserialize_unit(); 17 | 18 | char deserialize_char(); 19 | 20 | float deserialize_f32(); 21 | 22 | double deserialize_f64(); 23 | 24 | byte deserialize_u8(); 25 | 26 | ushort deserialize_u16(); 27 | 28 | uint deserialize_u32(); 29 | 30 | ulong deserialize_u64(); 31 | 32 | BigInteger deserialize_u128(); 33 | 34 | sbyte deserialize_i8(); 35 | 36 | short deserialize_i16(); 37 | 38 | int deserialize_i32(); 39 | 40 | long deserialize_i64(); 41 | 42 | BigInteger deserialize_i128(); 43 | 44 | long deserialize_len(); 45 | 46 | int deserialize_variant_index(); 47 | 48 | bool deserialize_option_tag(); 49 | 50 | void increase_container_depth(); 51 | 52 | void decrease_container_depth(); 53 | 54 | int get_buffer_offset(); 55 | 56 | void check_that_key_slices_are_increasing(Range key1, Range key2); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/ISerializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System.Numerics; 5 | 6 | namespace Serde 7 | { 8 | public interface ISerializer 9 | { 10 | void serialize_str(string value); 11 | 12 | void serialize_bytes(ValueArray value); 13 | 14 | void serialize_bool(bool value); 15 | 16 | void serialize_unit(Unit value); 17 | 18 | void serialize_char(char value); 19 | 20 | void serialize_f32(float value); 21 | 22 | void serialize_f64(double value); 23 | 24 | void serialize_u8(byte value); 25 | 26 | void serialize_u16(ushort value); 27 | 28 | void serialize_u32(uint value); 29 | 30 | void serialize_u64(ulong value); 31 | 32 | void serialize_u128(BigInteger value); 33 | 34 | void serialize_i8(sbyte value); 35 | 36 | void serialize_i16(short value); 37 | 38 | void serialize_i32(int value); 39 | 40 | void serialize_i64(long value); 41 | 42 | void serialize_i128(BigInteger value); 43 | 44 | void serialize_len(long value); 45 | 46 | void serialize_variant_index(int value); 47 | 48 | void serialize_option_tag(bool value); 49 | 50 | void increase_container_depth(); 51 | 52 | void decrease_container_depth(); 53 | 54 | int get_buffer_offset(); 55 | 56 | void sort_map_entries(int[] offsets); 57 | 58 | byte[] get_bytes(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/Option.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Serde 8 | { 9 | public readonly struct Option : IEquatable> where T : IEquatable 10 | { 11 | public static Option None => default; 12 | public static Option Some(T value) 13 | { 14 | if (value == null) throw new ArgumentNullException(nameof(value)); 15 | return new Option(value); 16 | } 17 | 18 | readonly bool isSome; 19 | readonly T value; 20 | 21 | Option(T val) 22 | { 23 | isSome = val != null; 24 | value = val; 25 | } 26 | 27 | public bool IsSome(out T value) 28 | { 29 | value = this.value; 30 | return isSome; 31 | } 32 | 33 | public override bool Equals(object obj) => obj is Option option && Equals(option); 34 | 35 | public bool Equals(Option other) 36 | { 37 | if (isSome != other.isSome) return false; 38 | if (!isSome) return true; 39 | return value.Equals(other.value); 40 | } 41 | 42 | public override int GetHashCode() 43 | { 44 | var hashCode = -934799437; 45 | hashCode = hashCode * -1521134295 + isSome.GetHashCode(); 46 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(value); 47 | return hashCode; 48 | } 49 | 50 | public static bool operator ==(Option left, Option right) => Equals(left, right); 51 | 52 | public static bool operator !=(Option left, Option right) => !Equals(left, right); 53 | } 54 | 55 | public static class OptionExtensions 56 | { 57 | public static U Match(this Option option, Func onIsSome, Func onIsNone) 58 | where T : IEquatable where U : IEquatable => 59 | option.IsSome(out var value) ? onIsSome(value) : onIsNone(); 60 | 61 | public static Option Bind(this Option option, Func> binder) 62 | where T : IEquatable where U : IEquatable => 63 | option.Match(onIsSome: binder, onIsNone: () => Option.None); 64 | 65 | public static Option Map(this Option option, Func mapper) 66 | where T : IEquatable where U : IEquatable => 67 | option.Bind(value => Option.Some(mapper(value))); 68 | 69 | public static Option Filter(this Option option, Predicate predicate) 70 | where T : IEquatable => 71 | option.Bind(value => predicate(value) ? option : Option.None); 72 | 73 | public static T DefaultValue(this Option option, T defaultValue) 74 | where T : IEquatable => 75 | option.Match(onIsSome: value => value, onIsNone: () => defaultValue); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/Range.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | 6 | namespace Serde 7 | { 8 | public struct Range : IEquatable 9 | { 10 | public int Start { get; } 11 | public int End { get; } 12 | public int Length => End - Start; 13 | 14 | public Range(int start, int end) 15 | { 16 | Start = start; 17 | End = end; 18 | } 19 | 20 | public override int GetHashCode() 21 | { 22 | var hashCode = -1676728671; 23 | hashCode = hashCode * -1521134295 + Start.GetHashCode(); 24 | hashCode = hashCode * -1521134295 + End.GetHashCode(); 25 | return hashCode; 26 | } 27 | 28 | public override bool Equals(object obj) => obj is Range range && Equals(range); 29 | 30 | public bool Equals(Range other) => Start == other.Start && End == other.End; 31 | 32 | public static bool operator ==(Range range1, Range range2) => range1.Equals(range2); 33 | 34 | public static bool operator !=(Range range1, Range range2) => !(range1 == range2); 35 | } 36 | 37 | public static class RangeExtensions 38 | { 39 | public static Span Slice(this T[] array, Range range) => 40 | new Span(array, range.Start, range.Length); 41 | public static Span Slice(this ArraySegment array, Range range) => 42 | new ArraySegment(array.Array, array.Offset + range.Start, range.Length); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/Serde.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 7.2 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/SerializationException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | 6 | namespace Serde 7 | { 8 | public sealed class SerializationException : Exception 9 | { 10 | public SerializationException(string message) : base(message) { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/Unit.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | 6 | namespace Serde 7 | { 8 | /// 9 | /// Analogous to Rust's Unit type `()`. 10 | /// 11 | public readonly struct Unit : IEquatable 12 | { 13 | public override bool Equals(object obj) => obj is Unit unit; 14 | 15 | public bool Equals(Unit other) => true; 16 | 17 | public static bool operator==(Unit l, Unit r) => true; 18 | 19 | public static bool operator!=(Unit l, Unit r) => false; 20 | 21 | public override int GetHashCode() => 793253941; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/ValueArray.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace Serde 10 | { 11 | /// 12 | /// Immutable wrapper class around T[]. Implements value semantics for 13 | /// and . 14 | /// 15 | public class ValueArray : IEquatable>, IReadOnlyList, IStructuralEquatable 16 | where T: IEquatable 17 | { 18 | private readonly T[] array; 19 | private int? hashCode; 20 | 21 | public int Count => array.Length; 22 | 23 | public T this[int index] => array[index]; 24 | 25 | public ValueArray(T[] data) { 26 | array = data ?? throw new ArgumentNullException(nameof(data)); 27 | hashCode = null; 28 | } 29 | 30 | public T[] ToArray() => array.ToArray(); 31 | 32 | public static implicit operator ReadOnlySpan(ValueArray bytes) => bytes.array; 33 | 34 | public ReadOnlySpan AsReadOnlySpan() => array; 35 | 36 | public override bool Equals(object obj) => obj is ValueArray bytes && Equals(bytes); 37 | 38 | public bool Equals(ValueArray other) { 39 | if (other == null) return false; 40 | if (ReferenceEquals(this, other)) return true; 41 | if (Count != other.Count) return false; 42 | for (int i = 0; i < Count; i++) 43 | if (!array[i].Equals(other[i])) return false; 44 | return true; 45 | } 46 | 47 | public static bool operator ==(ValueArray left, ValueArray right) => Equals(left, right); 48 | 49 | public static bool operator !=(ValueArray left, ValueArray right) => !Equals(left, right); 50 | 51 | public IEnumerator GetEnumerator() => ((IEnumerable)array).GetEnumerator(); 52 | 53 | IEnumerator IEnumerable.GetEnumerator() => array.GetEnumerator(); 54 | 55 | public override int GetHashCode() 56 | { 57 | unchecked 58 | { 59 | if (hashCode.HasValue) return hashCode.Value; 60 | int code = 1849862467; 61 | foreach (T elem in array) 62 | code = code * 31 + elem.GetHashCode(); 63 | hashCode = code; 64 | return code; 65 | } 66 | } 67 | 68 | public bool Equals(object other, IEqualityComparer comparer) 69 | { 70 | return ((IStructuralEquatable)array).Equals(other, comparer); 71 | } 72 | 73 | public int GetHashCode(IEqualityComparer comparer) 74 | { 75 | return ((IStructuralEquatable)array).GetHashCode(comparer); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/ValueDictionary.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | 8 | namespace Serde 9 | { 10 | /// 11 | /// Immutable wrapper class around . Implements value semantics for 12 | /// and . 13 | /// 14 | public class ValueDictionary : IEquatable>, IReadOnlyDictionary 15 | where K: IEquatable 16 | where V: IEquatable 17 | { 18 | private readonly Dictionary dict; 19 | private int? hashCode; 20 | 21 | public int Count => dict.Count; 22 | 23 | public IEnumerable Keys => dict.Keys; 24 | 25 | public IEnumerable Values => dict.Values; 26 | 27 | public V this[K key] => dict[key]; 28 | 29 | public ValueDictionary(Dictionary dictionary) { 30 | dict = dictionary ?? throw new ArgumentNullException(nameof(dictionary)); 31 | hashCode = null; 32 | } 33 | 34 | public bool ContainsKey(K key) => dict.ContainsKey(key); 35 | 36 | public bool TryGetValue(K key, out V value) => dict.TryGetValue(key, out value); 37 | 38 | IEnumerator> IEnumerable>.GetEnumerator() => dict.GetEnumerator(); 39 | 40 | public IEnumerator GetEnumerator() => ((IEnumerable)dict).GetEnumerator(); 41 | 42 | public override bool Equals(object obj) => obj is ValueDictionary bytes && Equals(bytes); 43 | 44 | public bool Equals(ValueDictionary other) { 45 | if (other == null) return false; 46 | if (Count != other.Count) return false; 47 | foreach (var key in Keys) 48 | { 49 | if (!other.ContainsKey(key)) return false; 50 | if (!dict[key].Equals(other[key])) return false; 51 | } 52 | return true; 53 | } 54 | 55 | public static bool operator ==(ValueDictionary left, ValueDictionary right) => Equals(left, right); 56 | 57 | public static bool operator !=(ValueDictionary left, ValueDictionary right) => !Equals(left, right); 58 | 59 | 60 | public override int GetHashCode() 61 | { 62 | unchecked 63 | { 64 | if (hashCode.HasValue) return hashCode.Value; 65 | int code = 45053; 66 | foreach (var pair in dict) 67 | { 68 | code = code * 31 + pair.Key.GetHashCode(); 69 | code = code * 31 + pair.Value.GetHashCode(); 70 | } 71 | hashCode = code; 72 | return code; 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /serde-generate/runtime/csharp/Serde/Verification.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | using System; 5 | 6 | namespace Serde 7 | { 8 | public static class Verification 9 | { 10 | /// 11 | /// Returns an integer corresponding to the lexicographic ordering of the two input byte strings. 12 | /// 13 | public static int CompareLexicographic(ReadOnlySpan key1, ReadOnlySpan key2) 14 | { 15 | for (int i = 0; i < key1.Length; i++) 16 | { 17 | var byte1 = key1[i]; 18 | if (i >= key2.Length) 19 | { 20 | return 1; 21 | } 22 | var byte2 = key2[i]; 23 | if (byte1 > byte2) 24 | { 25 | return 1; 26 | } 27 | if (byte1 < byte2) 28 | { 29 | return -1; 30 | } 31 | } 32 | if (key2.Length > key1.Length) 33 | { 34 | return -1; 35 | } 36 | return 0; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/bcs/bcs.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | library bcs; 5 | 6 | import 'dart:typed_data'; 7 | import '../serde/serde.dart'; 8 | 9 | part 'bcs_deserializer.dart'; 10 | part 'bcs_serializer.dart'; 11 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/bcs/bcs_deserializer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'bcs.dart'; 5 | 6 | // Maximum length allowed for sequences (vectors, bytes, strings) and maps. 7 | const maxSequenceLength = (1 << 31) - 1; 8 | 9 | // Maximum number of nested structs and enum variants. 10 | const maxContainerDepth = 500; 11 | 12 | class BcsDeserializer extends BinaryDeserializer { 13 | BcsDeserializer(Uint8List input) 14 | : super( 15 | input: input, 16 | containerDepthBudget: maxContainerDepth, 17 | ); 18 | 19 | int deserializeUleb128AsUint32() { 20 | var value = 0; 21 | for (var shift = 0; shift < 32; shift += 7) { 22 | final x = super.deserializeUint8(); 23 | final digit = (x & 0x7F); 24 | value = value | (digit << shift); 25 | if (value > maxInt) { 26 | throw Exception('Overflow while parsing uleb128-encoded uint32 value'); 27 | } 28 | if (digit == x) { 29 | if (shift > 0 && digit == 0) { 30 | throw Exception('Invalid uleb128 number (unexpected zero digit)'); 31 | } 32 | return value; 33 | } 34 | } 35 | throw Exception('Overflow while parsing uleb128-encoded uint32 value'); 36 | } 37 | 38 | @override 39 | int deserializeLength() { 40 | final length = deserializeUleb128AsUint32(); 41 | if (length > maxSequenceLength) { 42 | throw Exception("length is too large"); 43 | } 44 | return length; 45 | } 46 | 47 | @override 48 | int deserializeVariantIndex() { 49 | return deserializeUleb128AsUint32(); 50 | } 51 | 52 | @override 53 | void checkThatKeySlicesAreIncreasing(Slice key1, Slice key2) { 54 | if (Slice.compareBytes(input.buffer.asUint8List(), key1, key2) >= 0) { 55 | throw Exception( 56 | "Error while decoding map: keys are not serialized in the expected order"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/bcs/bcs_serializer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'bcs.dart'; 5 | 6 | class BcsSerializer extends BinarySerializer { 7 | BcsSerializer() 8 | : super( 9 | containerDepthBudget: maxContainerDepth, 10 | ); 11 | 12 | void serializeUint32AsUleb128(int value) { 13 | while (((value & 0xFFFFFFFF) >> 7) != 0) { 14 | output.add((value & 0x7f) | 0x80); 15 | value = (value & 0xFFFFFFFF) >> 7; 16 | } 17 | output.add(value); 18 | } 19 | 20 | @override 21 | void serializeLength(int value) { 22 | serializeUint32AsUleb128(value); 23 | } 24 | 25 | @override 26 | void serializeVariantIndex(int value) { 27 | serializeUint32AsUleb128(value); 28 | } 29 | 30 | @override 31 | void sortMapEntries(List offsets) { 32 | if (offsets.isEmpty) { 33 | return; 34 | } 35 | 36 | // Prepare a list of slices 37 | final data = Uint8List.fromList(output); 38 | List slices = []; 39 | 40 | // Collect slices 41 | for (int i = 0; i < offsets.length; i++) { 42 | final int startOffset = offsets[i]; 43 | final int cutOffset; 44 | if (i + 1 < offsets.length) { 45 | cutOffset = offsets[i + 1]; 46 | } else { 47 | cutOffset = data.length; 48 | } 49 | slices.add(data.sublist(startOffset, cutOffset)); 50 | } 51 | 52 | // Sort slices using lexicographic comparison 53 | slices.sort((a, b) { 54 | for (int i = 0; i < a.length && i < b.length; i++) { 55 | if (a[i] != b[i]) { 56 | return a[i].compareTo(b[i]); 57 | } 58 | } 59 | return a.length.compareTo(b.length); 60 | }); 61 | 62 | // Write sorted slices back to output 63 | int writePosition = offsets[0]; 64 | for (final slice in slices) { 65 | output.setRange(writePosition, writePosition + slice.length, slice); 66 | writePosition += slice.length; 67 | } 68 | 69 | // Ensure the final length is correct 70 | assert(offsets.last == output.length); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/bincode/bincode.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | library bincode; 5 | 6 | import 'dart:typed_data'; 7 | import '../serde/serde.dart'; 8 | 9 | part 'bincode_deserializer.dart'; 10 | part 'bincode_serializer.dart'; 11 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/bincode/bincode_deserializer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'bincode.dart'; 5 | 6 | // Maximum number of nested structs and enum variants. 7 | const maxContainerDepth = (1 << 31) - 1; 8 | 9 | class BincodeDeserializer extends BinaryDeserializer { 10 | BincodeDeserializer(Uint8List input) 11 | : super(input: input, containerDepthBudget: maxContainerDepth); 12 | 13 | @override 14 | int deserializeLength() { 15 | return deserializeUint64().toInt(); 16 | } 17 | 18 | @override 19 | int deserializeVariantIndex() { 20 | return deserializeUint32(); 21 | } 22 | 23 | @override 24 | void checkThatKeySlicesAreIncreasing(Slice key1, Slice key2) { 25 | // Not required by the format. 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/bincode/bincode_serializer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'bincode.dart'; 5 | 6 | class BincodeSerializer extends BinarySerializer { 7 | BincodeSerializer() 8 | : super( 9 | containerDepthBudget: maxContainerDepth, 10 | ); 11 | 12 | @override 13 | void serializeLength(int value) { 14 | serializeUint64(Uint64(BigInt.from(value))); 15 | } 16 | 17 | @override 18 | void serializeVariantIndex(int value) { 19 | serializeUint32(value); 20 | } 21 | 22 | @override 23 | void sortMapEntries(List offsets) { 24 | // Not required by the format. 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: serde 2 | 3 | environment: 4 | sdk: '>=3.0.0 <4.0.0' 5 | 6 | dependencies: 7 | meta: ^1.0.0 8 | tuple: ^2.0.0 9 | dev_dependencies: 10 | test: ^1.19.3 11 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/bytes.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | /// Immutable wrapper class around byte[]. 7 | /// Enforces value-semantice for `equals` and `hashCode`. 8 | @immutable 9 | class Bytes { 10 | const Bytes(this.content); 11 | 12 | final Uint8List content; 13 | 14 | @override 15 | bool operator ==(Object other) { 16 | if (identical(this, other)) return true; 17 | if (other.runtimeType != runtimeType) return false; 18 | 19 | return other is Bytes && listEquals(content, other.content); 20 | } 21 | 22 | @override 23 | int get hashCode => Object.hashAll(content); 24 | } 25 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/hash_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | const maxInt = 4294967296; 7 | 8 | bool listEquals(List? a, List? b) { 9 | if (a == null) return b == null; 10 | if (b == null || a.length != b.length) return false; 11 | if (identical(a, b)) return true; 12 | for (int index = 0; index < a.length; index += 1) { 13 | if (!_elementEquals(a[index], b[index])) return false; 14 | } 15 | return true; 16 | } 17 | 18 | bool mapEquals(Map? a, Map? b) { 19 | if (a == null) return b == null; 20 | if (b == null || a.length != b.length) return false; 21 | if (identical(a, b)) return true; 22 | for (final T key in a.keys) { 23 | if (!a.containsKey(key) || !_elementEquals(a[key], b[key])) { 24 | return false; 25 | } 26 | } 27 | return true; 28 | } 29 | 30 | bool _elementEquals(T? a, T? b) { 31 | if (a is List && b is List) { 32 | return listEquals(a, b); 33 | } else if (a is Map && b is Map) { 34 | return mapEquals(a, b); 35 | } 36 | return a == b; 37 | } 38 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/int_128.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | @immutable 7 | class Int128 { 8 | const Int128(this.high, this.low); 9 | 10 | factory Int128.parse(String num, {int? radix}) { 11 | return Int128.fromBigInt(BigInt.parse(num, radix: radix)); 12 | } 13 | 14 | factory Int128.fromBigInt(BigInt num) { 15 | final input = num.toSigned(128); 16 | final high = (input >> 64).toSigned(64); 17 | final low = (input & BigInt.parse('0xFFFFFFFFFFFFFFFF')).toSigned(64); 18 | return Int128(high, low); 19 | } 20 | 21 | final BigInt high; 22 | final BigInt low; 23 | 24 | @override 25 | bool operator ==(Object other) { 26 | if (identical(this, other)) return true; 27 | if (other.runtimeType != runtimeType) return false; 28 | 29 | return other is Int128 && 30 | high.toSigned(64) == other.high.toSigned(64) && 31 | low.toUnsigned(64) == other.low.toUnsigned(64); 32 | } 33 | 34 | @override 35 | int get hashCode => Object.hash( 36 | high, 37 | low, 38 | ); 39 | 40 | @override 41 | String toString() { 42 | return toBigInt().toString(); 43 | } 44 | 45 | BigInt toBigInt() => (high.toSigned(64) << 64) + low.toUnsigned(64); 46 | } 47 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/serde.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | library serde; 5 | 6 | import 'dart:convert' show utf8; 7 | import 'dart:typed_data'; 8 | 9 | import 'package:meta/meta.dart'; 10 | 11 | part 'binary_deserializer.dart'; 12 | part 'binary_serializer.dart'; 13 | part 'bytes.dart'; 14 | part 'hash_utils.dart'; 15 | part 'int_128.dart'; 16 | part 'slice.dart'; 17 | part 'uint_128.dart'; 18 | part 'uint_64.dart'; 19 | part 'unit.dart'; 20 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/slice.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | @immutable 7 | class Slice { 8 | const Slice(this.start, this.end); 9 | 10 | final int start; 11 | final int end; 12 | 13 | // Lexicographic comparison between the (unsigned!) bytes referenced by `slice1` and `slice2` 14 | // into `content`. 15 | static int compareBytes(Uint8List content, Slice slice1, Slice slice2) { 16 | final start1 = slice1.start; 17 | final end1 = slice1.end; 18 | final start2 = slice2.start; 19 | final end2 = slice2.end; 20 | final il = end1 - start1; 21 | 22 | for (var i = 0; i < il; i++) { 23 | final byte1 = content[start1 + i] & 0xFF; 24 | if (start2 + i >= end2) { 25 | return 1; 26 | } 27 | final byte2 = content[start2 + i] & 0xFF; 28 | if (byte1 > byte2) { 29 | return 1; 30 | } 31 | if (byte1 < byte2) { 32 | return -1; 33 | } 34 | } 35 | 36 | if (end2 - start2 > end1 - start1) { 37 | return -1; 38 | } 39 | 40 | return 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/uint_128.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | /// A Dart type to represent the Rust u128 type. 7 | @immutable 8 | class Uint128 { 9 | const Uint128(this.high, this.low); 10 | 11 | factory Uint128.parse(String num, {int? radix}) { 12 | return Uint128.fromBigInt(BigInt.parse(num, radix: radix)); 13 | } 14 | 15 | factory Uint128.fromBigInt(BigInt num) { 16 | final input = num.toUnsigned(128); 17 | final high = (input >> 64).toUnsigned(64); 18 | final low = (input & BigInt.parse('0xFFFFFFFFFFFFFFFF')).toUnsigned(64); 19 | return Uint128(high, low); 20 | } 21 | 22 | final BigInt high; 23 | final BigInt low; 24 | 25 | @override 26 | bool operator ==(Object other) { 27 | if (identical(this, other)) return true; 28 | if (other.runtimeType != runtimeType) return false; 29 | 30 | return other is Uint128 && high == other.high && low == other.low; 31 | } 32 | 33 | @override 34 | int get hashCode => Object.hash( 35 | high, 36 | low, 37 | ); 38 | 39 | @override 40 | String toString() { 41 | return toBigInt().toString(); 42 | } 43 | 44 | BigInt toBigInt() => (high.toUnsigned(64) << 64) + low.toUnsigned(64); 45 | } 46 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/uint_64.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | /// A Dart type to represent the Rust u64 type. 7 | @immutable 8 | class Uint64 { 9 | const Uint64(this._high); 10 | 11 | factory Uint64.parse(String num, {int? radix}) { 12 | return Uint64.fromBigInt(BigInt.parse(num, radix: radix)); 13 | } 14 | 15 | factory Uint64.fromBigInt(BigInt num) { 16 | return Uint64(num.toUnsigned(64)); 17 | } 18 | 19 | final BigInt _high; 20 | 21 | @override 22 | bool operator ==(Object other) { 23 | if (identical(this, other)) return true; 24 | if (other.runtimeType != runtimeType) return false; 25 | 26 | return other is Uint64 && _high == other._high; 27 | } 28 | 29 | @override 30 | int get hashCode => _high.hashCode; 31 | 32 | @override 33 | String toString() { 34 | return toBigInt().toString(); 35 | } 36 | 37 | BigInt toBigInt() => _high; 38 | 39 | // Warning: If the number does not fit, clamps to the max (or min) integer. 40 | int toInt() => _high.toInt(); 41 | } 42 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/serde/unit.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | part of 'serde.dart'; 5 | 6 | @immutable 7 | class Unit { 8 | const Unit(); 9 | 10 | @override 11 | bool operator ==(Object other) { 12 | if (identical(this, other)) return true; 13 | if (other.runtimeType != runtimeType) return false; 14 | 15 | return other is Unit; 16 | } 17 | 18 | @override 19 | int get hashCode => 7; 20 | } 21 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/test/bcs_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import 'dart:typed_data'; 5 | import 'package:test/test.dart'; 6 | import '../bcs/bcs.dart'; 7 | 8 | void main() { 9 | test('serializeUint32', () { 10 | BcsSerializer serializer = BcsSerializer(); 11 | serializer.serializeUint32(1); 12 | expect(serializer.bytes, Uint8List.fromList([1, 0, 0, 0])); 13 | }); 14 | 15 | test('deserializeUint32', () { 16 | BcsDeserializer serializer = 17 | BcsDeserializer(Uint8List.fromList([1, 0, 0, 0])); 18 | int result = serializer.deserializeUint32(); 19 | expect(result, 1); 20 | }); 21 | 22 | test('slice', () { 23 | BcsSerializer serializer = BcsSerializer(); 24 | serializer.serializeUint8(-1); 25 | serializer.serializeUint32(1); 26 | serializer.serializeUint32(1); 27 | serializer.serializeUint32(2); 28 | expect( 29 | serializer.bytes, 30 | Uint8List.fromList([ 31 | -1, 32 | /**/ 1, 33 | /**/ 0, 34 | 0, 35 | /**/ 0, 36 | 1, 37 | 0, 38 | /**/ 0, 39 | /**/ 0, 40 | /**/ 2, 41 | 0, 42 | 0, 43 | 0 44 | ])); 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/test/bincode_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import 'dart:typed_data'; 5 | import 'package:test/test.dart'; 6 | import '../bincode/bincode.dart'; 7 | 8 | void main() { 9 | test('serializeUint32', () { 10 | BincodeSerializer serializer = BincodeSerializer(); 11 | serializer.serializeUint32(1); 12 | expect(serializer.bytes, Uint8List.fromList([1, 0, 0, 0])); 13 | }); 14 | 15 | test('deserializeUint32', () { 16 | BincodeDeserializer serializer = 17 | BincodeDeserializer(Uint8List.fromList([1, 0, 0, 0])); 18 | int result = serializer.deserializeUint32(); 19 | expect(result, 1); 20 | }); 21 | 22 | test('slice', () { 23 | BincodeSerializer serializer = BincodeSerializer(); 24 | serializer.serializeUint8(-1); 25 | serializer.serializeUint32(1); 26 | serializer.serializeUint32(1); 27 | serializer.serializeUint32(2); 28 | expect( 29 | serializer.bytes, 30 | Uint8List.fromList([ 31 | -1, 32 | /**/ 1, 33 | /**/ 0, 34 | 0, 35 | /**/ 0, 36 | 1, 37 | 0, 38 | /**/ 0, 39 | /**/ 0, 40 | /**/ 2, 41 | 0, 42 | 0, 43 | 0 44 | ])); 45 | }); 46 | 47 | test('serializeUint8', () { 48 | final serializer = BincodeSerializer(); 49 | serializer.serializeUint8(255); 50 | final deserializer = BincodeDeserializer(serializer.bytes); 51 | expect(deserializer.deserializeUint8(), 255); 52 | expect(() => serializer.serializeUint8(256), throwsException); 53 | }); 54 | 55 | test('serializeUint16', () { 56 | final serializer = BincodeSerializer(); 57 | serializer.serializeUint16(65535); 58 | final deserializer = BincodeDeserializer(serializer.bytes); 59 | expect(deserializer.deserializeUint16(), 65535); 60 | expect(() => serializer.serializeUint16(65536), throwsException); 61 | }); 62 | 63 | test('serializeUint32', () { 64 | final serializer = BincodeSerializer(); 65 | serializer.serializeUint32(4294967295); 66 | final deserializer = BincodeDeserializer(serializer.bytes); 67 | expect(deserializer.deserializeUint32(), 4294967295); 68 | expect(() => serializer.serializeUint32(4294967296), throwsException); 69 | }); 70 | 71 | test('serializeInt8', () { 72 | final serializer = BincodeSerializer(); 73 | serializer.serializeInt8(127); 74 | final deserializer = BincodeDeserializer(serializer.bytes); 75 | expect(deserializer.deserializeInt8(), 127); 76 | expect(() => serializer.serializeInt8(128), throwsException); 77 | expect(() => serializer.serializeInt8(-129), throwsException); 78 | }); 79 | 80 | test('serializeInt16', () { 81 | final serializer = BincodeSerializer(); 82 | serializer.serializeInt16(32767); 83 | final deserializer = BincodeDeserializer(serializer.bytes); 84 | expect(deserializer.deserializeInt16(), 32767); 85 | expect(() => serializer.serializeInt16(32768), throwsException); 86 | expect(() => serializer.serializeInt16(-32769), throwsException); 87 | }); 88 | 89 | test('serializeInt32', () { 90 | final serializer = BincodeSerializer(); 91 | serializer.serializeInt32(2147483647); 92 | final deserializer = BincodeDeserializer(serializer.bytes); 93 | expect(deserializer.deserializeInt32(), 2147483647); 94 | expect(() => serializer.serializeInt32(2147483648), throwsException); 95 | expect(() => serializer.serializeInt32(-2147483649), throwsException); 96 | }); 97 | 98 | test('serializeString', () { 99 | final serializer = BincodeSerializer(); 100 | serializer.serializeString('dummy text / ダミーテキスト'); 101 | final deserializer = BincodeDeserializer(serializer.bytes); 102 | expect(deserializer.deserializeString(), 'dummy text / ダミーテキスト'); 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /serde-generate/runtime/dart/test/serde_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import 'dart:typed_data'; 5 | 6 | import 'package:test/test.dart'; 7 | 8 | import '../serde/serde.dart'; 9 | 10 | void main() { 11 | test('Uint64', () { 12 | expect(Uint64.parse('0').toString(), '0'); 13 | expect(Uint64.parse('184').toString(), '184'); 14 | expect(Uint64.parse('18446744073709551615').toString(), 15 | '18446744073709551615'); 16 | }); 17 | 18 | test('Uint128', () { 19 | expect(Uint128.parse('0').toString(), '0'); 20 | expect(Uint128.parse('340').toString(), '340'); 21 | expect(Uint128.parse('340282366920938463463374607431768211455').toString(), 22 | '340282366920938463463374607431768211455'); 23 | }); 24 | 25 | test('Int128', () { 26 | expect(Int128.parse('-170141183460469231731687303715884105728').toString(), 27 | '-170141183460469231731687303715884105728'); 28 | expect(Int128.parse('-170').toString(), '-170'); 29 | expect(Int128.parse('170').toString(), '170'); 30 | expect(Int128.parse('170141183460469231731687303715884105727').toString(), 31 | '170141183460469231731687303715884105727'); 32 | }); 33 | 34 | test('Bytes', () { 35 | final a = Bytes(Uint8List.fromList([0])); 36 | final b = Bytes(Uint8List.fromList([0])); 37 | final c = Bytes(Uint8List.fromList([1])); 38 | 39 | expect(a, b, reason: 'a == b'); 40 | expect(a.hashCode, b.hashCode, reason: 'a and b have same hashCode'); 41 | 42 | expect(a, isNot(c), reason: 'a != c'); 43 | expect(a.hashCode, isNot(c.hashCode), reason: 'a and c have different hashCode'); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/bcs/deserializer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package bcs 5 | 6 | import ( 7 | "bytes" 8 | "errors" 9 | 10 | "github.com/novifinancial/serde-reflection/serde-generate/runtime/golang/serde" 11 | ) 12 | 13 | // Maximum length allowed for sequences (vectors, bytes, strings) and maps. 14 | const MaxSequenceLength = (1 << 31) - 1 15 | 16 | // Maximum number of nested structs and enum variants. 17 | const MaxContainerDepth = 500 18 | 19 | const maxUint32 = uint64(^uint32(0)) 20 | 21 | // `deserializer` extends `serde.BinaryDeserializer` to implement `serde.Deserializer`. 22 | type deserializer struct { 23 | serde.BinaryDeserializer 24 | } 25 | 26 | func NewDeserializer(input []byte) serde.Deserializer { 27 | return &deserializer{*serde.NewBinaryDeserializer(input, MaxContainerDepth)} 28 | } 29 | 30 | // DeserializeF32 is unimplemented. 31 | func (d *deserializer) DeserializeF32() (float32, error) { 32 | return 0, errors.New("unimplemented") 33 | } 34 | 35 | // DeserializeF64 is unimplemented. 36 | func (d *deserializer) DeserializeF64() (float64, error) { 37 | return 0, errors.New("unimplemented") 38 | } 39 | 40 | func (d *deserializer) DeserializeBytes() ([]byte, error) { 41 | return d.BinaryDeserializer.DeserializeBytes(d.DeserializeLen) 42 | } 43 | 44 | func (d *deserializer) DeserializeStr() (string, error) { 45 | return d.BinaryDeserializer.DeserializeStr(d.DeserializeLen) 46 | } 47 | 48 | func (d *deserializer) DeserializeLen() (uint64, error) { 49 | ret, err := d.deserializeUleb128AsU32() 50 | if ret > MaxSequenceLength { 51 | return 0, errors.New("length is too large") 52 | } 53 | return uint64(ret), err 54 | } 55 | 56 | func (d *deserializer) DeserializeVariantIndex() (uint32, error) { 57 | return d.deserializeUleb128AsU32() 58 | } 59 | 60 | func (d *deserializer) CheckThatKeySlicesAreIncreasing(key1, key2 serde.Slice) error { 61 | if bytes.Compare(d.Input[key1.Start:key1.End], d.Input[key2.Start:key2.End]) >= 0 { 62 | return errors.New("Error while decoding map: keys are not serialized in the expected order") 63 | } 64 | return nil 65 | } 66 | 67 | func (d *deserializer) deserializeUleb128AsU32() (uint32, error) { 68 | var value uint64 69 | for shift := 0; shift < 32; shift += 7 { 70 | byte, err := d.Buffer.ReadByte() 71 | if err != nil { 72 | return 0, err 73 | } 74 | digit := byte & 0x7F 75 | value = value | (uint64(digit) << shift) 76 | 77 | if value > maxUint32 { 78 | return 0, errors.New("overflow while parsing uleb128-encoded uint32 value") 79 | } 80 | if digit == byte { 81 | if shift > 0 && digit == 0 { 82 | return 0, errors.New("invalid uleb128 number (unexpected zero digit)") 83 | } 84 | return uint32(value), nil 85 | } 86 | } 87 | return 0, errors.New("overflow while parsing uleb128-encoded uint32 value") 88 | } 89 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/bcs/serializer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package bcs 5 | 6 | import ( 7 | "bytes" 8 | "errors" 9 | "sort" 10 | 11 | "github.com/novifinancial/serde-reflection/serde-generate/runtime/golang/serde" 12 | ) 13 | 14 | // `serializer` extends `serde.BinarySerializer` to implement `serde.Serializer`. 15 | type serializer struct { 16 | serde.BinarySerializer 17 | } 18 | 19 | func NewSerializer() serde.Serializer { 20 | return &serializer{*serde.NewBinarySerializer(MaxContainerDepth)} 21 | } 22 | 23 | // SerializeF32 is unimplemented 24 | func (s *serializer) SerializeF32(value float32) error { 25 | return errors.New("unimplemented") 26 | } 27 | 28 | // SerializeF64 is unimplemented 29 | func (s *serializer) SerializeF64(value float64) error { 30 | return errors.New("unimplemented") 31 | } 32 | 33 | func (s *serializer) SerializeStr(value string) error { 34 | return s.BinarySerializer.SerializeStr(value, s.SerializeLen) 35 | } 36 | 37 | func (s *serializer) SerializeBytes(value []byte) error { 38 | return s.BinarySerializer.SerializeBytes(value, s.SerializeLen) 39 | } 40 | 41 | func (s *serializer) SerializeLen(value uint64) error { 42 | if value > MaxSequenceLength { 43 | return errors.New("length is too large") 44 | } 45 | s.serializeU32AsUleb128(uint32(value)) 46 | return nil 47 | } 48 | 49 | func (s *serializer) SerializeVariantIndex(value uint32) error { 50 | s.serializeU32AsUleb128(value) 51 | return nil 52 | } 53 | 54 | func (s *serializer) SortMapEntries(offsets []uint64) { 55 | if len(offsets) <= 1 { 56 | return 57 | } 58 | data := s.Buffer.Bytes() 59 | slices := make([]serde.Slice, len(offsets)) 60 | for i, v := range offsets { 61 | var w uint64 62 | if i+1 < len(offsets) { 63 | w = offsets[i+1] 64 | } else { 65 | w = uint64(len(data)) 66 | } 67 | slices[i] = serde.Slice{Start: v, End: w} 68 | } 69 | entries := map_entries{data, slices} 70 | sort.Sort(entries) 71 | buffer := make([]byte, len(data)-int(offsets[0])) 72 | current := buffer[0:0] 73 | for _, slice := range entries.slices { 74 | current = append(current, data[slice.Start:slice.End]...) 75 | } 76 | copy(data[offsets[0]:], current) 77 | } 78 | 79 | func (s *serializer) serializeU32AsUleb128(value uint32) { 80 | for value >= 0x80 { 81 | b := byte((value & 0x7f) | 0x80) 82 | _ = s.Buffer.WriteByte(b) 83 | value = value >> 7 84 | } 85 | _ = s.Buffer.WriteByte(byte(value)) 86 | } 87 | 88 | type map_entries struct { 89 | data []byte 90 | slices []serde.Slice 91 | } 92 | 93 | func (a map_entries) Len() int { return len(a.slices) } 94 | 95 | func (a map_entries) Less(i, j int) bool { 96 | slice_i := a.data[a.slices[i].Start:a.slices[i].End] 97 | slice_j := a.data[a.slices[j].Start:a.slices[j].End] 98 | return bytes.Compare(slice_i, slice_j) < 0 99 | } 100 | 101 | func (a map_entries) Swap(i, j int) { a.slices[i], a.slices[j] = a.slices[j], a.slices[i] } 102 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/bincode/deserializer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package bincode 5 | 6 | import ( 7 | "errors" 8 | "math" 9 | 10 | "github.com/novifinancial/serde-reflection/serde-generate/runtime/golang/serde" 11 | ) 12 | 13 | // MaxSequenceLength is max length supported in practice (e.g. in Java). 14 | const MaxSequenceLength = (1 << 31) - 1 15 | 16 | // `deserializer` extends `serde.BinaryDeserializer` to implement `serde.Deserializer`. 17 | type deserializer struct { 18 | serde.BinaryDeserializer 19 | } 20 | 21 | func NewDeserializer(input []byte) serde.Deserializer { 22 | return &deserializer{*serde.NewBinaryDeserializer(input, math.MaxUint64)} 23 | } 24 | 25 | func (d *deserializer) DeserializeF32() (float32, error) { 26 | ret, err := d.DeserializeU32() 27 | return math.Float32frombits(ret), err 28 | } 29 | 30 | func (d *deserializer) DeserializeF64() (float64, error) { 31 | ret, err := d.DeserializeU64() 32 | return math.Float64frombits(ret), err 33 | } 34 | 35 | func (d *deserializer) DeserializeBytes() ([]byte, error) { 36 | return d.BinaryDeserializer.DeserializeBytes(d.DeserializeLen) 37 | } 38 | 39 | func (d *deserializer) DeserializeStr() (string, error) { 40 | return d.BinaryDeserializer.DeserializeStr(d.DeserializeLen) 41 | } 42 | 43 | func (d *deserializer) DeserializeLen() (uint64, error) { 44 | ret, err := d.DeserializeU64() 45 | if ret > MaxSequenceLength { 46 | return 0, errors.New("length is too large") 47 | } 48 | return uint64(ret), err 49 | } 50 | 51 | func (d *deserializer) DeserializeVariantIndex() (uint32, error) { 52 | return d.DeserializeU32() 53 | } 54 | 55 | func (d *deserializer) CheckThatKeySlicesAreIncreasing(key1, key2 serde.Slice) error { 56 | // No need to check key ordering in Bincode. 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/bincode/serializer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package bincode 5 | 6 | import ( 7 | "math" 8 | 9 | "github.com/novifinancial/serde-reflection/serde-generate/runtime/golang/serde" 10 | ) 11 | 12 | // `serializer` extends `serde.BinarySerializer` to implement `serde.Serializer`. 13 | type serializer struct { 14 | serde.BinarySerializer 15 | } 16 | 17 | func NewSerializer() serde.Serializer { 18 | return &serializer{*serde.NewBinarySerializer(math.MaxUint64)} 19 | } 20 | 21 | func (s *serializer) SerializeF32(value float32) error { 22 | return s.SerializeU32(math.Float32bits(value)) 23 | } 24 | 25 | func (s *serializer) SerializeF64(value float64) error { 26 | return s.SerializeU64(math.Float64bits(value)) 27 | } 28 | 29 | func (s *serializer) SerializeStr(value string) error { 30 | return s.BinarySerializer.SerializeStr(value, s.SerializeLen) 31 | } 32 | 33 | func (s *serializer) SerializeBytes(value []byte) error { 34 | return s.BinarySerializer.SerializeBytes(value, s.SerializeLen) 35 | } 36 | 37 | func (s *serializer) SerializeLen(value uint64) error { 38 | return s.SerializeU64(value) 39 | } 40 | 41 | func (s *serializer) SerializeVariantIndex(value uint32) error { 42 | return s.SerializeU32(value) 43 | } 44 | 45 | func (s *serializer) SortMapEntries(offsets []uint64) { 46 | // No need to sort map entries in Bincode. 47 | } 48 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/novifinancial/serde-reflection/serde-generate/runtime/golang 2 | 3 | go 1.14 4 | 5 | require github.com/stretchr/testify v1.6.1 6 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 7 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/serde/binary_serializer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package serde 5 | 6 | import ( 7 | "bytes" 8 | "errors" 9 | ) 10 | 11 | // `BinarySerializer` is a partial implementation of the `Serializer` interface. 12 | // It is used as an embedded struct by the Bincode and BCS serializers. 13 | type BinarySerializer struct { 14 | Buffer bytes.Buffer 15 | containerDepthBudget uint64 16 | } 17 | 18 | func NewBinarySerializer(max_container_depth uint64) *BinarySerializer { 19 | s := new(BinarySerializer) 20 | s.containerDepthBudget = max_container_depth 21 | return s 22 | } 23 | 24 | func (d *BinarySerializer) IncreaseContainerDepth() error { 25 | if d.containerDepthBudget == 0 { 26 | return errors.New("exceeded maximum container depth") 27 | } 28 | d.containerDepthBudget -= 1 29 | return nil 30 | } 31 | 32 | func (d *BinarySerializer) DecreaseContainerDepth() { 33 | d.containerDepthBudget += 1 34 | } 35 | 36 | // `serializeLen` to be provided by the extending struct. 37 | func (s *BinarySerializer) SerializeBytes(value []byte, serializeLen func(uint64) error) error { 38 | serializeLen(uint64(len(value))) 39 | s.Buffer.Write(value) 40 | return nil 41 | } 42 | 43 | // `serializeLen` to be provided by the extending struct. 44 | func (s *BinarySerializer) SerializeStr(value string, serializeLen func(uint64) error) error { 45 | return s.SerializeBytes([]byte(value), serializeLen) 46 | } 47 | 48 | func (s *BinarySerializer) SerializeBool(value bool) error { 49 | if value { 50 | return s.Buffer.WriteByte(1) 51 | } 52 | return s.Buffer.WriteByte(0) 53 | } 54 | 55 | func (s *BinarySerializer) SerializeUnit(value struct{}) error { 56 | return nil 57 | } 58 | 59 | // SerializeChar is unimplemented. 60 | func (s *BinarySerializer) SerializeChar(value rune) error { 61 | return errors.New("unimplemented") 62 | } 63 | 64 | func (s *BinarySerializer) SerializeU8(value uint8) error { 65 | s.Buffer.WriteByte(byte(value)) 66 | return nil 67 | } 68 | 69 | func (s *BinarySerializer) SerializeU16(value uint16) error { 70 | s.Buffer.WriteByte(byte(value)) 71 | s.Buffer.WriteByte(byte(value >> 8)) 72 | return nil 73 | } 74 | 75 | func (s *BinarySerializer) SerializeU32(value uint32) error { 76 | s.Buffer.WriteByte(byte(value)) 77 | s.Buffer.WriteByte(byte(value >> 8)) 78 | s.Buffer.WriteByte(byte(value >> 16)) 79 | s.Buffer.WriteByte(byte(value >> 24)) 80 | return nil 81 | } 82 | 83 | func (s *BinarySerializer) SerializeU64(value uint64) error { 84 | s.Buffer.WriteByte(byte(value)) 85 | s.Buffer.WriteByte(byte(value >> 8)) 86 | s.Buffer.WriteByte(byte(value >> 16)) 87 | s.Buffer.WriteByte(byte(value >> 24)) 88 | s.Buffer.WriteByte(byte(value >> 32)) 89 | s.Buffer.WriteByte(byte(value >> 40)) 90 | s.Buffer.WriteByte(byte(value >> 48)) 91 | s.Buffer.WriteByte(byte(value >> 56)) 92 | return nil 93 | } 94 | 95 | func (s *BinarySerializer) SerializeU128(value Uint128) error { 96 | s.SerializeU64(value.Low) 97 | s.SerializeU64(value.High) 98 | return nil 99 | } 100 | 101 | func (s *BinarySerializer) SerializeI8(value int8) error { 102 | s.SerializeU8(uint8(value)) 103 | return nil 104 | } 105 | 106 | func (s *BinarySerializer) SerializeI16(value int16) error { 107 | s.SerializeU16(uint16(value)) 108 | return nil 109 | } 110 | 111 | func (s *BinarySerializer) SerializeI32(value int32) error { 112 | s.SerializeU32(uint32(value)) 113 | return nil 114 | } 115 | 116 | func (s *BinarySerializer) SerializeI64(value int64) error { 117 | s.SerializeU64(uint64(value)) 118 | return nil 119 | } 120 | 121 | func (s *BinarySerializer) SerializeI128(value Int128) error { 122 | s.SerializeU64(value.Low) 123 | s.SerializeI64(value.High) 124 | return nil 125 | } 126 | 127 | func (s *BinarySerializer) SerializeOptionTag(value bool) error { 128 | return s.SerializeBool(value) 129 | } 130 | 131 | func (s *BinarySerializer) GetBufferOffset() uint64 { 132 | return uint64(s.Buffer.Len()) 133 | } 134 | 135 | func (s *BinarySerializer) GetBytes() []byte { 136 | return s.Buffer.Bytes() 137 | } 138 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/serde/interfaces.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package serde 5 | 6 | type Serializer interface { 7 | SerializeStr(value string) error 8 | 9 | SerializeBytes(value []byte) error 10 | 11 | SerializeBool(value bool) error 12 | 13 | SerializeUnit(value struct{}) error 14 | 15 | SerializeChar(value rune) error 16 | 17 | SerializeF32(value float32) error 18 | 19 | SerializeF64(value float64) error 20 | 21 | SerializeU8(value uint8) error 22 | 23 | SerializeU16(value uint16) error 24 | 25 | SerializeU32(value uint32) error 26 | 27 | SerializeU64(value uint64) error 28 | 29 | SerializeU128(value Uint128) error 30 | 31 | SerializeI8(value int8) error 32 | 33 | SerializeI16(value int16) error 34 | 35 | SerializeI32(value int32) error 36 | 37 | SerializeI64(value int64) error 38 | 39 | SerializeI128(value Int128) error 40 | 41 | SerializeLen(value uint64) error 42 | 43 | SerializeVariantIndex(value uint32) error 44 | 45 | SerializeOptionTag(value bool) error 46 | 47 | GetBufferOffset() uint64 48 | 49 | SortMapEntries(offsets []uint64) 50 | 51 | GetBytes() []byte 52 | 53 | IncreaseContainerDepth() error 54 | 55 | DecreaseContainerDepth() 56 | } 57 | 58 | type Deserializer interface { 59 | DeserializeStr() (string, error) 60 | 61 | DeserializeBytes() ([]byte, error) 62 | 63 | DeserializeBool() (bool, error) 64 | 65 | DeserializeUnit() (struct{}, error) 66 | 67 | DeserializeChar() (rune, error) 68 | 69 | DeserializeF32() (float32, error) 70 | 71 | DeserializeF64() (float64, error) 72 | 73 | DeserializeU8() (uint8, error) 74 | 75 | DeserializeU16() (uint16, error) 76 | 77 | DeserializeU32() (uint32, error) 78 | 79 | DeserializeU64() (uint64, error) 80 | 81 | DeserializeU128() (Uint128, error) 82 | 83 | DeserializeI8() (int8, error) 84 | 85 | DeserializeI16() (int16, error) 86 | 87 | DeserializeI32() (int32, error) 88 | 89 | DeserializeI64() (int64, error) 90 | 91 | DeserializeI128() (Int128, error) 92 | 93 | DeserializeLen() (uint64, error) 94 | 95 | DeserializeVariantIndex() (uint32, error) 96 | 97 | DeserializeOptionTag() (bool, error) 98 | 99 | GetBufferOffset() uint64 100 | 101 | CheckThatKeySlicesAreIncreasing(key1, key2 Slice) error 102 | 103 | IncreaseContainerDepth() error 104 | 105 | DecreaseContainerDepth() 106 | } 107 | 108 | type Slice struct { 109 | Start uint64 110 | End uint64 111 | } 112 | -------------------------------------------------------------------------------- /serde-generate/runtime/golang/serde/types.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package serde 5 | 6 | type Uint128 struct { 7 | High uint64 8 | Low uint64 9 | } 10 | 11 | type Int128 struct { 12 | High int64 13 | Low uint64 14 | } 15 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/bcs/BcsDeserializer.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.bcs; 5 | 6 | import com.novi.serde.DeserializationError; 7 | import com.novi.serde.Slice; 8 | import com.novi.serde.BinaryDeserializer; 9 | 10 | public class BcsDeserializer extends BinaryDeserializer { 11 | public BcsDeserializer(byte[] input) { 12 | super(input, BcsSerializer.MAX_CONTAINER_DEPTH); 13 | } 14 | 15 | public Float deserialize_f32() throws DeserializationError { 16 | throw new DeserializationError("Not implemented: deserialize_f32"); 17 | } 18 | 19 | public Double deserialize_f64() throws DeserializationError { 20 | throw new DeserializationError("Not implemented: deserialize_f64"); 21 | } 22 | 23 | private int deserialize_uleb128_as_u32() throws DeserializationError { 24 | long value = 0; 25 | for (int shift = 0; shift < 32; shift += 7) { 26 | byte x = getByte(); 27 | byte digit = (byte) (x & 0x7F); 28 | value = value | ((long)digit << shift); 29 | if ((value < 0) || (value > Integer.MAX_VALUE)) { 30 | throw new DeserializationError("Overflow while parsing uleb128-encoded uint32 value"); 31 | } 32 | if (digit == x) { 33 | if (shift > 0 && digit == 0) { 34 | throw new DeserializationError("Invalid uleb128 number (unexpected zero digit)"); 35 | } 36 | return (int) value; 37 | } 38 | } 39 | throw new DeserializationError("Overflow while parsing uleb128-encoded uint32 value"); 40 | } 41 | 42 | public long deserialize_len() throws DeserializationError { 43 | return deserialize_uleb128_as_u32(); 44 | } 45 | 46 | public int deserialize_variant_index() throws DeserializationError { 47 | return deserialize_uleb128_as_u32(); 48 | } 49 | 50 | public void check_that_key_slices_are_increasing(Slice key1, Slice key2) throws DeserializationError { 51 | if (Slice.compare_bytes(input.array(), key1, key2) >= 0) { 52 | throw new DeserializationError("Error while decoding map: keys are not serialized in the expected order"); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/bcs/BcsSerializer.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.bcs; 5 | 6 | import com.novi.serde.SerializationError; 7 | import com.novi.serde.Slice; 8 | import com.novi.serde.BinarySerializer; 9 | 10 | public class BcsSerializer extends BinarySerializer { 11 | public static final long MAX_LENGTH = Integer.MAX_VALUE; 12 | public static final long MAX_CONTAINER_DEPTH = 500; 13 | 14 | public BcsSerializer() { 15 | super(MAX_CONTAINER_DEPTH); 16 | } 17 | 18 | public void serialize_f32(Float value) throws SerializationError { 19 | throw new SerializationError("Not implemented: serialize_f32"); 20 | } 21 | 22 | public void serialize_f64(Double value) throws SerializationError { 23 | throw new SerializationError("Not implemented: serialize_f64"); 24 | } 25 | 26 | private void serialize_u32_as_uleb128(int value) { 27 | while ((value >>> 7) != 0) { 28 | output.write((value & 0x7f) | 0x80); 29 | value = value >>> 7; 30 | } 31 | output.write(value); 32 | } 33 | 34 | public void serialize_len(long value) throws SerializationError { 35 | if ((value < 0) || (value > MAX_LENGTH)) { 36 | throw new SerializationError("Incorrect length value"); 37 | } 38 | serialize_u32_as_uleb128((int) value); 39 | } 40 | 41 | public void serialize_variant_index(int value) throws SerializationError { 42 | serialize_u32_as_uleb128(value); 43 | } 44 | 45 | public void sort_map_entries(int[] offsets) { 46 | if (offsets.length <= 1) { 47 | return; 48 | } 49 | int offset0 = offsets[0]; 50 | byte[] content = output.getBuffer(); 51 | Slice[] slices = new Slice[offsets.length]; 52 | for (int i = 0; i < offsets.length - 1; i++) { 53 | slices[i] = new Slice(offsets[i], offsets[i + 1]); 54 | } 55 | slices[offsets.length - 1] = new Slice(offsets[offsets.length - 1], output.size()); 56 | 57 | java.util.Arrays.sort(slices, new java.util.Comparator() { 58 | @Override 59 | public int compare(Slice slice1, Slice slice2) { 60 | return Slice.compare_bytes(content, slice1, slice2); 61 | } 62 | }); 63 | 64 | byte[] old_content = new byte[output.size() - offset0]; 65 | System.arraycopy(content, offset0, old_content, 0, output.size() - offset0); 66 | 67 | int position = offset0; 68 | for (int i = 0; i < offsets.length; i++) { 69 | int start = slices[i].start; 70 | int end = slices[i].end; 71 | System.arraycopy(old_content, start - offset0, content, position, end - start); 72 | position += end - start; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/bcs/BcsTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.bcs; 5 | 6 | import java.util.Arrays; 7 | import java.lang.reflect.Method; 8 | import java.math.BigInteger; 9 | import java.lang.Runnable; 10 | 11 | public class BcsTest { 12 | 13 | static void test_serialize_u128() throws Exception { 14 | BcsSerializer serializer = new BcsSerializer(); 15 | serializer.serialize_u128(BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE)); 16 | assert Arrays.equals(serializer.get_bytes(), new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}); 17 | 18 | serializer = new BcsSerializer(); 19 | serializer.serialize_u128(BigInteger.ONE); 20 | assert Arrays.equals(serializer.get_bytes(), new byte[]{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); 21 | 22 | serializer = new BcsSerializer(); 23 | serializer.serialize_u128(BigInteger.ZERO); 24 | assert Arrays.equals(serializer.get_bytes(), new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); 25 | 26 | try { 27 | serializer.serialize_u128(BigInteger.ONE.negate()); 28 | assert false; 29 | } catch (java.lang.IllegalArgumentException e) { /* all good */ } 30 | 31 | try { 32 | serializer.serialize_u128(BigInteger.ONE.shiftLeft(128).add(BigInteger.ONE)); 33 | assert false; 34 | } catch (java.lang.IllegalArgumentException e) { /* all good */ } 35 | } 36 | 37 | static void test_serialize_i128() throws Exception { 38 | BcsSerializer serializer = new BcsSerializer(); 39 | serializer.serialize_i128(BigInteger.ONE.negate()); 40 | assert Arrays.equals(serializer.get_bytes(), new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}); 41 | 42 | serializer = new BcsSerializer(); 43 | serializer.serialize_i128(BigInteger.ONE); 44 | assert Arrays.equals(serializer.get_bytes(), new byte[]{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); 45 | 46 | serializer = new BcsSerializer(); 47 | serializer.serialize_i128(BigInteger.ONE.shiftLeft(127).subtract(BigInteger.ONE)); 48 | assert Arrays.equals(serializer.get_bytes(), new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 127}); 49 | 50 | serializer = new BcsSerializer(); 51 | serializer.serialize_i128(BigInteger.ONE.shiftLeft(127).negate()); 52 | assert Arrays.equals(serializer.get_bytes(), new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -128}); 53 | 54 | try { 55 | serializer.serialize_i128(BigInteger.ONE.shiftLeft(127)); 56 | assert false; 57 | } catch (java.lang.IllegalArgumentException e) { /* all good */ } 58 | 59 | try { 60 | serializer.serialize_i128(BigInteger.ONE.shiftLeft(127).add(BigInteger.ONE).negate()); 61 | assert false; 62 | } catch (java.lang.IllegalArgumentException e) { /* all good */ } 63 | } 64 | 65 | static void test_serializer_slice_ordering() throws Exception { 66 | BcsSerializer serializer = new BcsSerializer(); 67 | 68 | serializer.serialize_u8((byte) -1); 69 | serializer.serialize_u32(1); 70 | serializer.serialize_u32(1); 71 | serializer.serialize_u32(2); 72 | assert Arrays.equals(serializer.get_bytes(), new byte[]{-1, /**/ 1, /**/ 0, 0, /**/ 0, 1, 0, /**/ 0, /**/ 0, /**/ 2, 0, 0, 0}); 73 | 74 | int[] offsets = {1, 2, 4, 7, 8, 9}; 75 | serializer.sort_map_entries(offsets); 76 | assert Arrays.equals(serializer.get_bytes(), new byte[]{-1, /**/ 0, /**/ 0, /**/ 0, 0, /**/ 0, 1, 0, /**/ 1, /**/ 2, 0, 0, 0}); 77 | } 78 | 79 | public static void main(String[] args) throws Exception { 80 | for (Method method : BcsTest.class.getDeclaredMethods()) { 81 | if (method.getName().startsWith("test_")) { 82 | method.invoke(null); 83 | } 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/bincode/BincodeDeserializer.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.bincode; 5 | 6 | import com.novi.serde.DeserializationError; 7 | import com.novi.serde.Slice; 8 | import com.novi.serde.BinaryDeserializer; 9 | 10 | public class BincodeDeserializer extends BinaryDeserializer { 11 | public BincodeDeserializer(byte[] input) { 12 | super(input, Long.MAX_VALUE); 13 | } 14 | 15 | public Float deserialize_f32() throws DeserializationError { 16 | return Float.valueOf(getFloat()); 17 | } 18 | 19 | public Double deserialize_f64() throws DeserializationError { 20 | return Double.valueOf(getDouble()); 21 | } 22 | 23 | public long deserialize_len() throws DeserializationError { 24 | long value = getLong(); 25 | if (value < 0 || value > Integer.MAX_VALUE) { 26 | throw new DeserializationError("Incorrect length value"); 27 | } 28 | return value; 29 | } 30 | 31 | public int deserialize_variant_index() throws DeserializationError { 32 | return getInt(); 33 | } 34 | 35 | public void check_that_key_slices_are_increasing(Slice key1, Slice key2) throws DeserializationError { 36 | // Not required by the format. 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/bincode/BincodeSerializer.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.bincode; 5 | 6 | import com.novi.serde.SerializationError; 7 | import com.novi.serde.BinarySerializer; 8 | 9 | public class BincodeSerializer extends BinarySerializer { 10 | public BincodeSerializer() { 11 | super(Long.MAX_VALUE); 12 | } 13 | 14 | public void serialize_f32(Float value) throws SerializationError { 15 | serialize_i32(Integer.valueOf(Float.floatToRawIntBits(value.floatValue()))); 16 | } 17 | 18 | public void serialize_f64(Double value) throws SerializationError { 19 | serialize_i64(Long.valueOf(Double.doubleToRawLongBits(value.doubleValue()))); 20 | } 21 | 22 | public void serialize_len(long value) throws SerializationError { 23 | serialize_u64(value); 24 | } 25 | 26 | public void serialize_variant_index(int value) throws SerializationError { 27 | serialize_u32(value); 28 | } 29 | 30 | public void sort_map_entries(int[] offsets) { 31 | // Not required by the format. 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/ArrayLen.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Target; 8 | 9 | @Target({ElementType.TYPE_USE}) 10 | public @interface ArrayLen { 11 | int length(); 12 | } 13 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Bytes.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.util.Arrays; 7 | import java.util.Objects; 8 | 9 | /** 10 | * Immutable wrapper class around byte[]. 11 | * 12 | * Enforces value-semantice for `equals` and `hashCode`. 13 | */ 14 | public final class Bytes { 15 | private final byte[] content; 16 | 17 | private static final Bytes EMPTY = new Bytes(new byte[0]); 18 | 19 | /// Low-level constructor (use with care). 20 | public Bytes(byte[] content) { 21 | Objects.requireNonNull(content, "content must not be null"); 22 | this.content = content; 23 | } 24 | 25 | public static Bytes empty() { 26 | return EMPTY; 27 | } 28 | 29 | public static Bytes valueOf(byte[] content) { 30 | Objects.requireNonNull(content, "content must not be null"); 31 | if (content.length == 0) { 32 | return EMPTY; 33 | } else { 34 | return new Bytes(content.clone()); 35 | } 36 | } 37 | 38 | public byte[] content() { 39 | return this.content.clone(); 40 | } 41 | 42 | public boolean equals(Object obj) { 43 | if (this == obj) return true; 44 | if (obj == null) return false; 45 | if (getClass() != obj.getClass()) return false; 46 | Bytes other = (Bytes) obj; 47 | return Arrays.equals(this.content, other.content); 48 | } 49 | 50 | public int hashCode() { 51 | return Arrays.hashCode(content); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/DeserializationError.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | @SuppressWarnings("serial") 7 | public final class DeserializationError extends Exception { 8 | public DeserializationError(String s) { 9 | super(s); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Deserializer.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.math.BigInteger; 7 | 8 | public interface Deserializer { 9 | String deserialize_str() throws DeserializationError; 10 | 11 | Bytes deserialize_bytes() throws DeserializationError; 12 | 13 | Boolean deserialize_bool() throws DeserializationError; 14 | 15 | Unit deserialize_unit() throws DeserializationError; 16 | 17 | Character deserialize_char() throws DeserializationError; 18 | 19 | Float deserialize_f32() throws DeserializationError; 20 | 21 | Double deserialize_f64() throws DeserializationError; 22 | 23 | @Unsigned Byte deserialize_u8() throws DeserializationError; 24 | 25 | @Unsigned Short deserialize_u16() throws DeserializationError; 26 | 27 | @Unsigned Integer deserialize_u32() throws DeserializationError; 28 | 29 | @Unsigned Long deserialize_u64() throws DeserializationError; 30 | 31 | @Unsigned @Int128 BigInteger deserialize_u128() throws DeserializationError; 32 | 33 | Byte deserialize_i8() throws DeserializationError; 34 | 35 | Short deserialize_i16() throws DeserializationError; 36 | 37 | Integer deserialize_i32() throws DeserializationError; 38 | 39 | Long deserialize_i64() throws DeserializationError; 40 | 41 | @Int128 BigInteger deserialize_i128() throws DeserializationError; 42 | 43 | long deserialize_len() throws DeserializationError; 44 | 45 | int deserialize_variant_index() throws DeserializationError; 46 | 47 | boolean deserialize_option_tag() throws DeserializationError; 48 | 49 | void increase_container_depth() throws DeserializationError; 50 | 51 | void decrease_container_depth(); 52 | 53 | int get_buffer_offset(); 54 | 55 | void check_that_key_slices_are_increasing(Slice key1, Slice key2) throws DeserializationError; 56 | } 57 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Int128.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Target; 8 | 9 | @Target({ElementType.TYPE_USE}) 10 | public @interface Int128 { 11 | } 12 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/SerializationError.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | @SuppressWarnings("serial") 7 | public final class SerializationError extends Exception { 8 | public SerializationError(String s) { 9 | super(s); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Serializer.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.math.BigInteger; 7 | 8 | public interface Serializer { 9 | void serialize_str(String value) throws SerializationError; 10 | 11 | void serialize_bytes(Bytes value) throws SerializationError; 12 | 13 | void serialize_bool(Boolean value) throws SerializationError; 14 | 15 | void serialize_unit(Unit value) throws SerializationError; 16 | 17 | void serialize_char(Character value) throws SerializationError; 18 | 19 | void serialize_f32(Float value) throws SerializationError; 20 | 21 | void serialize_f64(Double value) throws SerializationError; 22 | 23 | void serialize_u8(@Unsigned Byte value) throws SerializationError; 24 | 25 | void serialize_u16(@Unsigned Short value) throws SerializationError; 26 | 27 | void serialize_u32(@Unsigned Integer value) throws SerializationError; 28 | 29 | void serialize_u64(@Unsigned Long value) throws SerializationError; 30 | 31 | void serialize_u128(@Unsigned @Int128 BigInteger value) throws SerializationError; 32 | 33 | void serialize_i8(Byte value) throws SerializationError; 34 | 35 | void serialize_i16(Short value) throws SerializationError; 36 | 37 | void serialize_i32(Integer value) throws SerializationError; 38 | 39 | void serialize_i64(Long value) throws SerializationError; 40 | 41 | void serialize_i128(@Int128 BigInteger value) throws SerializationError; 42 | 43 | void serialize_len(long value) throws SerializationError; 44 | 45 | void serialize_variant_index(int value) throws SerializationError; 46 | 47 | void serialize_option_tag(boolean value) throws SerializationError; 48 | 49 | void increase_container_depth() throws SerializationError; 50 | 51 | void decrease_container_depth(); 52 | 53 | int get_buffer_offset(); 54 | 55 | void sort_map_entries(int[] offsets); 56 | 57 | byte[] get_bytes(); 58 | } 59 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Slice.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | public final class Slice { 7 | public final int start; 8 | public final int end; 9 | 10 | public Slice(int start, int end) { 11 | this.start = start; 12 | this.end = end; 13 | } 14 | 15 | // Lexicographic comparison between the (unsigned!) bytes referenced by `slice1` and `slice2` 16 | // into `content`. 17 | public static int compare_bytes(byte[] content, Slice slice1, Slice slice2) { 18 | int start1 = slice1.start; 19 | int end1 = slice1.end; 20 | int start2 = slice2.start; 21 | int end2 = slice2.end; 22 | for (int i = 0; i < end1 - start1; i++) { 23 | int byte1 = content[start1 + i] & 0xFF; 24 | if (start2 + i >= end2) { 25 | return 1; 26 | } 27 | int byte2 = content[start2 + i] & 0xFF; 28 | if (byte1 > byte2) { 29 | return 1; 30 | } 31 | if (byte1 < byte2) { 32 | return -1; 33 | } 34 | } 35 | if (end2 - start2 > end1 - start1) { 36 | return -1; 37 | } 38 | return 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Tuple2.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.util.Objects; 7 | 8 | public final class Tuple2 { 9 | public final T0 field0; 10 | public final T1 field1; 11 | 12 | public Tuple2(T0 f0, T1 f1) { 13 | Objects.requireNonNull(f0, "f0 must not be null"); 14 | Objects.requireNonNull(f1, "f1 must not be null"); 15 | this.field0 = f0; 16 | this.field1 = f1; 17 | } 18 | 19 | public boolean equals(Object obj) { 20 | if (this == obj) return true; 21 | if (obj == null) return false; 22 | if (getClass() != obj.getClass()) return false; 23 | Tuple2 other = (Tuple2) obj; 24 | if (!Objects.equals(this.field0, other.field0)) { 25 | return false; 26 | } 27 | if (!Objects.equals(this.field1, other.field1)) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | public int hashCode() { 34 | int value = 7; 35 | value = 31 * value + (this.field0 != null ? this.field0.hashCode() : 0); 36 | value = 31 * value + (this.field1 != null ? this.field1.hashCode() : 0); 37 | return value; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Tuple3.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.util.Objects; 7 | 8 | public final class Tuple3 { 9 | public final T0 field0; 10 | public final T1 field1; 11 | public final T2 field2; 12 | 13 | public Tuple3(T0 f0, T1 f1, T2 f2) { 14 | Objects.requireNonNull(f0, "f0 must not be null"); 15 | Objects.requireNonNull(f1, "f1 must not be null"); 16 | Objects.requireNonNull(f2, "f2 must not be null"); 17 | this.field0 = f0; 18 | this.field1 = f1; 19 | this.field2 = f2; 20 | } 21 | 22 | public boolean equals(Object obj) { 23 | if (this == obj) return true; 24 | if (obj == null) return false; 25 | if (getClass() != obj.getClass()) return false; 26 | Tuple3 other = (Tuple3) obj; 27 | if (!Objects.equals(this.field0, other.field0)) { 28 | return false; 29 | } 30 | if (!Objects.equals(this.field1, other.field1)) { 31 | return false; 32 | } 33 | if (!Objects.equals(this.field2, other.field2)) { 34 | return false; 35 | } 36 | return true; 37 | } 38 | 39 | public int hashCode() { 40 | int value = 7; 41 | value = 31 * value + (this.field0 != null ? this.field0.hashCode() : 0); 42 | value = 31 * value + (this.field1 != null ? this.field1.hashCode() : 0); 43 | value = 31 * value + (this.field2 != null ? this.field2.hashCode() : 0); 44 | return value; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Tuple4.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.util.Objects; 7 | 8 | public final class Tuple4 { 9 | public final T0 field0; 10 | public final T1 field1; 11 | public final T2 field2; 12 | public final T3 field3; 13 | 14 | public Tuple4(T0 f0, T1 f1, T2 f2, T3 f3) { 15 | Objects.requireNonNull(f0, "f0 must not be null"); 16 | Objects.requireNonNull(f1, "f1 must not be null"); 17 | Objects.requireNonNull(f2, "f2 must not be null"); 18 | Objects.requireNonNull(f3, "f3 must not be null"); 19 | this.field0 = f0; 20 | this.field1 = f1; 21 | this.field2 = f2; 22 | this.field3 = f3; 23 | } 24 | 25 | public boolean equals(Object obj) { 26 | if (this == obj) return true; 27 | if (obj == null) return false; 28 | if (getClass() != obj.getClass()) return false; 29 | Tuple4 other = (Tuple4) obj; 30 | if (!Objects.equals(this.field0, other.field0)) { 31 | return false; 32 | } 33 | if (!Objects.equals(this.field1, other.field1)) { 34 | return false; 35 | } 36 | if (!Objects.equals(this.field2, other.field2)) { 37 | return false; 38 | } 39 | if (!Objects.equals(this.field3, other.field3)) { 40 | return false; 41 | } 42 | return true; 43 | } 44 | 45 | public int hashCode() { 46 | int value = 7; 47 | value = 31 * value + (this.field0 != null ? this.field0.hashCode() : 0); 48 | value = 31 * value + (this.field1 != null ? this.field1.hashCode() : 0); 49 | value = 31 * value + (this.field2 != null ? this.field2.hashCode() : 0); 50 | value = 31 * value + (this.field3 != null ? this.field3.hashCode() : 0); 51 | return value; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Tuple5.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.util.Objects; 7 | 8 | public final class Tuple5 { 9 | public final T0 field0; 10 | public final T1 field1; 11 | public final T2 field2; 12 | public final T3 field3; 13 | public final T4 field4; 14 | 15 | public Tuple5(T0 f0, T1 f1, T2 f2, T3 f3, T4 f4) { 16 | Objects.requireNonNull(f0, "f0 must not be null"); 17 | Objects.requireNonNull(f1, "f1 must not be null"); 18 | Objects.requireNonNull(f2, "f2 must not be null"); 19 | Objects.requireNonNull(f3, "f3 must not be null"); 20 | Objects.requireNonNull(f4, "f4 must not be null"); 21 | this.field0 = f0; 22 | this.field1 = f1; 23 | this.field2 = f2; 24 | this.field3 = f3; 25 | this.field4 = f4; 26 | } 27 | 28 | public boolean equals(Object obj) { 29 | if (this == obj) return true; 30 | if (obj == null) return false; 31 | if (getClass() != obj.getClass()) return false; 32 | Tuple5 other = (Tuple5) obj; 33 | if (!Objects.equals(this.field0, other.field0)) { 34 | return false; 35 | } 36 | if (!Objects.equals(this.field1, other.field1)) { 37 | return false; 38 | } 39 | if (!Objects.equals(this.field2, other.field2)) { 40 | return false; 41 | } 42 | if (!Objects.equals(this.field3, other.field3)) { 43 | return false; 44 | } 45 | if (!Objects.equals(this.field4, other.field4)) { 46 | return false; 47 | } 48 | return true; 49 | } 50 | 51 | public int hashCode() { 52 | int value = 7; 53 | value = 31 * value + (this.field0 != null ? this.field0.hashCode() : 0); 54 | value = 31 * value + (this.field1 != null ? this.field1.hashCode() : 0); 55 | value = 31 * value + (this.field2 != null ? this.field2.hashCode() : 0); 56 | value = 31 * value + (this.field3 != null ? this.field3.hashCode() : 0); 57 | value = 31 * value + (this.field4 != null ? this.field4.hashCode() : 0); 58 | return value; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Tuple6.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.util.Objects; 7 | 8 | public final class Tuple6 { 9 | public final T0 field0; 10 | public final T1 field1; 11 | public final T2 field2; 12 | public final T3 field3; 13 | public final T4 field4; 14 | public final T5 field5; 15 | 16 | public Tuple6(T0 f0, T1 f1, T2 f2, T3 f3, T4 f4, T5 f5) { 17 | Objects.requireNonNull(f0, "f0 must not be null"); 18 | Objects.requireNonNull(f1, "f1 must not be null"); 19 | Objects.requireNonNull(f2, "f2 must not be null"); 20 | Objects.requireNonNull(f3, "f3 must not be null"); 21 | Objects.requireNonNull(f4, "f4 must not be null"); 22 | Objects.requireNonNull(f5, "f5 must not be null"); 23 | this.field0 = f0; 24 | this.field1 = f1; 25 | this.field2 = f2; 26 | this.field3 = f3; 27 | this.field4 = f4; 28 | this.field5 = f5; 29 | } 30 | 31 | public boolean equals(Object obj) { 32 | if (this == obj) return true; 33 | if (obj == null) return false; 34 | if (getClass() != obj.getClass()) return false; 35 | Tuple6 other = (Tuple6) obj; 36 | if (!Objects.equals(this.field0, other.field0)) { 37 | return false; 38 | } 39 | if (!Objects.equals(this.field1, other.field1)) { 40 | return false; 41 | } 42 | if (!Objects.equals(this.field2, other.field2)) { 43 | return false; 44 | } 45 | if (!Objects.equals(this.field3, other.field3)) { 46 | return false; 47 | } 48 | if (!Objects.equals(this.field4, other.field4)) { 49 | return false; 50 | } 51 | if (!Objects.equals(this.field5, other.field5)) { 52 | return false; 53 | } 54 | return true; 55 | } 56 | 57 | public int hashCode() { 58 | int value = 7; 59 | value = 31 * value + (this.field0 != null ? this.field0.hashCode() : 0); 60 | value = 31 * value + (this.field1 != null ? this.field1.hashCode() : 0); 61 | value = 31 * value + (this.field2 != null ? this.field2.hashCode() : 0); 62 | value = 31 * value + (this.field3 != null ? this.field3.hashCode() : 0); 63 | value = 31 * value + (this.field4 != null ? this.field4.hashCode() : 0); 64 | value = 31 * value + (this.field5 != null ? this.field5.hashCode() : 0); 65 | return value; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Unit.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | public final class Unit { 7 | public Unit() {} 8 | 9 | public boolean equals(Object obj) { 10 | if (this == obj) return true; 11 | if (obj == null) return false; 12 | if (getClass() != obj.getClass()) return false; 13 | return true; 14 | } 15 | 16 | public int hashCode() { 17 | return 7; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /serde-generate/runtime/java/com/novi/serde/Unsigned.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | package com.novi.serde; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Target; 8 | 9 | @Target({ElementType.TYPE_USE}) 10 | public @interface Unsigned { 11 | } 12 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bcs/deserialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | open Common.Misc 5 | include Common.Deserialize 6 | 7 | let max_u32 = 1 lsl 32 - 1 8 | 9 | let char _ = failwith "char deserialization not implemented" 10 | let float32 _ = failwith "float32 deserialization not implemented" 11 | let float64 _ = failwith "float64 deserialization not implemented" 12 | 13 | let uleb128_32 b = 14 | let rec f ~previous_zero acc b i = 15 | let v = uint8 b in 16 | let v = Stdint.Uint8.to_int v.r in 17 | let v_aux = (v land 0x7f) lsl (7 * i) in 18 | let acc = acc + v_aux in 19 | if v land 0x80 <> 0 then f ~previous_zero:(v_aux=0) acc b (i+1) 20 | else if previous_zero && v_aux=0 then failwith "not minimal representation" 21 | else acc in 22 | let i = f ~previous_zero:false 0 b 0 in 23 | if i < 0 || i > max_u32 then failwith "integer above max u32" 24 | else i 25 | 26 | 27 | let length b = 28 | let i = uleb128_32 b in 29 | if i < 0 || i > max_length then failwith "integer above max length" 30 | else i 31 | 32 | let variant_index b = uleb128_32 b 33 | 34 | let variable f b = variable length f b 35 | let string b = string length b 36 | let bytes b = bytes length b 37 | let map ser_k de_k de_v = map length ser_k de_k de_v 38 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bcs/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name bcs_runtime) 3 | (modules serialize deserialize runtime) 4 | (implements runtime)) 5 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bcs/runtime.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | module Serialize = Serialize 5 | module Deserialize = Deserialize 6 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bcs/serialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | open Common.Misc 5 | include Common.Serialize 6 | 7 | let max_depth : int option = Some 500 8 | let max_u32 = 1 lsl 32 - 1 9 | 10 | let char _ = failwith "char serialization not implememted" 11 | let float32 _ = failwith "float32 serialization not implemented" 12 | let float64 _ = failwith "float64 serialization not implemented" 13 | 14 | let uleb128_32 (i : int) = 15 | if i < 0 || i > max_u32 then failwith "integer not in u32 range" 16 | else 17 | let rec f x = 18 | if x < 0x80 then (uint8 (Stdint.Uint8.of_int x)).r 19 | else 20 | Bytes.concat Bytes.empty [ 21 | (uint8 @@ Stdint.Uint8.of_int ((x land 0x7f) lor 0x80)).r; 22 | f (x lsr 7) 23 | ] in 24 | f i 25 | 26 | let length i = 27 | if i > max_length then failwith "integer above max length" 28 | else uleb128_32 i 29 | 30 | let variant_index i = {Common.Misc.r=uleb128_32 i; depth=0} 31 | 32 | let variable f l = variable length f l 33 | let string s = string length s 34 | let bytes b = bytes length b 35 | let map ser_k ser_v m = map length ser_k ser_v m 36 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bincode/deserialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | open Common.Misc 5 | include Common.Deserialize 6 | 7 | let max_length = 1 lsl 31 - 1 8 | 9 | let char b = 10 | let c = Bytes.get b.buffer b.offset in 11 | b.offset <- b.offset + 1; 12 | {Common.Misc.r=c; depth=0} 13 | 14 | let length b = 15 | let i = Stdint.Uint64.to_int @@ (uint64 b).r in 16 | if i < 0 || i > max_length then failwith "integer above max length" 17 | else i 18 | 19 | let variant_index b = Stdint.Uint32.to_int @@ (uint32 b).r 20 | 21 | let float32 b = 22 | let i = int32 b in 23 | { i with r = Stdlib.Int32.float_of_bits i.r } 24 | 25 | let float64 b = 26 | let i = int64 b in 27 | { i with r = Stdlib.Int64.float_of_bits i.r } 28 | 29 | let variable f b = variable length f b 30 | let string b = string length b 31 | let bytes b = bytes length b 32 | let map ser_k de_k de_v b = map length ser_k de_k de_v b 33 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bincode/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name bincode_runtime) 3 | (modules serialize deserialize runtime) 4 | (implements runtime)) 5 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bincode/runtime.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | module Serialize = Serialize 5 | module Deserialize = Deserialize 6 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/bincode/serialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | open Common.Misc 5 | include Common.Serialize 6 | 7 | let max_depth : int option = None 8 | let max_length = 1 lsl 31 - 1 9 | 10 | let char (c : char) = {Common.Misc.r=Bytes.make 1 c; depth=0} 11 | let length i = 12 | if i > max_length then failwith "integer above max length" 13 | else (uint64 @@ Stdint.Uint64.of_int i).r 14 | let variant_index i = uint32 @@ Stdint.Uint32.of_int i 15 | let float32 f = 16 | let i = Stdlib.Int32.bits_of_float f in 17 | int32 i 18 | let float64 f = 19 | let i = Stdlib.Int64.bits_of_float f in 20 | int64 i 21 | 22 | let variable f l = variable length f l 23 | let string s = string length s 24 | let bytes b = bytes length b 25 | let map ser_k ser_v m = map length ser_k ser_v m 26 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/common/deserialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | open Stdint 5 | open Misc 6 | 7 | type b = {buffer : bytes; mutable offset: int} 8 | 9 | let max_length = 1 lsl 31 - 1 10 | 11 | let bool b = 12 | let c = Bytes.get b.buffer b.offset in 13 | let r = 14 | if c = '\001' then true 15 | else if c = '\000' then false 16 | else failwith (Format.sprintf "character %C is not a boolean" c) in 17 | b.offset <- b.offset + 1; 18 | {r; depth=0} 19 | 20 | let uint8 b = 21 | let r = Uint8.of_bytes_little_endian b.buffer b.offset in 22 | b.offset <- b.offset + 1; 23 | {r; depth=0} 24 | 25 | let uint16 b = 26 | let r = Uint16.of_bytes_little_endian b.buffer b.offset in 27 | b.offset <- b.offset + 2; 28 | {r; depth=0} 29 | 30 | let uint32 b = 31 | let r = Uint32.of_bytes_little_endian b.buffer b.offset in 32 | b.offset <- b.offset + 4; 33 | {r; depth=0} 34 | 35 | let uint64 b = 36 | let r = Uint64.of_bytes_little_endian b.buffer b.offset in 37 | b.offset <- b.offset + 8; 38 | {r; depth=0} 39 | 40 | let uint128 b = 41 | let r = Uint128.of_bytes_little_endian b.buffer b.offset in 42 | b.offset <- b.offset + 16; 43 | {r; depth=0} 44 | 45 | let int8 b = 46 | let r = Int8.of_bytes_little_endian b.buffer b.offset in 47 | b.offset <- b.offset + 1; 48 | {r; depth=0} 49 | 50 | let int16 b = 51 | let r = Int16.of_bytes_little_endian b.buffer b.offset in 52 | b.offset <- b.offset + 2; 53 | {r; depth=0} 54 | 55 | let int32 b = 56 | let r = Int32.of_bytes_little_endian b.buffer b.offset in 57 | b.offset <- b.offset + 4; 58 | {r; depth=0} 59 | 60 | let int64 b = 61 | let r = Int64.of_bytes_little_endian b.buffer b.offset in 62 | b.offset <- b.offset + 8; 63 | {r; depth=0} 64 | 65 | let int128 b = 66 | let r = Int128.of_bytes_little_endian b.buffer b.offset in 67 | b.offset <- b.offset + 16; 68 | {r; depth=0} 69 | 70 | let option f b = 71 | let bo = bool b in 72 | if not bo.r then {r=None; depth=0} 73 | else 74 | let r = f b in 75 | {r with r=Some r.r} 76 | 77 | let unit (_ : b) = {r=(); depth=0} 78 | 79 | let fixed f n b = 80 | let rec aux b acc i = 81 | if i = 0 then {acc with r = Array.of_list @@ List.rev acc.r} 82 | else 83 | let x = f b in 84 | let depth = max acc.depth x.depth in 85 | aux b {r=x.r :: acc.r; depth} (i-1) in 86 | aux b {r=[]; depth=0} n 87 | 88 | let variable length f b = 89 | let n = length b in 90 | let rec aux b acc i = 91 | if i = 0 then {acc with r = List.rev acc.r} 92 | else 93 | let x = f b in 94 | let depth = max acc.depth x.depth in 95 | aux b {r=x.r :: acc.r; depth} (i-1) in 96 | aux b {r=[]; depth=0} n 97 | 98 | let is_utf8_string s = 99 | let decoder = Uutf.decoder ~encoding:`UTF_8 (`String s) in 100 | let rec aux decoder = 101 | match Uutf.decode decoder with 102 | | `Uchar _ -> aux decoder 103 | | `End -> true 104 | | `Malformed _ -> false 105 | | `Await -> false in 106 | aux decoder 107 | 108 | let string length b = 109 | let n = length b in 110 | let r = Bytes.sub b.buffer b.offset n in 111 | b.offset <- b.offset + n; 112 | let s = Bytes.to_string r in 113 | if is_utf8_string s then {r=s; depth=0} else failwith "non utf8 string" 114 | 115 | let bytes length b = 116 | let n = length b in 117 | let r = Bytes.sub b.buffer b.offset n in 118 | b.offset <- b.offset + n; 119 | {r; depth=0} 120 | 121 | let map length ser_k de_k de_v b = 122 | let compare k1 k2 = Bytes.compare (ser_k k1).r (ser_k k2).r in 123 | let r = variable length (fun b -> 124 | let (v, k) = de_v b, de_k b in 125 | {depth = max k.depth v.depth; r = (k.r, v.r)}) b in 126 | { r with 127 | r = snd @@ List.fold_left (fun (last_k, acc) (k, v) -> 128 | match last_k with 129 | | Some last_k when compare last_k k >= 0 -> failwith "map not ordered" 130 | | _ -> (Some k, Map.add ~compare k v acc)) (None, Map.empty) r.r } 131 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/common/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name common) 3 | (modules misc map serialize deserialize) 4 | (libraries stdint uutf)) 5 | 6 | (library 7 | (name serde) 8 | (modules serde) 9 | (libraries runtime)) 10 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/common/misc.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | type 'a r = {r: 'a; depth: int} 5 | 6 | let list_depth l = List.fold_left (fun acc x -> max acc x.depth) 0 l 7 | let list_result l = List.map (fun x -> x.r) l 8 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/common/serde.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | module Map = Common.Map 5 | type ('k, 'v) map = ('k, 'v) Map.t 6 | 7 | include Common.Misc 8 | 9 | let max_depth = Runtime.Serialize.max_depth 10 | 11 | let check_depth r = match max_depth with 12 | | Some md when md < r.depth -> failwith (Format.sprintf "depth above %d" md) 13 | | _ -> r 14 | 15 | module Serialize = struct 16 | include Runtime.Serialize 17 | let apply f x = (f x).r 18 | end 19 | 20 | module Deserialize = struct 21 | include Runtime.Deserialize 22 | let check_length b = 23 | if Bytes.length b.buffer <> b.offset then 24 | failwith "buffer not empty" 25 | let apply f buffer = 26 | let b = {buffer; offset=0} in 27 | let r = f b in 28 | let () = check_length b in 29 | r.r 30 | end 31 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/common/serialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | open Stdint 5 | open Misc 6 | 7 | let max_length = 1 lsl 31 - 1 8 | 9 | let bool bo = 10 | if bo then {r=Bytes.make 1 '\001'; depth=0} 11 | else {r=Bytes.make 1 '\000'; depth=0} 12 | 13 | let uint8 (i : uint8) = 14 | let b = Bytes.create 1 in 15 | Uint8.to_bytes_little_endian i b 0; 16 | {r=b; depth=0} 17 | 18 | let uint16 (i : uint16) = 19 | let b = Bytes.create 2 in 20 | Uint16.to_bytes_little_endian i b 0; 21 | {r=b; depth=0} 22 | 23 | let uint32 (i : uint32) = 24 | let b = Bytes.create 4 in 25 | Uint32.to_bytes_little_endian i b 0; 26 | {r=b; depth=0} 27 | 28 | let uint64 (i : uint64) = 29 | let b = Bytes.create 8 in 30 | Uint64.to_bytes_little_endian i b 0; 31 | {r=b; depth=0} 32 | 33 | let uint128 (i : uint128) = 34 | let b = Bytes.create 16 in 35 | Uint128.to_bytes_little_endian i b 0; 36 | {r=b; depth=0} 37 | 38 | let int8 (i : int8) = 39 | let b = Bytes.create 1 in 40 | Int8.to_bytes_little_endian i b 0; 41 | {r=b; depth=0} 42 | 43 | let int16 (i : int16) = 44 | let b = Bytes.create 2 in 45 | Int16.to_bytes_little_endian i b 0; 46 | {r=b; depth=0} 47 | 48 | let int32 (i : int32) = 49 | let b = Bytes.create 4 in 50 | Int32.to_bytes_little_endian i b 0; 51 | {r=b; depth=0} 52 | 53 | let int64 (i : int64) = 54 | let b = Bytes.create 8 in 55 | Int64.to_bytes_little_endian i b 0; 56 | {r=b; depth=0} 57 | 58 | let int128 (i : int128) = 59 | let b = Bytes.create 16 in 60 | Int128.to_bytes_little_endian i b 0; 61 | {r=b; depth=0} 62 | 63 | let option f = function 64 | | None -> bool false 65 | | Some x -> 66 | let r = f x in 67 | {r with r=Bytes.concat Bytes.empty [ (bool true).r; r.r ]} 68 | 69 | let unit () = 70 | {r=Bytes.empty; depth=0} 71 | 72 | let concat l = 73 | let depth = list_depth l in 74 | {depth; r = Bytes.concat Bytes.empty @@ list_result l} 75 | 76 | let fixed f a = 77 | concat @@ Array.to_list @@ Array.map f a 78 | 79 | let variable length f l = 80 | concat @@ {r=length (List.length l); depth=0} :: (List.rev @@ List.rev_map f l) 81 | 82 | let string length s = 83 | { r = Bytes.concat Bytes.empty [ length (String.length s); Bytes.of_string s ]; depth=0 } 84 | 85 | let bytes length b = 86 | { r = Bytes.concat Bytes.empty [ length (Bytes.length b); b ]; depth = 0 } 87 | 88 | let map length fk fv m = 89 | variable length (fun (k, v) -> concat [ fk k; fv v ]) @@ Map.bindings m 90 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/dune: -------------------------------------------------------------------------------- 1 | (env (_ (flags (:standard -w +a-4-41-44-45-48-70 -warn-error -a)))) 2 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 3.0) 2 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/ppx/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name ppx) 3 | (modules ppx) 4 | (kind ppx_deriver) 5 | (ppx_runtime_libraries serde) 6 | (libraries ppxlib)) 7 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/serde/deserialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | include Common.Deserialize 5 | 6 | let char _ = failwith "char deserialization not implemented" 7 | let length _ = failwith "length deserialization not implemented" 8 | let variant_index _ = failwith "variant_index deserialization not implemented" 9 | let float32 _ = failwith "float32 deserialization not implemented" 10 | let float64 _ = failwith "float64 deserialization not implemented" 11 | 12 | let variable f b = variable length f b 13 | let string b = string length b 14 | let bytes b = bytes length b 15 | let map ser_k de_k de_v = map length ser_k de_k de_v 16 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/serde/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name serde_runtime) 3 | (modules serialize deserialize runtime) 4 | (implements runtime)) 5 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/serde/runtime.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | module Serialize = Serialize 5 | module Deserialize = Deserialize 6 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/serde/serialize.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) Zefchain Labs, Inc. 2 | * SPDX-License-Identifier: MIT OR Apache-2.0 *) 3 | 4 | include Common.Serialize 5 | 6 | let max_depth : int option = None 7 | 8 | let char _ = failwith "char serialization not implememted" 9 | let length _ = failwith "length serialization not implemented" 10 | let variant_index _ = failwith "variant_index serialization not implemented" 11 | let float32 _ = failwith "float32 serialization not implemented" 12 | let float64 _ = failwith "float64 serialization not implemented" 13 | 14 | let variable f l = variable length f l 15 | let string s = string length s 16 | let bytes b = bytes length b 17 | let map ser_k ser_v m = map length ser_k ser_v m 18 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/test/dune: -------------------------------------------------------------------------------- 1 | (test 2 | (name test_bcs) 3 | (modules test_bcs) 4 | (preprocess (pps ppx)) 5 | (libraries alcotest bcs_runtime)) 6 | 7 | (test 8 | (name test_bincode) 9 | (modules test_bincode) 10 | (preprocess (pps ppx)) 11 | (libraries alcotest bincode_runtime)) 12 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/virtual/deserialize.mli: -------------------------------------------------------------------------------- 1 | open Stdint 2 | 3 | type b = {buffer : bytes; mutable offset: int} 4 | 5 | val bool : b -> bool Common.Misc.r 6 | val uint8 : b -> uint8 Common.Misc.r 7 | val uint16 : b -> uint16 Common.Misc.r 8 | val uint32 : b -> uint32 Common.Misc.r 9 | val uint64 : b -> uint64 Common.Misc.r 10 | val uint128 : b -> uint128 Common.Misc.r 11 | val int8 : b -> int8 Common.Misc.r 12 | val int16 : b -> int16 Common.Misc.r 13 | val int32 : b -> int32 Common.Misc.r 14 | val int64 : b -> int64 Common.Misc.r 15 | val int128 : b -> int128 Common.Misc.r 16 | val option : (b -> 'a Common.Misc.r) -> b -> 'a option Common.Misc.r 17 | val unit : b -> unit Common.Misc.r 18 | val fixed : (b -> 'a Common.Misc.r) -> int -> b -> 'a array Common.Misc.r 19 | 20 | val char : b -> char Common.Misc.r 21 | val length : b -> int 22 | val variant_index : b -> int 23 | val float32 : b -> float Common.Misc.r 24 | val float64 : b -> float Common.Misc.r 25 | val variable : (b -> 'a Common.Misc.r) -> b -> 'a list Common.Misc.r 26 | val string : b -> string Common.Misc.r 27 | val bytes : b -> bytes Common.Misc.r 28 | val map : ('k -> bytes Common.Misc.r) -> (b -> 'k Common.Misc.r) -> (b -> 'v Common.Misc.r) -> b -> ('k, 'v) Common.Map.t Common.Misc.r 29 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/virtual/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name runtime) 3 | (virtual_modules serialize deserialize runtime) 4 | (libraries common) 5 | (default_implementation serde_runtime)) 6 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/virtual/runtime.mli: -------------------------------------------------------------------------------- 1 | module Serialize = Serialize 2 | module Deserialize = Deserialize 3 | -------------------------------------------------------------------------------- /serde-generate/runtime/ocaml/virtual/serialize.mli: -------------------------------------------------------------------------------- 1 | open Stdint 2 | 3 | val max_depth: int option 4 | val concat : bytes Common.Misc.r list -> bytes Common.Misc.r 5 | 6 | val bool : bool -> bytes Common.Misc.r 7 | val uint8 : uint8 -> bytes Common.Misc.r 8 | val uint16 : uint16 -> bytes Common.Misc.r 9 | val uint32 : uint32 -> bytes Common.Misc.r 10 | val uint64 : uint64 -> bytes Common.Misc.r 11 | val uint128 : uint128 -> bytes Common.Misc.r 12 | val int8 : int8 -> bytes Common.Misc.r 13 | val int16 : int16 -> bytes Common.Misc.r 14 | val int32 : int32 -> bytes Common.Misc.r 15 | val int64 : int64 -> bytes Common.Misc.r 16 | val int128 : int128 -> bytes Common.Misc.r 17 | val option : ('a -> bytes Common.Misc.r) -> 'a option -> bytes Common.Misc.r 18 | val unit : unit -> bytes Common.Misc.r 19 | val fixed : ('a -> bytes Common.Misc.r) -> 'a array -> bytes Common.Misc.r 20 | 21 | val char : char -> bytes Common.Misc.r 22 | val length : int -> bytes 23 | val variant_index : int -> bytes Common.Misc.r 24 | val float32 : float -> bytes Common.Misc.r 25 | val float64 : float -> bytes Common.Misc.r 26 | val variable : ('a -> bytes Common.Misc.r) -> 'a list -> bytes Common.Misc.r 27 | val string : string -> bytes Common.Misc.r 28 | val bytes : bytes -> bytes Common.Misc.r 29 | val map : ('k -> bytes Common.Misc.r) -> ('v -> bytes Common.Misc.r) -> ('k, 'v) Common.Map.t -> bytes Common.Misc.r 30 | -------------------------------------------------------------------------------- /serde-generate/runtime/python/bcs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates 2 | # SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import dataclasses 5 | import collections 6 | import io 7 | import typing 8 | from copy import copy 9 | from typing import get_type_hints 10 | 11 | import serde_types as st 12 | import serde_binary as sb 13 | 14 | MAX_LENGTH = (1 << 31) - 1 15 | MAX_U32 = (1 << 32) - 1 16 | MAX_CONTAINER_DEPTH = 500 17 | 18 | 19 | class BcsSerializer(sb.BinarySerializer): 20 | def __init__(self): 21 | super().__init__( 22 | output=io.BytesIO(), container_depth_budget=MAX_CONTAINER_DEPTH 23 | ) 24 | 25 | def serialize_u32_as_uleb128(self, value: int): 26 | while value >= 0x80: 27 | b = (value & 0x7F) | 0x80 28 | self.output.write(b.to_bytes(1, "little", signed=False)) 29 | value >>= 7 30 | self.output.write(value.to_bytes(1, "little", signed=False)) 31 | 32 | def serialize_len(self, value: int): 33 | if value > MAX_LENGTH: 34 | raise st.SerializationError("Length exceeds the maximum supported value.") 35 | self.serialize_u32_as_uleb128(value) 36 | 37 | def serialize_variant_index(self, value: int): 38 | if value > MAX_U32: 39 | raise st.SerializationError( 40 | "Variant index exceeds the maximum supported value." 41 | ) 42 | self.serialize_u32_as_uleb128(value) 43 | 44 | def sort_map_entries(self, offsets: typing.List[int]): 45 | if len(offsets) < 1: 46 | return 47 | buf = self.output.getbuffer() 48 | offsets.append(len(buf)) 49 | slices = [] 50 | for i in range(1, len(offsets)): 51 | slices.append(bytes(buf[offsets[i - 1] : offsets[i]])) 52 | buf.release() 53 | slices.sort() 54 | self.output.seek(offsets[0]) 55 | for s in slices: 56 | self.output.write(s) 57 | assert offsets[-1] == len(self.output.getbuffer()) 58 | 59 | 60 | class BcsDeserializer(sb.BinaryDeserializer): 61 | def __init__(self, content): 62 | super().__init__( 63 | input=io.BytesIO(content), container_depth_budget=MAX_CONTAINER_DEPTH 64 | ) 65 | 66 | def deserialize_uleb128_as_u32(self) -> int: 67 | value = 0 68 | for shift in range(0, 32, 7): 69 | byte = int.from_bytes(self.read(1), "little", signed=False) 70 | digit = byte & 0x7F 71 | value |= digit << shift 72 | if value > MAX_U32: 73 | raise st.DeserializationError( 74 | "Overflow while parsing uleb128-encoded uint32 value" 75 | ) 76 | if digit == byte: 77 | if shift > 0 and digit == 0: 78 | raise st.DeserializationError( 79 | "Invalid uleb128 number (unexpected zero digit)" 80 | ) 81 | return value 82 | 83 | raise st.DeserializationError( 84 | "Overflow while parsing uleb128-encoded uint32 value" 85 | ) 86 | 87 | def deserialize_len(self) -> int: 88 | value = self.deserialize_uleb128_as_u32() 89 | if value > MAX_LENGTH: 90 | raise st.DeserializationError("Length exceeds the maximum supported value.") 91 | return value 92 | 93 | def deserialize_variant_index(self) -> int: 94 | return self.deserialize_uleb128_as_u32() 95 | 96 | def check_that_key_slices_are_increasing( 97 | self, slice1: typing.Tuple[int, int], slice2: typing.Tuple[int, int] 98 | ): 99 | key1 = bytes(self.input.getbuffer()[slice1[0] : slice1[1]]) 100 | key2 = bytes(self.input.getbuffer()[slice2[0] : slice2[1]]) 101 | if key1 >= key2: 102 | raise st.DeserializationError( 103 | "Serialized keys in a map must be ordered by increasing lexicographic order" 104 | ) 105 | 106 | 107 | def serialize(obj: typing.Any, obj_type) -> bytes: 108 | serializer = BcsSerializer() 109 | serializer.serialize_any(obj, obj_type) 110 | return serializer.get_buffer() 111 | 112 | 113 | def deserialize(content: bytes, obj_type) -> typing.Tuple[typing.Any, bytes]: 114 | deserializer = BcsDeserializer(content) 115 | value = deserializer.deserialize_any(obj_type) 116 | return value, deserializer.get_remaining_buffer() 117 | -------------------------------------------------------------------------------- /serde-generate/runtime/python/bincode/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates 2 | # SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import dataclasses 5 | import collections 6 | import io 7 | import struct 8 | import typing 9 | from copy import copy 10 | from typing import get_type_hints 11 | 12 | import serde_types as st 13 | import serde_binary as sb 14 | 15 | # Maximum length in practice for sequences (e.g. in Java). 16 | MAX_LENGTH = (1 << 31) - 1 17 | 18 | 19 | class BincodeSerializer(sb.BinarySerializer): 20 | def __init__(self): 21 | super().__init__(output=io.BytesIO(), container_depth_budget=None) 22 | 23 | def serialize_f32(self, value: st.float32): 24 | self.output.write(struct.pack(" MAX_LENGTH: 31 | raise st.SerializationError("Length exceeds the maximum supported value.") 32 | self.output.write(int(value).to_bytes(8, "little", signed=False)) 33 | 34 | def serialize_variant_index(self, value: int): 35 | self.output.write(int(value).to_bytes(4, "little", signed=False)) 36 | 37 | def sort_map_entries(self, offsets: typing.List[int]): 38 | pass 39 | 40 | 41 | class BincodeDeserializer(sb.BinaryDeserializer): 42 | def __init__(self, content): 43 | super().__init__(input=io.BytesIO(content), container_depth_budget=None) 44 | 45 | def deserialize_f32(self) -> st.float32: 46 | (value,) = struct.unpack(" st.float64: 50 | (value,) = struct.unpack(" int: 54 | value = int.from_bytes(self.read(8), byteorder="little", signed=False) 55 | if value > MAX_LENGTH: 56 | raise st.DeserializationError("Length exceeds the maximum supported value.") 57 | return value 58 | 59 | def deserialize_variant_index(self) -> int: 60 | return int.from_bytes(self.read(4), byteorder="little", signed=False) 61 | 62 | def check_that_key_slices_are_increasing( 63 | self, slice1: typing.Tuple[int, int], slice2: typing.Tuple[int, int] 64 | ): 65 | pass 66 | 67 | 68 | def serialize(obj: typing.Any, obj_type) -> bytes: 69 | serializer = BincodeSerializer() 70 | serializer.serialize_any(obj, obj_type) 71 | return serializer.get_buffer() 72 | 73 | 74 | def deserialize(content: bytes, obj_type) -> typing.Tuple[typing.Any, bytes]: 75 | deserializer = BincodeDeserializer(content) 76 | value = deserializer.deserialize_any(obj_type) 77 | return value, deserializer.get_remaining_buffer() 78 | -------------------------------------------------------------------------------- /serde-generate/runtime/python/serde_types/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates 2 | # SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import numpy as np 5 | from dataclasses import dataclass 6 | import typing 7 | 8 | 9 | class SerializationError(ValueError): 10 | """Error raised during Serialization""" 11 | 12 | pass 13 | 14 | 15 | class DeserializationError(ValueError): 16 | """Error raised during Deserialization""" 17 | 18 | pass 19 | 20 | 21 | @dataclass(init=False) 22 | class uint128: 23 | high: np.uint64 24 | low: np.uint64 25 | 26 | def __init__(self, num): 27 | self.high = np.uint64(num >> 64) 28 | self.low = np.uint64(num & 0xFFFFFFFFFFFFFFFF) 29 | 30 | def __int__(self): 31 | return (int(self.high) << 64) | int(self.low) 32 | 33 | 34 | @dataclass(init=False) 35 | class int128: 36 | high: np.int64 37 | low: np.uint64 38 | 39 | def __init__(self, num): 40 | self.high = np.int64(num >> 64) 41 | self.low = np.uint64(num & 0xFFFFFFFFFFFFFFFF) 42 | 43 | def __int__(self): 44 | return (int(self.high) << 64) | int(self.low) 45 | 46 | 47 | @dataclass(init=False) 48 | class char: 49 | value: str 50 | 51 | def __init__(self, s): 52 | if len(s) != 1: 53 | raise ValueError("`char` expects a single unicode character") 54 | self.value = s 55 | 56 | def __str__(self): 57 | return self.value 58 | 59 | 60 | unit = typing.Type[None] 61 | 62 | bool = bool 63 | int8 = np.int8 64 | int16 = np.int16 65 | int32 = np.int32 66 | int64 = np.int64 67 | 68 | uint8 = np.uint8 69 | uint16 = np.uint16 70 | uint32 = np.uint32 71 | uint64 = np.uint64 72 | 73 | float32 = np.float32 74 | float64 = np.float64 75 | -------------------------------------------------------------------------------- /serde-generate/runtime/python/serde_types/test_serde_types.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates 2 | # SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | import unittest 5 | import serde_types as st 6 | 7 | 8 | class SerdeTypesTestCase(unittest.TestCase): 9 | def test_u128(self): 10 | x = 0x0102030405060708090A0B0C0D0E0F10 11 | y = st.uint128(x) 12 | self.assertEqual(y.high, 0x0102030405060708) 13 | self.assertEqual(y.low, 0x090A0B0C0D0E0F10) 14 | self.assertEqual(int(y), x) 15 | 16 | def test_i128_positive(self): 17 | x = 0x0102030405060708090A0B0C0D0E0F10 18 | y = st.int128(x) 19 | self.assertEqual(y.high, 0x0102030405060708) 20 | self.assertEqual(y.low, 0x090A0B0C0D0E0F10) 21 | self.assertEqual(int(y), x) 22 | 23 | def test_i128_negative(self): 24 | x = -2 25 | y = st.int128(x) 26 | self.assertEqual(y.high, -1) 27 | self.assertEqual(y.low, 0xFFFFFFFFFFFFFFFE) 28 | self.assertEqual(int(y), x) 29 | 30 | def test_char(self): 31 | self.assertEqual(str(st.char("a")), "a") 32 | with self.assertRaises(ValueError): 33 | st.char("ab") 34 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | Package.resolved 9 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // Copyright (c) Facebook, Inc. and its affiliates. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Serde", 8 | products: [ 9 | // Products define the executables and libraries a package produces, and make them visible to other packages. 10 | .library( 11 | name: "Serde", 12 | targets: ["Serde"] 13 | ), 14 | ], 15 | dependencies: [ 16 | // Dependencies declare other packages that this package depends on. 17 | // .package(url: /* package url */, from: "1.0.0"), 18 | ], 19 | targets: [ 20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 21 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 22 | .target( 23 | name: "Serde", 24 | dependencies: [] 25 | ), 26 | .testTarget( 27 | name: "SerdeTests", 28 | dependencies: ["Serde"] 29 | ), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/README.md: -------------------------------------------------------------------------------- 1 | # serde 2 | 3 | Provides bincode and BCS serialization runtimes for the data structures generated by `serde-generate`. 4 | 5 | Currently tested under Linux with Swift 5.3 only because of https://bugs.swift.org/browse/SR-14659 6 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/BcsDeserializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public class BcsDeserializer: BinaryDeserializer { 6 | public let MAX_LENGTH: Int = 1 << 31 - 1 7 | public let MAX_CONTAINER_DEPTH: Int = 500 8 | 9 | public init(input: [UInt8]) { 10 | super.init(input: input, maxContainerDepth: MAX_CONTAINER_DEPTH) 11 | } 12 | 13 | private func deserialize_uleb128_as_u32() throws -> UInt32 { 14 | var value: UInt64 = 0 15 | for shift in stride(from: 0, to: 32, by: 7) { 16 | let x = try deserialize_u8() 17 | let digit = x & 0x7F 18 | value |= UInt64(digit) << shift 19 | if value > UInt32.max { 20 | throw DeserializationError.invalidInput(issue: "Overflow while parsing uleb128-encoded uint32 value") 21 | } 22 | if digit == x { 23 | if shift > 0, digit == 0 { 24 | throw DeserializationError.invalidInput(issue: "Invalid uleb128 number (unexpected zero digit)") 25 | } 26 | return UInt32(value) 27 | } 28 | } 29 | throw DeserializationError.invalidInput(issue: "Overflow while parsing uleb128-encoded uint32 value") 30 | } 31 | 32 | override public func deserialize_len() throws -> Int { 33 | let value = try deserialize_uleb128_as_u32() 34 | if value > MAX_LENGTH { 35 | throw DeserializationError.invalidInput(issue: "Overflow while parsing length value") 36 | } 37 | return Int(value) 38 | } 39 | 40 | override public func deserialize_variant_index() throws -> UInt32 { 41 | return try deserialize_uleb128_as_u32() 42 | } 43 | 44 | override public func check_that_key_slices_are_increasing(key1: Slice, key2: Slice) throws { 45 | guard input[key1.start ..< key1.end].lexicographicallyPrecedes(input[key2.start ..< key2.end]) else { 46 | throw DeserializationError.invalidInput(issue: "Invalid ordering of keys") 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/BcsSerializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public class BcsSerializer: BinarySerializer { 6 | public let MAX_LENGTH: Int = 1 << 31 - 1 7 | public let MAX_CONTAINER_DEPTH: Int = 500 8 | 9 | public init() { 10 | super.init(maxContainerDepth: MAX_CONTAINER_DEPTH) 11 | } 12 | 13 | private func serialize_u32_as_uleb128(value: UInt32) throws { 14 | var input = value 15 | while input >= 0x80 { 16 | writeByte(UInt8((value & 0x7F) | 0x80)) 17 | input >>= 7 18 | } 19 | writeByte(UInt8(input)) 20 | } 21 | 22 | override public func serialize_len(value: Int) throws { 23 | if value < 0 || value > MAX_LENGTH { 24 | throw SerializationError.invalidValue(issue: "Invalid length value") 25 | } 26 | try serialize_u32_as_uleb128(value: UInt32(value)) 27 | } 28 | 29 | override public func serialize_variant_index(value: UInt32) throws { 30 | try serialize_u32_as_uleb128(value: value) 31 | } 32 | 33 | override public func sort_map_entries(offsets: [Int]) { 34 | if offsets.count <= 1 { 35 | return 36 | } 37 | let offset0 = offsets[0] 38 | var slices: [Slice] = [] 39 | slices.reserveCapacity(offsets.count) 40 | for i in 0 ..< (offsets.count - 1) { 41 | slices.append(Slice(start: offsets[i], end: offsets[i + 1])) 42 | } 43 | slices.append(Slice(start: offsets[offsets.count - 1], end: output.count)) 44 | slices.sort(by: { key1, key2 in 45 | output[key1.start ..< key1.end].lexicographicallyPrecedes(output[key2.start ..< key2.end]) 46 | }) 47 | 48 | let content = output 49 | var position = offset0 50 | for slice in slices { 51 | for i in slice.start ..< slice.end { 52 | output[position] = content[i] 53 | position += 1 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/BincodeDeserializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public class BincodeDeserializer: BinaryDeserializer { 6 | public let MAX_LENGTH: Int = 1 << 31 - 1 7 | 8 | public init(input: [UInt8]) { 9 | super.init(input: input, maxContainerDepth: Int.max) 10 | } 11 | 12 | override public func deserialize_len() throws -> Int { 13 | let value = try deserialize_i64() 14 | if value < 0 || value > MAX_LENGTH { 15 | throw DeserializationError.invalidInput(issue: "Incorrect length value") 16 | } 17 | return Int(value) 18 | } 19 | 20 | override public func deserialize_f32() throws -> Float { 21 | let num = try deserialize_u32() 22 | return Float(bitPattern: num) 23 | } 24 | 25 | override public func deserialize_f64() throws -> Double { 26 | let num = try deserialize_u64() 27 | return Double(bitPattern: num) 28 | } 29 | 30 | override public func deserialize_variant_index() throws -> UInt32 { 31 | return try deserialize_u32() 32 | } 33 | 34 | override public func check_that_key_slices_are_increasing(key1 _: Slice, key2 _: Slice) throws { 35 | // Nothing to do 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/BincodeSerializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public class BincodeSerializer: BinarySerializer { 6 | public let MAX_LENGTH: Int = 1 << 31 - 1 7 | 8 | public init() { 9 | super.init(maxContainerDepth: Int.max) 10 | } 11 | 12 | override public func serialize_len(value: Int) throws { 13 | if value < 0 || value > MAX_LENGTH { 14 | throw SerializationError.invalidValue(issue: "Invalid length value") 15 | } 16 | try serialize_u64(value: UInt64(value)) 17 | } 18 | 19 | override public func serialize_f32(value: Float) throws { 20 | try serialize_u32(value: value.bitPattern) 21 | } 22 | 23 | override public func serialize_f64(value: Double) throws { 24 | try serialize_u64(value: value.bitPattern) 25 | } 26 | 27 | override public func serialize_variant_index(value: UInt32) throws { 28 | try serialize_u32(value: value) 29 | } 30 | 31 | override public func sort_map_entries(offsets _: [Int]) { 32 | // Not required by the format. 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Deserializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public enum DeserializationError: Error { 6 | case invalidInput(issue: String) 7 | } 8 | 9 | public protocol Deserializer { 10 | func deserialize_str() throws -> String 11 | func deserialize_bytes() throws -> [UInt8] 12 | func deserialize_bool() throws -> Bool 13 | func deserialize_unit() throws -> Unit 14 | func deserialize_char() throws -> Character 15 | func deserialize_f32() throws -> Float 16 | func deserialize_f64() throws -> Double 17 | func deserialize_u8() throws -> UInt8 18 | func deserialize_u16() throws -> UInt16 19 | func deserialize_u32() throws -> UInt32 20 | func deserialize_u64() throws -> UInt64 21 | func deserialize_u128() throws -> UInt128 22 | func deserialize_i8() throws -> Int8 23 | func deserialize_i16() throws -> Int16 24 | func deserialize_i32() throws -> Int32 25 | func deserialize_i64() throws -> Int64 26 | func deserialize_i128() throws -> Int128 27 | func deserialize_len() throws -> Int 28 | func deserialize_variant_index() throws -> UInt32 29 | func deserialize_option_tag() throws -> Bool 30 | func get_buffer_offset() -> Int 31 | func check_that_key_slices_are_increasing(key1: Slice, key2: Slice) throws 32 | func increase_container_depth() throws 33 | func decrease_container_depth() throws 34 | } 35 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Indirect.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | // See https://forums.swift.org/t/using-indirect-modifier-for-struct-properties/37600/16 4 | @propertyWrapper 5 | public enum Indirect: Hashable where T: Hashable { 6 | indirect case wrapped(T) 7 | 8 | public init(wrappedValue initialValue: T) { 9 | self = .wrapped(initialValue) 10 | } 11 | 12 | public var wrappedValue: T { 13 | get { switch self { case let .wrapped(x): return x } } 14 | set { self = .wrapped(newValue) } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Int128.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public struct Int128: Hashable { 6 | public var high: Int64 7 | public var low: UInt64 8 | 9 | public init(high: Int64, low: UInt64) { 10 | self.high = high 11 | self.low = low 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Serializer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public enum SerializationError: Error { 6 | case invalidValue(issue: String) 7 | } 8 | 9 | public protocol Serializer { 10 | func serialize_str(value: String) throws 11 | func serialize_bytes(value: [UInt8]) throws 12 | func serialize_bool(value: Bool) throws 13 | func serialize_unit(value: Unit) throws 14 | func serialize_char(value: Character) throws 15 | func serialize_f32(value: Float) throws 16 | func serialize_f64(value: Double) throws 17 | func serialize_u8(value: UInt8) throws 18 | func serialize_u16(value: UInt16) throws 19 | func serialize_u32(value: UInt32) throws 20 | func serialize_u64(value: UInt64) throws 21 | func serialize_u128(value: UInt128) throws 22 | func serialize_i8(value: Int8) throws 23 | func serialize_i16(value: Int16) throws 24 | func serialize_i32(value: Int32) throws 25 | func serialize_i64(value: Int64) throws 26 | func serialize_i128(value: Int128) throws 27 | func serialize_len(value: Int) throws 28 | func serialize_variant_index(value: UInt32) throws 29 | func serialize_option_tag(value: Bool) throws 30 | func increase_container_depth() throws 31 | func decrease_container_depth() throws 32 | func get_buffer_offset() -> Int 33 | func sort_map_entries(offsets: [Int]) 34 | func get_bytes() -> [UInt8] 35 | } 36 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Slice.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public struct Slice: Equatable { 6 | public var start: Int 7 | public var end: Int 8 | 9 | public init(start: Int, end: Int) { 10 | self.start = start 11 | self.end = end 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Tuple2.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | // Swift tuples are not properly equatable or hashable. This ruins our data model so we must use homemade structs as in Java. 6 | 7 | public struct Tuple2: Hashable { 8 | public var field0: T0 9 | public var field1: T1 10 | 11 | public init(_ field0: T0, _ field1: T1) { 12 | self.field0 = field0 13 | self.field1 = field1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Tuple3.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | // Swift tuples are not properly equatable or hashable. This ruins our data model so we must use homemade structs as in Java. 6 | 7 | public struct Tuple3: Hashable { 8 | public var field0: T0 9 | public var field1: T1 10 | public var field2: T2 11 | 12 | public init(_ field0: T0, _ field1: T1, _ field2: T2) { 13 | self.field0 = field0 14 | self.field1 = field1 15 | self.field2 = field2 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Tuple4.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | // Swift tuples are not properly equatable or hashable. This ruins our data model so we must use homemade structs as in Java. 6 | 7 | public struct Tuple4: Hashable { 8 | public var field0: T0 9 | public var field1: T1 10 | public var field2: T2 11 | public var field3: T3 12 | 13 | public init(_ field0: T0, _ field1: T1, _ field2: T2, _ field3: T3) { 14 | self.field0 = field0 15 | self.field1 = field1 16 | self.field2 = field2 17 | self.field3 = field3 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Tuple5.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | // Swift tuples are not properly equatable or hashable. This ruins our data model so we must use homemade structs as in Java. 6 | 7 | public struct Tuple5: Hashable { 8 | public var field0: T0 9 | public var field1: T1 10 | public var field2: T2 11 | public var field3: T3 12 | public var field4: T4 13 | 14 | public init(_ field0: T0, _ field1: T1, _ field2: T2, _ field3: T3, _ field4: T4) { 15 | self.field0 = field0 16 | self.field1 = field1 17 | self.field2 = field2 18 | self.field3 = field3 19 | self.field4 = field4 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Tuple6.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | // Swift tuples are not properly equatable or hashable. This ruins our data model so we must use homemade structs as in Java. 6 | 7 | public struct Tuple6: Hashable { 8 | public var field0: T0 9 | public var field1: T1 10 | public var field2: T2 11 | public var field3: T3 12 | public var field4: T4 13 | public var field5: T5 14 | 15 | public init(_ field0: T0, _ field1: T1, _ field2: T2, _ field3: T3, _ field4: T4, _ field5: T5) { 16 | self.field0 = field0 17 | self.field1 = field1 18 | self.field2 = field2 19 | self.field3 = field3 20 | self.field4 = field4 21 | self.field5 = field5 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/UInt128.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | public struct UInt128: Hashable { 6 | public var high: UInt64 7 | public var low: UInt64 8 | 9 | public init(high: UInt64, low: UInt64) { 10 | self.high = high 11 | self.low = low 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Sources/Serde/Unit.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import Foundation 4 | 5 | // Defining Unit as () creates all sorts of warnings in the generated code. 6 | 7 | public struct Unit: Hashable {} 8 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | import XCTest 4 | 5 | import SerdeTests 6 | 7 | var tests = [XCTestCaseEntry]() 8 | tests += SerdeTests.__allTests() 9 | 10 | XCTMain(tests) 11 | -------------------------------------------------------------------------------- /serde-generate/runtime/swift/Tests/SerdeTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. 2 | 3 | #if !canImport(ObjectiveC) 4 | import XCTest 5 | 6 | extension SerdeTests { 7 | // DO NOT MODIFY: This is autogenerated, use: 8 | // `swift test --generate-linuxmain` 9 | // to regenerate. 10 | static let __allTests__SerdeTests = [ 11 | ("testCheckThatKeySlicesAreIncreasing", testCheckThatKeySlicesAreIncreasing), 12 | ("testDeserializer", testDeserializer), 13 | ("testSerializeI128", testSerializeI128), 14 | ("testSerializeInt16", testSerializeInt16), 15 | ("testSerializeInt32", testSerializeInt32), 16 | ("testSerializeInt64", testSerializeInt64), 17 | ("testSerializeInt8", testSerializeInt8), 18 | ("testSerializer", testSerializer), 19 | ("testSerializeU128", testSerializeU128), 20 | ("testSerializeUint16", testSerializeUint16), 21 | ("testSerializeUint32", testSerializeUint32), 22 | ("testSerializeUint8", testSerializeUint8), 23 | ("testSortMapEntries", testSortMapEntries), 24 | ("testULEB128Encoding", testULEB128Encoding), 25 | ] 26 | } 27 | 28 | public func __allTests() -> [XCTestCaseEntry] { 29 | return [ 30 | testCase(SerdeTests.__allTests__SerdeTests), 31 | ] 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/bcs/bcsDeserializer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | import { BinaryDeserializer } from "../serde/binaryDeserializer.ts"; 7 | 8 | export class BcsDeserializer extends BinaryDeserializer { 9 | private static readonly MAX_UINT_32 = 2 ** 32 - 1; 10 | 11 | public deserializeUleb128AsU32(): number { 12 | let value = 0; 13 | for (let shift = 0; shift < 32; shift += 7) { 14 | const x = this.deserializeU8(); 15 | const digit = x & 0x7f; 16 | value = value | (digit << shift); 17 | if (value < 0 || value > BcsDeserializer.MAX_UINT_32) { 18 | throw new Error("Overflow while parsing uleb128-encoded uint32 value"); 19 | } 20 | if (digit == x) { 21 | if (shift > 0 && digit == 0) { 22 | throw new Error("Invalid uleb128 number (unexpected zero digit)"); 23 | } 24 | return value; 25 | } 26 | } 27 | throw new Error("Overflow while parsing uleb128-encoded uint32 value"); 28 | } 29 | 30 | deserializeLen(): number { 31 | return this.deserializeUleb128AsU32(); 32 | } 33 | 34 | public deserializeVariantIndex(): number { 35 | return this.deserializeUleb128AsU32(); 36 | } 37 | 38 | public checkThatKeySlicesAreIncreasing( 39 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 40 | _key1: [number, number], 41 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 42 | _key2: [number, number], 43 | ): void { 44 | // TODO(#58) 45 | return; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/bcs/bcsSerializer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | import { BinarySerializer } from "../serde/binarySerializer.ts"; 7 | 8 | export class BcsSerializer extends BinarySerializer { 9 | public serializeU32AsUleb128(value: number): void { 10 | const valueArray = []; 11 | while (value >>> 7 != 0) { 12 | valueArray.push((value & 0x7f) | 0x80); 13 | value = value >>> 7; 14 | } 15 | valueArray.push(value); 16 | this.serialize(new Uint8Array(valueArray)); 17 | } 18 | 19 | serializeLen(value: number): void { 20 | this.serializeU32AsUleb128(value); 21 | } 22 | 23 | public serializeVariantIndex(value: number): void { 24 | this.serializeU32AsUleb128(value); 25 | } 26 | 27 | public sortMapEntries(_offsets: number[]) { 28 | // TODO(#58) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/bcs/mod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | export * from "./bcsSerializer.ts"; 7 | export * from "./bcsDeserializer.ts"; 8 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/bincode/bincodeDeserializer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | import { BinaryDeserializer } from "../serde/binaryDeserializer.ts"; 7 | 8 | export class BincodeDeserializer extends BinaryDeserializer { 9 | deserializeLen(): number { 10 | return Number(this.deserializeU64()); 11 | } 12 | 13 | public deserializeVariantIndex(): number { 14 | return this.deserializeU32(); 15 | } 16 | 17 | checkThatKeySlicesAreIncreasing( 18 | key1: [number, number], 19 | key2: [number, number], 20 | ): void { 21 | return; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/bincode/bincodeSerializer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | import { BinarySerializer } from "../serde/binarySerializer.ts"; 7 | 8 | export class BincodeSerializer extends BinarySerializer { 9 | serializeLen(value: number): void { 10 | this.serializeU64(value); 11 | } 12 | 13 | public serializeVariantIndex(value: number): void { 14 | this.serializeU32(value); 15 | } 16 | 17 | public sortMapEntries(offsets: number[]): void { 18 | return; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/bincode/mod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | export { BincodeSerializer } from "./bincodeSerializer.ts"; 7 | export { BincodeDeserializer } from "./bincodeDeserializer.ts"; 8 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/serde/deserializer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | export interface Deserializer { 7 | deserializeStr(): string; 8 | 9 | deserializeBytes(): Uint8Array; 10 | 11 | deserializeBool(): boolean; 12 | 13 | deserializeUnit(): null; 14 | 15 | deserializeChar(): string; 16 | 17 | deserializeF32(): number; 18 | 19 | deserializeF64(): number; 20 | 21 | deserializeU8(): number; 22 | 23 | deserializeU16(): number; 24 | 25 | deserializeU32(): number; 26 | 27 | deserializeU64(): bigint; 28 | 29 | deserializeU128(): bigint; 30 | 31 | deserializeI8(): number; 32 | 33 | deserializeI16(): number; 34 | 35 | deserializeI32(): number; 36 | 37 | deserializeI64(): bigint; 38 | 39 | deserializeI128(): bigint; 40 | 41 | deserializeLen(): number; 42 | 43 | deserializeVariantIndex(): number; 44 | 45 | deserializeOptionTag(): boolean; 46 | 47 | getBufferOffset(): number; 48 | 49 | checkThatKeySlicesAreIncreasing( 50 | key1: [number, number], 51 | key2: [number, number], 52 | ): void; 53 | } 54 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/serde/mod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | export * from "./types.ts"; 7 | export * from "./serializer.ts"; 8 | export * from "./deserializer.ts"; 9 | export * from "./binarySerializer.ts"; 10 | export * from "./binaryDeserializer.ts"; 11 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/serde/serializer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | export interface Serializer { 7 | serializeStr(value: string): void; 8 | 9 | serializeBytes(value: Uint8Array): void; 10 | 11 | serializeBool(value: boolean): void; 12 | 13 | serializeUnit(value: null): void; 14 | 15 | serializeChar(value: string): void; 16 | 17 | serializeF32(value: number): void; 18 | 19 | serializeF64(value: number): void; 20 | 21 | serializeU8(value: number): void; 22 | 23 | serializeU16(value: number): void; 24 | 25 | serializeU32(value: number): void; 26 | 27 | serializeU64(value: bigint | number): void; 28 | 29 | serializeU128(value: bigint | number): void; 30 | 31 | serializeI8(value: number): void; 32 | 33 | serializeI16(value: number): void; 34 | 35 | serializeI32(value: number): void; 36 | 37 | serializeI64(value: bigint | number): void; 38 | 39 | serializeI128(value: bigint | number): void; 40 | 41 | serializeLen(value: number): void; 42 | 43 | serializeVariantIndex(value: number): void; 44 | 45 | serializeOptionTag(value: boolean): void; 46 | 47 | getBufferOffset(): number; 48 | 49 | getBytes(): Uint8Array; 50 | 51 | sortMapEntries(offsets: number[]): void; 52 | } 53 | -------------------------------------------------------------------------------- /serde-generate/runtime/typescript/serde/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates 3 | * SPDX-License-Identifier: MIT OR Apache-2.0 4 | */ 5 | 6 | export type Optional = T | null; 7 | export type Seq = T[]; 8 | export type Tuple = T; 9 | export type ListTuple = Tuple[]; 10 | 11 | export type unit = null; 12 | export type bool = boolean; 13 | export type int8 = number; 14 | export type int16 = number; 15 | export type int32 = number; 16 | export type int64 = bigint; 17 | export type int128 = bigint; 18 | export type uint8 = number; 19 | export type uint16 = number; 20 | export type uint32 = number; 21 | export type uint64 = bigint; 22 | export type uint128 = bigint; 23 | export type float32 = number; 24 | export type float64 = number; 25 | export type char = string; 26 | export type str = string; 27 | export type bytes = Uint8Array; 28 | -------------------------------------------------------------------------------- /serde-generate/src/analyzer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use serde_reflection::{ContainerFormat, Format, FormatHolder, Registry, Result}; 5 | use std::collections::{BTreeMap, BTreeSet, HashSet}; 6 | 7 | /// Compute dependencies while ignoring external names. 8 | fn get_dependencies<'a>( 9 | format: &'a ContainerFormat, 10 | external: &BTreeSet, 11 | ) -> Result> { 12 | let mut result = BTreeSet::new(); 13 | format.visit(&mut |format| { 14 | if let Format::TypeName(x) = format { 15 | if !external.contains(x) { 16 | result.insert(x.as_str()); 17 | } 18 | } 19 | Ok(()) 20 | })?; 21 | Ok(result) 22 | } 23 | 24 | /// Build a map of dependencies between the entries of a `Registry`. 25 | /// * By definition, an entry named `x` depends on `y` iff the container format of `x` in the registry 26 | /// syntactically contains a reference to `y` (i.e. an expression `Format::TypeName(y)`). 27 | /// * Dependencies can play a role in code generation in some languages (e.g. Rust or C++) where inductive 28 | /// definitions may require explicit "boxing" (i.e. adding pointer indirections) to ensure finite object sizes. 29 | pub fn get_dependency_map(registry: &Registry) -> Result>> { 30 | get_dependency_map_with_external_dependencies(registry, &BTreeSet::new()) 31 | } 32 | 33 | /// Same as get_dependency_map but allow to specify a set of externally-provided names to ignore. 34 | pub fn get_dependency_map_with_external_dependencies<'a>( 35 | registry: &'a Registry, 36 | external: &BTreeSet, 37 | ) -> Result>> { 38 | let mut children = BTreeMap::new(); 39 | for (name, format) in registry { 40 | children.insert(name.as_str(), get_dependencies(format, external)?); 41 | } 42 | Ok(children) 43 | } 44 | 45 | /// Classic topological sorting algorithm except that it doesn't abort in case of cycles. 46 | pub fn best_effort_topological_sort(children: &BTreeMap>) -> Vec 47 | where 48 | T: Clone + std::cmp::Ord + std::cmp::Eq + std::hash::Hash, 49 | { 50 | // Build the initial queue so that we pick up nodes with less children first (and otherwise 51 | // those with smaller key first). 52 | // This is a heuristic to break cycles preferably at large nodes (see comment below). 53 | let mut queue: Vec<_> = children.keys().rev().cloned().collect(); 54 | queue.sort_by(|node1, node2| children[node1].len().cmp(&children[node2].len())); 55 | 56 | let mut result = Vec::new(); 57 | // Nodes already inserted in result. 58 | let mut sorted = HashSet::new(); 59 | // Nodes for which children have been enqueued. 60 | let mut seen = HashSet::new(); 61 | 62 | while let Some(node) = queue.pop() { 63 | if sorted.contains(&node) { 64 | continue; 65 | } 66 | if seen.contains(&node) { 67 | // Second time we see this node. 68 | // * If `node` does not belong to a cycle in the graph, then by now, all its children 69 | // have been sorted. 70 | // * If `node` has children that depend back on it. We may be visiting `node` again 71 | // before some of those children. Just insert `node` here. By ignoring edges going back 72 | // to `node` now, we are effectively deciding to "break the cycle" there in future 73 | // applications (e.g. `node` may be forward-declared in C++ and `Box`-ed in Rust). 74 | sorted.insert(node.clone()); 75 | result.push(node); 76 | continue; 77 | } 78 | // First time we see this node: 79 | // 1. Mark it so that it is no longer enqueued. 80 | seen.insert(node.clone()); 81 | // 2. Schedule all the (yet unseen) children then this node for a second visit. 82 | // (If possible, visit children by increasing key.) 83 | queue.push(node.clone()); 84 | for child in children[&node].iter().rev() { 85 | if !seen.contains(child) { 86 | queue.push(child.clone()); 87 | } 88 | } 89 | } 90 | result 91 | } 92 | -------------------------------------------------------------------------------- /serde-generate/src/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use serde_reflection::Format; 5 | 6 | pub(crate) fn mangle_type(format: &Format) -> String { 7 | use Format::*; 8 | match format { 9 | TypeName(x) => x.to_string(), 10 | Unit => "unit".into(), 11 | Bool => "bool".into(), 12 | I8 => "i8".into(), 13 | I16 => "i16".into(), 14 | I32 => "i32".into(), 15 | I64 => "i64".into(), 16 | I128 => "i128".into(), 17 | U8 => "u8".into(), 18 | U16 => "u16".into(), 19 | U32 => "u32".into(), 20 | U64 => "u64".into(), 21 | U128 => "u128".into(), 22 | F32 => "f32".into(), 23 | F64 => "f64".into(), 24 | Char => "char".into(), 25 | Str => "str".into(), 26 | Bytes => "bytes".into(), 27 | 28 | Option(format) => format!("option_{}", mangle_type(format)), 29 | Seq(format) => format!("vector_{}", mangle_type(format)), 30 | Map { key, value } => format!("map_{}_to_{}", mangle_type(key), mangle_type(value)), 31 | Tuple(formats) => format!( 32 | "tuple{}_{}", 33 | formats.len(), 34 | formats 35 | .iter() 36 | .map(mangle_type) 37 | .collect::>() 38 | .join("_") 39 | ), 40 | TupleArray { content, size } => format!("array{}_{}_array", size, mangle_type(content)), 41 | Variable(_) => panic!("unexpected value"), 42 | } 43 | } 44 | 45 | pub(crate) fn uppercase_first_letter(s: &str) -> String { 46 | let mut c = s.chars(); 47 | match c.next() { 48 | None => String::new(), 49 | Some(f) => f.to_uppercase().collect::() + c.as_str(), 50 | } 51 | } 52 | 53 | pub(crate) fn lowercase_first_letter(s: &str) -> String { 54 | let mut c = s.chars(); 55 | match c.next() { 56 | None => String::new(), 57 | Some(f) => f.to_lowercase().collect::() + c.as_str(), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /serde-generate/src/indent.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use std::io::{Result, Write}; 5 | 6 | #[derive(Clone, Copy)] 7 | pub enum IndentConfig { 8 | Tab, 9 | Space(usize), 10 | } 11 | 12 | pub struct IndentedWriter { 13 | out: T, 14 | indentation: Vec, 15 | config: IndentConfig, 16 | at_begining_of_line: bool, 17 | } 18 | 19 | impl IndentedWriter { 20 | pub fn new(out: T, config: IndentConfig) -> Self { 21 | Self { 22 | out, 23 | indentation: Vec::new(), 24 | config, 25 | at_begining_of_line: true, 26 | } 27 | } 28 | 29 | pub fn indent(&mut self) { 30 | match self.config { 31 | IndentConfig::Tab => { 32 | self.indentation.push(b'\t'); 33 | } 34 | IndentConfig::Space(n) => { 35 | self.indentation.resize(self.indentation.len() + n, b' '); 36 | } 37 | } 38 | } 39 | 40 | pub fn unindent(&mut self) { 41 | match self.config { 42 | IndentConfig::Tab => { 43 | self.indentation.pop(); 44 | } 45 | IndentConfig::Space(n) => { 46 | self.indentation 47 | .truncate(self.indentation.len().saturating_sub(n)); 48 | } 49 | } 50 | } 51 | } 52 | 53 | impl Write for IndentedWriter { 54 | fn write(&mut self, mut buf: &[u8]) -> Result { 55 | let mut bytes_written = 0; 56 | 57 | while !buf.is_empty() { 58 | let (before_newline, has_newline, after_newline) = 59 | if let Some(idx) = buf.iter().position(|&b| b == b'\n') { 60 | (&buf[..idx], true, &buf[idx + 1..]) 61 | } else { 62 | (buf, false, &buf[buf.len()..]) 63 | }; 64 | 65 | if self.at_begining_of_line && !before_newline.is_empty() { 66 | self.out.write_all(&self.indentation)?; 67 | self.at_begining_of_line = false; 68 | } 69 | 70 | self.out.write_all(before_newline)?; 71 | bytes_written += before_newline.len(); 72 | 73 | if has_newline { 74 | self.out.write_all(b"\n")?; 75 | bytes_written += 1; 76 | self.at_begining_of_line = true; 77 | } 78 | 79 | buf = after_newline; 80 | } 81 | 82 | Ok(bytes_written) 83 | } 84 | 85 | fn flush(&mut self) -> Result<()> { 86 | self.out.flush() 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod test { 92 | use super::*; 93 | 94 | #[test] 95 | fn basic() -> Result<()> { 96 | let mut buffer: Vec = Vec::new(); 97 | 98 | let mut out = IndentedWriter::new(&mut buffer, IndentConfig::Space(2)); 99 | 100 | writeln!(out, "foo")?; 101 | out.indent(); 102 | writeln!(out, "bar")?; 103 | writeln!(out)?; 104 | writeln!(out, "bar")?; 105 | out.indent(); 106 | writeln!(out, "foobar")?; 107 | writeln!(out)?; 108 | writeln!(out, "foobar")?; 109 | out.unindent(); 110 | out.unindent(); 111 | writeln!(out, "foo")?; 112 | 113 | let expect: &[u8] = b"\ 114 | foo 115 | bar 116 | 117 | bar 118 | foobar 119 | 120 | foobar 121 | foo 122 | "; 123 | assert_eq!(buffer, expect); 124 | 125 | Ok(()) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /serde-generate/tests/analyzer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use crate::test_utils; 5 | use maplit::{btreemap, btreeset}; 6 | use serde_generate::analyzer; 7 | 8 | #[test] 9 | fn test_topological_sort() { 10 | use analyzer::best_effort_topological_sort as tsort; 11 | // 2 nodes, no cycle 12 | assert_eq!( 13 | tsort(&btreemap! { 14 | 1 => btreeset![2], 15 | 2 => btreeset![], 16 | }), 17 | vec![2, 1] 18 | ); 19 | // 3 nodes, no cycle 20 | assert_eq!( 21 | tsort(&btreemap! { 22 | 1 => btreeset![2, 3], 23 | 2 => btreeset![], 24 | 3 => btreeset![], 25 | }), 26 | vec![2, 3, 1] 27 | ); 28 | assert_eq!( 29 | tsort(&btreemap! { 30 | 1 => btreeset![2, 3], 31 | 2 => btreeset![3], 32 | 3 => btreeset![], 33 | }), 34 | vec![3, 2, 1] 35 | ); 36 | // Cycles are broken preferably by ignoring edges to nodes with many dependencies. 37 | // When 1 is larger. 38 | assert_eq!( 39 | tsort(&btreemap! { 40 | 1 => btreeset![2, 4, 5, 3], 41 | 2 => btreeset![], 42 | 3 => btreeset![1], 43 | 4 => btreeset![], 44 | 5 => btreeset![], 45 | }), 46 | vec![2, /* ignoring edge to 1 */ 3, 4, 5, 1] 47 | ); 48 | // When 3 is larger 49 | assert_eq!( 50 | tsort(&btreemap! { 51 | 1 => btreeset![2, 3], 52 | 2 => btreeset![], 53 | 3 => btreeset![1, 4, 5], 54 | 4 => btreeset![], 55 | 5 => btreeset![], 56 | }), 57 | vec![2, /* ignoring edge to 3 */ 1, 4, 5, 3] 58 | ); 59 | } 60 | 61 | #[test] 62 | fn test_on_larger_registry() { 63 | let registry = test_utils::get_registry().unwrap(); 64 | let map = analyzer::get_dependency_map(®istry).unwrap(); 65 | assert_eq!( 66 | map.get("SerdeData").unwrap(), 67 | &btreeset!( 68 | "CStyleEnum", 69 | "List", 70 | "NewTypeStruct", 71 | "OtherTypes", 72 | "PrimitiveTypes", 73 | "Struct", 74 | "Tree", 75 | "TupleStruct", 76 | "UnitStruct", 77 | "SimpleList", 78 | ) 79 | ); 80 | 81 | let vector = analyzer::best_effort_topological_sort(&map); 82 | assert_eq!( 83 | vector, 84 | vec![ 85 | "CStyleEnum", 86 | "List", 87 | "NewTypeStruct", 88 | "Struct", 89 | "OtherTypes", 90 | "PrimitiveTypes", 91 | "SimpleList", 92 | "Tree", 93 | "TupleStruct", 94 | "UnitStruct", 95 | "SerdeData" 96 | ] 97 | ); 98 | } 99 | -------------------------------------------------------------------------------- /serde-generate/tests/csharp_generation.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use crate::test_utils; 5 | use serde_generate::{csharp, CodeGeneratorConfig, Encoding}; 6 | use std::{collections::BTreeMap, process::Command, sync::Mutex}; 7 | use tempfile::{tempdir, TempDir}; 8 | 9 | lazy_static::lazy_static! { 10 | // `dotnet build` spuriously fails on linux if run concurrently 11 | static ref MUTEX: Mutex<()> = Mutex::new(()); 12 | } 13 | 14 | fn test_that_csharp_code_compiles_with_config( 15 | config: &CodeGeneratorConfig, 16 | ) -> (TempDir, std::path::PathBuf) { 17 | use serde_generate::SourceInstaller; 18 | 19 | let registry = test_utils::get_registry().unwrap(); 20 | let dir = tempdir().unwrap(); 21 | let dir_path = dir.path().to_path_buf(); 22 | 23 | let installer = csharp::Installer::new(dir_path.clone()); 24 | installer.install_module(config, ®istry).unwrap(); 25 | installer.install_serde_runtime().unwrap(); 26 | installer.install_bincode_runtime().unwrap(); 27 | installer.install_bcs_runtime().unwrap(); 28 | 29 | let proj_path = dir_path.join(config.module_name().replace('.', "/")); 30 | { 31 | let _lock = MUTEX.lock(); 32 | let status = Command::new("dotnet") 33 | .arg("build") 34 | .current_dir(&proj_path) 35 | .status() 36 | .unwrap(); 37 | assert!(status.success()); 38 | } 39 | 40 | (dir, proj_path) 41 | } 42 | 43 | #[test] 44 | fn test_that_csharp_code_compiles() { 45 | let config = CodeGeneratorConfig::new("Generated".to_string()); 46 | test_that_csharp_code_compiles_with_config(&config); 47 | } 48 | 49 | #[test] 50 | fn test_that_csharp_code_compiles_without_serialization() { 51 | let config = CodeGeneratorConfig::new("Generated".to_string()).with_serialization(false); 52 | test_that_csharp_code_compiles_with_config(&config); 53 | } 54 | 55 | #[test] 56 | fn test_that_csharp_code_compiles_with_c_style_enums() { 57 | let config = CodeGeneratorConfig::new("Generated".to_string()).with_c_style_enums(true); 58 | test_that_csharp_code_compiles_with_config(&config); 59 | } 60 | 61 | #[test] 62 | fn test_that_csharp_code_compiles_with_bcs() { 63 | let config = 64 | CodeGeneratorConfig::new("Generated".to_string()).with_encodings(vec![Encoding::Bcs]); 65 | test_that_csharp_code_compiles_with_config(&config); 66 | } 67 | 68 | #[test] 69 | fn test_that_csharp_code_compiles_with_bcs_and_extra_nesting() { 70 | let config = CodeGeneratorConfig::new("My.Generated.Project".to_string()) 71 | .with_encodings(vec![Encoding::Bcs]); 72 | test_that_csharp_code_compiles_with_config(&config); 73 | } 74 | 75 | #[test] 76 | fn test_that_csharp_code_compiles_with_bincode() { 77 | let config = 78 | CodeGeneratorConfig::new("Generated".to_string()).with_encodings(vec![Encoding::Bincode]); 79 | test_that_csharp_code_compiles_with_config(&config); 80 | } 81 | 82 | #[test] 83 | fn test_that_csharp_code_compiles_with_comments() { 84 | let comments = vec![( 85 | vec!["Generated".to_string(), "SerdeData".to_string()], 86 | "Some\ncomments".to_string(), 87 | )] 88 | .into_iter() 89 | .collect(); 90 | let config = CodeGeneratorConfig::new("Generated".to_string()).with_comments(comments); 91 | 92 | let (_dir, path) = test_that_csharp_code_compiles_with_config(&config); 93 | let content = std::fs::read_to_string(path.join("SerdeData.cs")).unwrap(); 94 | assert!(content.contains("/// Some\n /// comments")); 95 | } 96 | 97 | #[test] 98 | fn test_csharp_code_with_external_definitions() { 99 | let registry = test_utils::get_registry().unwrap(); 100 | let dir = tempdir().unwrap(); 101 | 102 | // (wrongly) Declare TraitHelpers as external. 103 | let mut definitions = BTreeMap::new(); 104 | definitions.insert("foo".to_string(), vec!["TraitHelpers".to_string()]); 105 | let config = 106 | CodeGeneratorConfig::new("Generated".to_string()).with_external_definitions(definitions); 107 | let generator = csharp::CodeGenerator::new(&config); 108 | 109 | generator 110 | .write_source_files(dir.path().to_path_buf(), ®istry) 111 | .unwrap(); 112 | 113 | // References were updated. 114 | let content = std::fs::read_to_string(dir.path().join("Generated/SerdeData.cs")).unwrap(); 115 | assert!(content.contains("foo.TraitHelpers.")); 116 | } 117 | -------------------------------------------------------------------------------- /serde-generate/tests/lib.rs: -------------------------------------------------------------------------------- 1 | mod analyzer; 2 | #[cfg(feature = "cpp")] 3 | mod cpp_generation; 4 | #[cfg(feature = "cpp")] 5 | mod cpp_runtime; 6 | #[cfg(feature = "csharp")] 7 | mod csharp_generation; 8 | #[cfg(feature = "csharp")] 9 | mod csharp_runtime; 10 | #[cfg(feature = "dart")] 11 | mod dart_generation; 12 | #[cfg(feature = "dart")] 13 | mod dart_runtime; 14 | #[cfg(feature = "golang")] 15 | mod golang_generation; 16 | #[cfg(feature = "golang")] 17 | mod golang_runtime; 18 | #[cfg(feature = "java")] 19 | mod java_generation; 20 | #[cfg(feature = "java")] 21 | mod java_runtime; 22 | #[cfg(feature = "ocaml")] 23 | mod ocaml_generation; 24 | #[cfg(feature = "ocaml")] 25 | mod ocaml_runtime; 26 | #[cfg(feature = "python3")] 27 | mod python_generation; 28 | #[cfg(feature = "python3")] 29 | mod python_runtime; 30 | #[cfg(feature = "rust")] 31 | mod rust_generation; 32 | #[cfg(feature = "rust")] 33 | mod rust_runtime; 34 | #[cfg(feature = "solidity")] 35 | mod solidity_generation; 36 | #[cfg(feature = "solidity")] 37 | mod solidity_runtime; 38 | #[cfg(feature = "swift")] 39 | mod swift_generation; 40 | #[cfg(feature = "swift")] 41 | mod swift_runtime; 42 | #[cfg(feature = "typescript")] 43 | mod typescript_generation; 44 | #[cfg(feature = "typescript")] 45 | mod typescript_runtime; 46 | 47 | mod test_utils; 48 | -------------------------------------------------------------------------------- /serde-generate/tests/rust_runtime.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use crate::test_utils; 5 | use crate::test_utils::Runtime; 6 | use serde_generate::{rust, CodeGeneratorConfig}; 7 | use std::{fs::File, io::Write, process::Command}; 8 | use tempfile::tempdir; 9 | 10 | #[test] 11 | fn test_rust_bcs_runtime() { 12 | test_rust_runtime(Runtime::Bcs); 13 | } 14 | 15 | #[test] 16 | fn test_rust_bincode_runtime() { 17 | test_rust_runtime(Runtime::Bincode); 18 | } 19 | 20 | // Full test using cargo. This may take a while. 21 | fn test_rust_runtime(runtime: Runtime) { 22 | let registry = test_utils::get_registry().unwrap(); 23 | let dir = tempdir().unwrap(); 24 | let mut file = std::fs::File::create(dir.path().join("Cargo.toml")).unwrap(); 25 | write!( 26 | &mut file, 27 | r#"[package] 28 | name = "testing2" 29 | version = "0.1.0" 30 | edition = "2018" 31 | 32 | [dependencies] 33 | serde = {{ version = "1.0", features = ["derive"] }} 34 | serde_bytes = "0.11" 35 | {} 36 | 37 | [workspace] 38 | "#, 39 | runtime.rust_package() 40 | ) 41 | .unwrap(); 42 | std::fs::create_dir(dir.path().join("src")).unwrap(); 43 | 44 | let config = CodeGeneratorConfig::new("testing".to_string()); 45 | let generator = rust::CodeGenerator::new(&config); 46 | 47 | let source_path = dir.path().join("src/main.rs"); 48 | let mut source = File::create(source_path).unwrap(); 49 | generator.output(&mut source, ®istry).unwrap(); 50 | 51 | let encodings: Vec<_> = runtime 52 | .get_positive_samples() 53 | .iter() 54 | .map(|bytes| format!("vec!{:?}", bytes)) 55 | .collect(); 56 | 57 | writeln!( 58 | source, 59 | r#" 60 | fn main() {{ 61 | for encoding in vec![{}] {{ 62 | let value = {}::(&encoding).unwrap(); 63 | let s = {}(&value).unwrap(); 64 | assert_eq!(s, encoding); 65 | }} 66 | }} 67 | "#, 68 | encodings.join(", "), 69 | runtime.quote_deserialize(), 70 | runtime.quote_serialize(), 71 | ) 72 | .unwrap(); 73 | 74 | // Use a stable `target` dir to avoid downloading and recompiling crates everytime. 75 | let target_dir = std::env::current_dir().unwrap().join("../target"); 76 | let status = Command::new("cargo") 77 | .current_dir(dir.path()) 78 | .arg("run") 79 | .arg("--target-dir") 80 | .arg(target_dir) 81 | .status() 82 | .unwrap(); 83 | assert!(status.success()); 84 | } 85 | -------------------------------------------------------------------------------- /serde-generate/tests/typescript_runtime.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use crate::test_utils; 5 | use crate::test_utils::{Choice, Runtime, Test}; 6 | use heck::CamelCase; 7 | use serde_generate::{typescript, CodeGeneratorConfig, SourceInstaller}; 8 | use std::{fs::File, io::Write, process::Command}; 9 | use tempfile::tempdir; 10 | 11 | #[test] 12 | fn test_typescript_runtime_bcs_serialization() { 13 | let registry = test_utils::get_simple_registry().unwrap(); 14 | let dir = tempdir().unwrap(); 15 | let dir_path = dir.path(); 16 | std::fs::create_dir_all(dir_path.join("tests")).unwrap(); 17 | 18 | let installer = typescript::Installer::new(dir_path.to_path_buf()); 19 | installer.install_serde_runtime().unwrap(); 20 | installer.install_bcs_runtime().unwrap(); 21 | 22 | let source_path = dir_path.join("tests/test.ts"); 23 | let mut source = File::create(&source_path).unwrap(); 24 | 25 | let runtime = Runtime::Bcs; 26 | let config = CodeGeneratorConfig::new("main".to_string()).with_encodings(vec![runtime.into()]); 27 | let generator = typescript::CodeGenerator::new(&config); 28 | generator.output(&mut source, ®istry).unwrap(); 29 | 30 | let reference = runtime.serialize(&Test { 31 | a: vec![4, 6], 32 | b: (-3, 5), 33 | c: Choice::C { x: 7 }, 34 | }); 35 | 36 | writeln!( 37 | source, 38 | r#" 39 | import {{ assertEquals }} from "https://deno.land/std@0.110.0/testing/asserts.ts"; 40 | Deno.test("{1} serialization matches deserialization", () => {{ 41 | const expectedBytes = new Uint8Array([{0}]); 42 | const {1}Deserializer: {2}Deserializer = new {2}Deserializer(expectedBytes); 43 | const deserializedInstance: Test = Test.deserialize({1}Deserializer); 44 | 45 | const expectedInstance: Test = new Test( 46 | [4, 6], 47 | [BigInt(-3), BigInt(5)], 48 | new ChoiceVariantC(7), 49 | ); 50 | 51 | assertEquals(deserializedInstance, expectedInstance, "Object instances should match"); 52 | 53 | const {1}Serializer = new {2}Serializer(); 54 | expectedInstance.serialize({1}Serializer); 55 | const serializedBytes = {1}Serializer.getBytes(); 56 | 57 | assertEquals(serializedBytes, expectedBytes, "{1} bytes should match"); 58 | }}); 59 | "#, 60 | reference 61 | .iter() 62 | .map(|x| format!("{}", x)) 63 | .collect::>() 64 | .join(", "), 65 | runtime.name().to_lowercase(), 66 | runtime.name().to_camel_case(), 67 | ) 68 | .unwrap(); 69 | 70 | let status = Command::new("deno") 71 | .current_dir(dir_path) 72 | .arg("test") 73 | .arg(&source_path) 74 | .status() 75 | .unwrap(); 76 | assert!(status.success()); 77 | } 78 | -------------------------------------------------------------------------------- /serde-name/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-name" 3 | version = "0.2.1" 4 | description = "Extract the Serde name of structs and enums" 5 | documentation = "https://docs.rs/serde-name" 6 | repository = "https://github.com/zefchain/serde-reflection" 7 | authors = ["Mathieu Baudet "] 8 | license = "MIT OR Apache-2.0" 9 | readme = "README.md" 10 | keywords = ["data-structures", "serialization", "serde"] 11 | categories = ["encoding", "development-tools"] 12 | edition = "2021" 13 | rust-version = "1.60" 14 | exclude = [ 15 | # Readme template that doesn't need to be included. 16 | "README.tpl", 17 | ] 18 | 19 | [dependencies] 20 | thiserror = "1.0.25" 21 | serde = { version = "1.0.126", features = ["derive"] } 22 | 23 | [dev-dependencies] 24 | serde-reflection = { path = "../serde-reflection", version = "0.5.0" } 25 | -------------------------------------------------------------------------------- /serde-name/README.md: -------------------------------------------------------------------------------- 1 | # serde-name 2 | 3 | [![serde-name on crates.io](https://img.shields.io/crates/v/serde-name)](https://crates.io/crates/serde-name) 4 | [![Documentation (latest release)](https://docs.rs/serde-name/badge.svg)](https://docs.rs/serde-name/) 5 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](../LICENSE-APACHE) 6 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](../LICENSE-MIT) 7 | 8 | This crate provides fast and reliable ways to extract and to override the Serde name 9 | of a Rust container. 10 | 11 | ## Extracting Serde names 12 | 13 | Name extraction relies on the Deserialize trait of Serde: 14 | 15 | ```rust 16 | #[derive(Deserialize)] 17 | struct Foo { 18 | bar: Bar, 19 | } 20 | 21 | #[derive(Deserialize)] 22 | #[serde(rename = "ABC")] 23 | enum Bar { A, B, C } 24 | 25 | assert_eq!(trace_name::(), Some("Foo")); 26 | assert_eq!(trace_name::(), Some("ABC")); 27 | assert_eq!(trace_name::>(), None); 28 | ``` 29 | 30 | ## Overriding Serde names 31 | 32 | `SerializeNameAdapter` and `DeserializeNameAdapter` may be used to override the name 33 | of a container in the cases where `#[serde(rename = "..")]` is not flexible enough. 34 | 35 | ```rust 36 | #[derive(Serialize, Deserialize)] 37 | #[serde(remote = "Foo")] // Generates Foo::(de)serialize instead of implementing Serde traits. 38 | struct Foo { 39 | data: T, 40 | } 41 | 42 | impl<'de, T> Deserialize<'de> for Foo 43 | where 44 | T: Deserialize<'de>, 45 | { 46 | fn deserialize(deserializer: D) -> Result 47 | where 48 | D: serde::de::Deserializer<'de>, 49 | { 50 | Foo::deserialize(DeserializeNameAdapter::new( 51 | deserializer, 52 | std::any::type_name::(), 53 | )) 54 | } 55 | } 56 | 57 | impl Serialize for Foo 58 | where 59 | T: Serialize, 60 | { 61 | fn serialize(&self, serializer: S) -> Result 62 | where 63 | S: serde::ser::Serializer, 64 | { 65 | Foo::serialize( 66 | self, 67 | SerializeNameAdapter::new(serializer, std::any::type_name::()), 68 | ) 69 | } 70 | } 71 | 72 | // Testing the Deserialize implementation 73 | assert!(trace_name::>().unwrap().ends_with("Foo")); 74 | 75 | // Testing the Serialize implementation 76 | use serde_reflection::*; 77 | let mut tracer = Tracer::new(TracerConfig::default()); 78 | let mut samples = Samples::new(); 79 | let (mut ident, _) = tracer.trace_value(&mut samples, &Foo { data: 1u64 }).unwrap(); 80 | ident.normalize().unwrap(); 81 | assert!(matches!(ident, Format::TypeName(s) if s.ends_with("Foo"))); 82 | ``` 83 | 84 | ## Contributing 85 | 86 | See the [CONTRIBUTING](../CONTRIBUTING.md) file for how to help out. 87 | 88 | ## License 89 | 90 | This project is available under the terms of either the [Apache 2.0 license](../LICENSE-APACHE) or the [MIT license](../LICENSE-MIT). 91 | 92 | 98 | -------------------------------------------------------------------------------- /serde-name/README.tpl: -------------------------------------------------------------------------------- 1 | # {{crate}} 2 | 3 | [![serde-name on crates.io](https://img.shields.io/crates/v/serde-name)](https://crates.io/crates/serde-name) 4 | [![Documentation (latest release)](https://docs.rs/serde-name/badge.svg)](https://docs.rs/serde-name/) 5 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](../LICENSE-APACHE) 6 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](../LICENSE-MIT) 7 | 8 | {{readme}} 9 | 10 | ## Contributing 11 | 12 | See the [CONTRIBUTING](../CONTRIBUTING.md) file for how to help out. 13 | 14 | ## License 15 | 16 | This project is available under the terms of either the [Apache 2.0 license](../LICENSE-APACHE) or the [MIT license](../LICENSE-MIT). 17 | 18 | 24 | -------------------------------------------------------------------------------- /serde-name/src/de_adapter.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use serde::de::Visitor; 5 | 6 | /// An adapter for `serde::de::Deserializer` implementations that lets you override the 7 | /// name of the top-level container. 8 | pub struct DeserializeNameAdapter { 9 | inner: D, 10 | name: &'static str, 11 | } 12 | 13 | impl DeserializeNameAdapter { 14 | pub fn new(inner: D, name: &'static str) -> Self { 15 | Self { inner, name } 16 | } 17 | } 18 | 19 | macro_rules! declare_deserialize { 20 | ($method:ident) => { 21 | fn $method(self, visitor: V) -> std::result::Result 22 | where 23 | V: Visitor<'de>, 24 | { 25 | self.inner.$method(visitor) 26 | } 27 | }; 28 | } 29 | 30 | impl<'de, D> serde::de::Deserializer<'de> for DeserializeNameAdapter 31 | where 32 | D: serde::de::Deserializer<'de>, 33 | { 34 | type Error = D::Error; 35 | 36 | declare_deserialize!(deserialize_any); 37 | declare_deserialize!(deserialize_identifier); 38 | declare_deserialize!(deserialize_ignored_any); 39 | declare_deserialize!(deserialize_bool); 40 | declare_deserialize!(deserialize_i8); 41 | declare_deserialize!(deserialize_i16); 42 | declare_deserialize!(deserialize_i32); 43 | declare_deserialize!(deserialize_i64); 44 | declare_deserialize!(deserialize_i128); 45 | declare_deserialize!(deserialize_u8); 46 | declare_deserialize!(deserialize_u16); 47 | declare_deserialize!(deserialize_u32); 48 | declare_deserialize!(deserialize_u64); 49 | declare_deserialize!(deserialize_u128); 50 | declare_deserialize!(deserialize_f32); 51 | declare_deserialize!(deserialize_f64); 52 | declare_deserialize!(deserialize_char); 53 | declare_deserialize!(deserialize_str); 54 | declare_deserialize!(deserialize_string); 55 | declare_deserialize!(deserialize_bytes); 56 | declare_deserialize!(deserialize_byte_buf); 57 | declare_deserialize!(deserialize_option); 58 | declare_deserialize!(deserialize_unit); 59 | declare_deserialize!(deserialize_seq); 60 | declare_deserialize!(deserialize_map); 61 | 62 | fn deserialize_tuple( 63 | self, 64 | len: usize, 65 | visitor: V, 66 | ) -> std::result::Result 67 | where 68 | V: Visitor<'de>, 69 | { 70 | self.inner.deserialize_tuple(len, visitor) 71 | } 72 | 73 | fn deserialize_unit_struct( 74 | self, 75 | _name: &'static str, 76 | visitor: V, 77 | ) -> std::result::Result 78 | where 79 | V: Visitor<'de>, 80 | { 81 | self.inner.deserialize_unit_struct(self.name, visitor) 82 | } 83 | 84 | fn deserialize_newtype_struct( 85 | self, 86 | _name: &'static str, 87 | visitor: V, 88 | ) -> std::result::Result 89 | where 90 | V: Visitor<'de>, 91 | { 92 | self.inner.deserialize_newtype_struct(self.name, visitor) 93 | } 94 | 95 | fn deserialize_tuple_struct( 96 | self, 97 | _name: &'static str, 98 | len: usize, 99 | visitor: V, 100 | ) -> std::result::Result 101 | where 102 | V: Visitor<'de>, 103 | { 104 | self.inner.deserialize_tuple_struct(self.name, len, visitor) 105 | } 106 | 107 | fn deserialize_struct( 108 | self, 109 | _name: &'static str, 110 | fields: &'static [&'static str], 111 | visitor: V, 112 | ) -> std::result::Result 113 | where 114 | V: Visitor<'de>, 115 | { 116 | self.inner.deserialize_struct(self.name, fields, visitor) 117 | } 118 | 119 | fn deserialize_enum( 120 | self, 121 | _name: &'static str, 122 | variants: &'static [&'static str], 123 | visitor: V, 124 | ) -> std::result::Result 125 | where 126 | V: Visitor<'de>, 127 | { 128 | self.inner.deserialize_enum(self.name, variants, visitor) 129 | } 130 | 131 | fn is_human_readable(&self) -> bool { 132 | self.inner.is_human_readable() 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /serde-name/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | 6 | //! This crate provides fast and reliable ways to extract and to override the Serde name 7 | //! of a Rust container. 8 | //! 9 | //! # Extracting Serde names 10 | //! 11 | //! Name extraction relies on the Deserialize trait of Serde: 12 | //! 13 | //! ```rust 14 | //! # use serde::Deserialize; 15 | //! # use serde_name::trace_name; 16 | //! #[derive(Deserialize)] 17 | //! struct Foo { 18 | //! bar: Bar, 19 | //! } 20 | //! 21 | //! #[derive(Deserialize)] 22 | //! #[serde(rename = "ABC")] 23 | //! enum Bar { A, B, C } 24 | //! 25 | //! assert_eq!(trace_name::(), Some("Foo")); 26 | //! assert_eq!(trace_name::(), Some("ABC")); 27 | //! assert_eq!(trace_name::>(), None); 28 | //! ``` 29 | //! 30 | //! # Overriding Serde names 31 | //! 32 | //! `SerializeNameAdapter` and `DeserializeNameAdapter` may be used to override the name 33 | //! of a container in the cases where `#[serde(rename = "..")]` is not flexible enough. 34 | //! 35 | //! ```rust 36 | //! # use serde_name::{SerializeNameAdapter, DeserializeNameAdapter, trace_name}; 37 | //! # use serde::{Deserialize, Serialize}; 38 | //! #[derive(Serialize, Deserialize)] 39 | //! #[serde(remote = "Foo")] // Generates Foo::(de)serialize instead of implementing Serde traits. 40 | //! struct Foo { 41 | //! data: T, 42 | //! } 43 | //! 44 | //! impl<'de, T> Deserialize<'de> for Foo 45 | //! where 46 | //! T: Deserialize<'de>, 47 | //! { 48 | //! fn deserialize(deserializer: D) -> Result 49 | //! where 50 | //! D: serde::de::Deserializer<'de>, 51 | //! { 52 | //! Foo::deserialize(DeserializeNameAdapter::new( 53 | //! deserializer, 54 | //! std::any::type_name::(), 55 | //! )) 56 | //! } 57 | //! } 58 | //! 59 | //! impl Serialize for Foo 60 | //! where 61 | //! T: Serialize, 62 | //! { 63 | //! fn serialize(&self, serializer: S) -> Result 64 | //! where 65 | //! S: serde::ser::Serializer, 66 | //! { 67 | //! Foo::serialize( 68 | //! self, 69 | //! SerializeNameAdapter::new(serializer, std::any::type_name::()), 70 | //! ) 71 | //! } 72 | //! } 73 | //! 74 | //! // Testing the Deserialize implementation 75 | //! assert!(trace_name::>().unwrap().ends_with("Foo")); 76 | //! 77 | //! // Testing the Serialize implementation 78 | //! use serde_reflection::*; 79 | //! let mut tracer = Tracer::new(TracerConfig::default()); 80 | //! let mut samples = Samples::new(); 81 | //! let (mut ident, _) = tracer.trace_value(&mut samples, &Foo { data: 1u64 }).unwrap(); 82 | //! ident.normalize().unwrap(); 83 | //! assert!(matches!(ident, Format::TypeName(s) if s.ends_with("Foo"))); 84 | //! ``` 85 | 86 | mod de_adapter; 87 | mod ser_adapter; 88 | mod trace; 89 | 90 | pub use de_adapter::DeserializeNameAdapter; 91 | pub use ser_adapter::SerializeNameAdapter; 92 | pub use trace::trace_name; 93 | -------------------------------------------------------------------------------- /serde-name/tests/de_adapter.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use serde::{de::DeserializeOwned, Deserialize}; 5 | use serde_name::DeserializeNameAdapter; 6 | 7 | #[derive(Deserialize)] 8 | #[serde(remote = "E")] 9 | enum E { 10 | Unit, 11 | } 12 | 13 | #[derive(Deserialize)] 14 | #[serde(remote = "Unit")] 15 | struct Unit; 16 | 17 | #[derive(Deserialize)] 18 | #[serde(remote = "NewType")] 19 | struct NewType(u64); 20 | 21 | #[derive(Deserialize)] 22 | #[serde(remote = "Tuple")] 23 | struct Tuple(u64, u32); 24 | 25 | #[derive(Deserialize)] 26 | #[serde(remote = "Struct")] 27 | #[allow(dead_code)] 28 | struct Struct { 29 | a: u64, 30 | } 31 | 32 | macro_rules! impl_deserialize { 33 | ($name:ident) => { 34 | impl<'de> Deserialize<'de> for $name { 35 | fn deserialize(deserializer: D) -> Result 36 | where 37 | D: serde::de::Deserializer<'de>, 38 | { 39 | $name::deserialize(DeserializeNameAdapter::new( 40 | deserializer, 41 | std::any::type_name::(), 42 | )) 43 | } 44 | } 45 | }; 46 | } 47 | 48 | impl_deserialize!(E); 49 | impl_deserialize!(Unit); 50 | impl_deserialize!(NewType); 51 | impl_deserialize!(Tuple); 52 | impl_deserialize!(Struct); 53 | 54 | fn test_type(expected_name: &'static str) 55 | where 56 | T: DeserializeOwned, 57 | { 58 | // this crate 59 | assert_eq!(serde_name::trace_name::(), Some(expected_name)); 60 | } 61 | 62 | #[test] 63 | fn test_deserialize_adapter() { 64 | test_type::("de_adapter::E"); 65 | test_type::("de_adapter::Unit"); 66 | test_type::("de_adapter::NewType"); 67 | test_type::("de_adapter::Tuple"); 68 | test_type::("de_adapter::Struct"); 69 | } 70 | -------------------------------------------------------------------------------- /serde-name/tests/ser_adapter.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use serde::Serialize; 5 | use serde_name::SerializeNameAdapter; 6 | use serde_reflection::{Format, FormatHolder, Samples, Tracer, TracerConfig}; 7 | 8 | #[derive(Serialize)] 9 | #[serde(remote = "E")] 10 | enum E { 11 | Unit, 12 | } 13 | 14 | #[derive(Serialize)] 15 | #[serde(remote = "Unit")] 16 | struct Unit; 17 | 18 | #[derive(Serialize)] 19 | #[serde(remote = "NewType")] 20 | struct NewType(u64); 21 | 22 | #[derive(Serialize)] 23 | #[serde(remote = "Tuple")] 24 | struct Tuple(u64, u32); 25 | 26 | #[derive(Serialize)] 27 | #[serde(remote = "Struct")] 28 | #[allow(dead_code)] 29 | struct Struct { 30 | a: u64, 31 | } 32 | 33 | macro_rules! impl_serialize { 34 | ($name:ident) => { 35 | impl Serialize for $name { 36 | fn serialize(&self, serializer: S) -> Result 37 | where 38 | S: serde::ser::Serializer, 39 | { 40 | $name::serialize( 41 | self, 42 | SerializeNameAdapter::new(serializer, std::any::type_name::()), 43 | ) 44 | } 45 | } 46 | }; 47 | } 48 | 49 | impl_serialize!(E); 50 | impl_serialize!(Unit); 51 | impl_serialize!(NewType); 52 | impl_serialize!(Tuple); 53 | impl_serialize!(Struct); 54 | 55 | fn test_type(value: &T, expected_name: &'static str) 56 | where 57 | T: Serialize, 58 | { 59 | let mut tracer = Tracer::new(TracerConfig::default()); 60 | let mut samples = Samples::new(); 61 | let (mut ident, _) = tracer.trace_value(&mut samples, value).unwrap(); 62 | ident.normalize().unwrap(); 63 | assert_eq!(ident, Format::TypeName(expected_name.into())); 64 | } 65 | 66 | #[test] 67 | fn test_serialize_adapter() { 68 | test_type::(&E::Unit, "ser_adapter::E"); 69 | test_type::(&Unit, "ser_adapter::Unit"); 70 | test_type::(&NewType(3), "ser_adapter::NewType"); 71 | test_type::(&Tuple(1, 2), "ser_adapter::Tuple"); 72 | test_type::(&Struct { a: 3 }, "ser_adapter::Struct"); 73 | } 74 | -------------------------------------------------------------------------------- /serde-name/tests/trace.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 3 | 4 | use serde::{de::DeserializeOwned, Deserialize}; 5 | use serde_reflection::{Format, FormatHolder, Samples, Tracer, TracerConfig}; 6 | 7 | #[derive(Deserialize)] 8 | enum E { 9 | Unit, 10 | } 11 | 12 | #[derive(Deserialize)] 13 | struct Unit; 14 | 15 | #[derive(Deserialize)] 16 | #[allow(dead_code)] 17 | struct NewType(u64); 18 | 19 | #[derive(Deserialize)] 20 | #[allow(dead_code)] 21 | struct Tuple(u64, u32); 22 | 23 | #[derive(Deserialize)] 24 | #[serde(rename = "FooStruct")] 25 | #[allow(dead_code)] 26 | struct Struct { 27 | a: u64, 28 | } 29 | 30 | fn test_type(expected_name: &'static str) 31 | where 32 | T: DeserializeOwned, 33 | { 34 | // this crate 35 | assert_eq!(serde_name::trace_name::(), Some(expected_name)); 36 | 37 | // serde-reflection 38 | let mut tracer = Tracer::new(TracerConfig::default()); 39 | let samples = Samples::new(); 40 | let (mut ident, _samples) = tracer.trace_type::(&samples).unwrap(); 41 | ident.normalize().unwrap(); 42 | assert_eq!(ident, Format::TypeName(expected_name.into())); 43 | } 44 | 45 | #[test] 46 | fn test_serde_name_and_reflection() { 47 | test_type::("E"); 48 | test_type::("Unit"); 49 | test_type::("NewType"); 50 | test_type::("Tuple"); 51 | test_type::("FooStruct"); 52 | 53 | assert_eq!(serde_name::trace_name::(), None); 54 | assert_eq!(serde_name::trace_name::<(E, E)>(), None); 55 | } 56 | -------------------------------------------------------------------------------- /serde-reflection/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-reflection" 3 | version = "0.5.0" 4 | description = "Extract representations of Serde data formats" 5 | documentation = "https://docs.rs/serde-reflection" 6 | repository = "https://github.com/zefchain/serde-reflection" 7 | authors = ["Mathieu Baudet "] 8 | license = "MIT OR Apache-2.0" 9 | readme = "README.md" 10 | keywords = ["data-structures", "serialization", "serde"] 11 | categories = ["encoding", "development-tools"] 12 | edition = "2021" 13 | rust-version = "1.60" 14 | exclude = [ 15 | # Readme template that doesn't need to be included. 16 | "README.tpl", 17 | ] 18 | 19 | [dependencies] 20 | erased-discriminant = "1" 21 | once_cell = "1.7.2" 22 | serde = { version = "1.0.126", features = ["derive"] } 23 | thiserror = "1.0.25" 24 | typeid = "1" 25 | 26 | [dev-dependencies] 27 | bincode = "1.3.3" 28 | serde_json = "1.0.64" 29 | serde_yaml = "0.8.17" 30 | serde_bytes = "0.11.5" 31 | -------------------------------------------------------------------------------- /serde-reflection/README.tpl: -------------------------------------------------------------------------------- 1 | # {{crate}} 2 | 3 | [![serde-reflection on crates.io](https://img.shields.io/crates/v/serde-reflection)](https://crates.io/crates/serde-reflection) 4 | [![Documentation (latest release)](https://docs.rs/serde-reflection/badge.svg)](https://docs.rs/serde-reflection/) 5 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](../LICENSE-APACHE) 6 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](../LICENSE-MIT) 7 | 8 | {{readme}} 9 | 10 | ## Contributing 11 | 12 | See the [CONTRIBUTING](../CONTRIBUTING.md) file for how to help out. 13 | 14 | ## License 15 | 16 | This project is available under the terms of either the [Apache 2.0 license](../LICENSE-APACHE) or the [MIT license](../LICENSE-MIT). 17 | 18 | 24 | --------------------------------------------------------------------------------