├── .devcontainer └── devcontainer.json ├── .github └── workflows │ ├── bump-major.yml │ ├── bump-minor.yml │ ├── bump-patch.yml │ ├── bump.bash │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── msgpack-schema-impl ├── Cargo.toml ├── LICENSE └── src │ ├── attr.rs │ ├── deserialize.rs │ ├── lib.rs │ └── serialize.rs ├── msgpack-value ├── Cargo.toml ├── LICENSE └── src │ └── lib.rs ├── proptest-regressions └── lib.txt ├── src └── lib.rs └── tests ├── test.proptest-regressions ├── test.rs └── ui ├── duplicate.rs ├── duplicate.stderr ├── field.rs ├── field.stderr ├── item.rs ├── item.stderr ├── tag.rs ├── tag.stderr ├── tag_uniqueness.rs ├── tag_uniqueness.stderr ├── unit.rs ├── unit.stderr ├── variant.rs └── variant.stderr /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. 2 | { 3 | "name": "Default", 4 | "image": "mcr.microsoft.com/devcontainers/rust:latest" 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/bump-major.yml: -------------------------------------------------------------------------------- 1 | name: Create "Bump major version" Pull Request 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 8 | GIT_COMMITTER_NAME: github-actions[bot] 9 | GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 10 | GIT_AUTHOR_NAME: github-actions[bot] 11 | GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 12 | 13 | jobs: 14 | bump: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | - run: .github/workflows/bump.bash major 21 | -------------------------------------------------------------------------------- /.github/workflows/bump-minor.yml: -------------------------------------------------------------------------------- 1 | name: Create "Bump minor version" Pull Request 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 8 | GIT_COMMITTER_NAME: github-actions[bot] 9 | GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 10 | GIT_AUTHOR_NAME: github-actions[bot] 11 | GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 12 | 13 | jobs: 14 | bump: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | - run: .github/workflows/bump.bash minor 21 | -------------------------------------------------------------------------------- /.github/workflows/bump-patch.yml: -------------------------------------------------------------------------------- 1 | name: Create "Bump patch version" Pull Request 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 8 | GIT_COMMITTER_NAME: github-actions[bot] 9 | GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 10 | GIT_AUTHOR_NAME: github-actions[bot] 11 | GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com 12 | 13 | jobs: 14 | bump: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | - run: .github/workflows/bump.bash patch 21 | -------------------------------------------------------------------------------- /.github/workflows/bump.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Usage: ./bump.bash [major|minor|patch] 3 | 4 | VERSION=$(cargo read-manifest | jq -r .version) 5 | MAJOR=$(echo "$VERSION" | cut -d . -f 1) 6 | MINOR=$(echo "$VERSION" | cut -d . -f 2) 7 | PATCH=$(echo "$VERSION" | cut -d . -f 3) 8 | case $1 in 9 | major) 10 | NEW_VERSION=$(printf "%s.0.0\n" $((MAJOR + 1)));; 11 | minor) 12 | NEW_VERSION=$(printf "%s.%s.0\n" "$MAJOR" $((MINOR + 1)));; 13 | patch) 14 | NEW_VERSION=$(printf "%s.%s.%s\n" "$MAJOR" "$MINOR" $((PATCH + 1)));; 15 | *) 16 | echo invalid argument >&1 17 | exit 1 18 | esac 19 | 20 | function bump_changelog { 21 | CHANGELOG=$1 22 | 23 | awk '/## Unreleased/,0{next}{print}' "$CHANGELOG" 24 | 25 | cat - << EOS 26 | ## Unreleased 27 | 28 | ### Added 29 | 30 | ### Fixed 31 | 32 | ### Removed 33 | 34 | ### Changed 35 | 36 | --- 37 | 38 | ## $NEW_VERSION - $(date "+%Y-%m-%d") 39 | EOS 40 | 41 | read -r -d '' PROG << 'EOS' 42 | /###.*/ { 43 | section = $0 44 | next 45 | } 46 | { 47 | if (section) { 48 | print "" 49 | print section 50 | print "" 51 | section = "" 52 | } 53 | print 54 | } 55 | END{print ""} 56 | EOS 57 | awk '/## Unreleased/,/---/' "$CHANGELOG" | awk '/./&&!/---/&&NR>1' | awk -v NEW_VERSION="$NEW_VERSION" "$PROG" 58 | awk '/---/,0{print}' "$CHANGELOG" | awk 'NR>2' 59 | } 60 | 61 | function bump_manifest { 62 | MANIFEST=$1 63 | awk -v NEW_VERSION="$NEW_VERSION" '/^version = .*/{printf "version = \"%s\"\n", NEW_VERSION;next}{print}' "$MANIFEST" 64 | } 65 | 66 | git switch -c release/"$NEW_VERSION" 67 | 68 | # https://stackoverflow.com/a/73054135 69 | # shellcheck disable=SC2094 70 | cat <<< "$(bump_changelog CHANGELOG.md)" > CHANGELOG.md 71 | # shellcheck disable=SC2094 72 | cat <<< "$(bump_manifest msgpack-schema-impl/Cargo.toml)" > msgpack-schema-impl/Cargo.toml 73 | # shellcheck disable=SC2094 74 | cat <<< "$(bump_manifest msgpack-value/Cargo.toml)" > msgpack-value/Cargo.toml 75 | # shellcheck disable=SC2094 76 | cat <<< "$(bump_manifest Cargo.toml)" > Cargo.toml 77 | sed -i "s/version = \"=$VERSION\"/version = \"=$NEW_VERSION\"/g" Cargo.toml 78 | 79 | git add . 80 | git commit -m "bump $NEW_VERSION" 81 | git push -u origin HEAD 82 | 83 | gh pr create --base master --title "Bump version $NEW_VERSION" --body "Bump $1 version" --label release 84 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: CI 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | CARGO_INCREMENTAL: 0 8 | RUST_BACKTRACE: 1 9 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 10 | 11 | jobs: 12 | check: 13 | name: Check 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout sources 17 | uses: actions/checkout@v3 18 | 19 | - name: Install stable toolchain 20 | run: | 21 | rustup toolchain install stable --profile minimal --no-self-update 22 | rustup default stable 23 | 24 | - name: Enable Rust build cache 25 | uses: Swatinem/rust-cache@v2 26 | 27 | - name: Run cargo check 28 | run: | 29 | cargo check 30 | 31 | test: 32 | name: Test 33 | runs-on: ubuntu-latest 34 | steps: 35 | - name: Checkout sources 36 | uses: actions/checkout@v3 37 | 38 | - name: Install stable toolchain 39 | run: | 40 | rustup toolchain install stable --profile minimal --no-self-update 41 | rustup default stable 42 | 43 | - name: Enable Rust build cache 44 | uses: Swatinem/rust-cache@v2 45 | 46 | - name: Run cargo test 47 | run: | 48 | cargo test 49 | 50 | lints: 51 | name: Lints 52 | runs-on: ubuntu-latest 53 | steps: 54 | - name: Checkout sources 55 | uses: actions/checkout@v3 56 | 57 | - name: Install stable toolchain 58 | run: | 59 | rustup toolchain install stable --profile minimal --no-self-update 60 | rustup default stable 61 | 62 | - name: Enable Rust build cache 63 | uses: Swatinem/rust-cache@v2 64 | 65 | - name: Run cargo fmt 66 | run: | 67 | cargo fmt --all -- --check 68 | 69 | - name: Run cargo clippy 70 | run: | 71 | cargo clippy -- -D warnings 72 | 73 | - name: Run cargo rdme 74 | run: | 75 | cargo install cargo-rdme 76 | cargo rdme --check 77 | 78 | release: 79 | name: Release 80 | if: github.repository == 'Idein/msgpack-schema' && github.event_name == 'push' && github.ref == 'refs/heads/master' 81 | runs-on: ubuntu-latest 82 | steps: 83 | - name: Checkout sources 84 | uses: actions/checkout@v3 85 | 86 | - name: Run cargo publish 87 | run: | 88 | cargo publish --no-verify -p msgpack-schema-impl || : 89 | cargo publish --no-verify -p msgpack-value || : 90 | sleep 15 91 | cargo publish --no-verify -p msgpack-schema || : 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | msgpack-schema-impl/target/ 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## Unreleased 8 | 9 | ### Added 10 | 11 | ### Fixed 12 | 13 | ### Removed 14 | 15 | ### Changed 16 | 17 | --- 18 | 19 | ## 1.1.0 - 2023-07-15 20 | 21 | ### Added 22 | 23 | - Add `serialize_into` 24 | - Add the `proptest` feature flag to opt-out `proptest` impls 25 | 26 | ## 1.0.1 - 2023-07-03 27 | 28 | ### Fixed 29 | 30 | - Fix Variable Capture bug for "value" struct field name 31 | 32 | ## 1.0.0 - 2023-06-21 33 | 34 | ### Added 35 | 36 | - Add more docs 37 | - Add `impl Default for Value` 38 | 39 | ## 0.8.1 - 2023-06-18 40 | 41 | ### Fixed 42 | 43 | - Indexing must return the last value 44 | 45 | ## 0.8.0 - 2023-06-18 46 | 47 | ### Added 48 | 49 | - Add `Index` impls for `msgpack_value::Value` 50 | 51 | ## 0.7.0 - 2023-06-04 52 | 53 | ### Added 54 | 55 | - Restore `msgpack_schema::value` as a hidden module. 56 | 57 | ## 0.6.0 - 2023-04-21 58 | 59 | ### Added 60 | 61 | - Add more docs 62 | - Add `Deserializer::{try_deserialize, deserialize_any}` 63 | 64 | ### Removed 65 | 66 | - Remove `msgpack_schema::value` module. Use `msgpack_value` instead. 67 | 68 | ### Changed 69 | 70 | - Turn `Token` into a non-owning type. 71 | - Use last-value-wins strategy for duplicate keys. (following JSON) 72 | 73 | ## 0.5.0 - 2023-03-12 74 | 75 | ### Added 76 | 77 | - Add `msgpack-value` crate 78 | - Implement `proptest::arbitrary::Arbitrary` for `msgpack_value::Value` and others 79 | - Implement `Serialize` and `Deserialize` for `Box`, `Rc`, and `Arc` 80 | 81 | ### Changed 82 | 83 | - Add more tests 84 | 85 | ## 0.4.2 - 2022-01-25 86 | 87 | ### Changed 88 | 89 | - Bump Rust edition to 2021 (no user-facing changes) 90 | 91 | ## 0.4.1 - 2021-07-29 92 | 93 | ### Added 94 | 95 | - Add `value::Empty` 96 | - Support tuple structs (with more than one field) 97 | 98 | ## 0.4.0 - 2021-07-19 99 | 100 | ### Added 101 | 102 | - Report errors when there are attributes in an invalid position 103 | - (experimental) Add `schema` attribute 104 | - Support `#[flatten]` 105 | 106 | ### Removed 107 | 108 | - Remove `Serialize` and `Deserialize` impls for `Option` 109 | 110 | ## 0.3.1 - 2021-06-21 111 | 112 | ### Fixed 113 | 114 | - Fix Cargo dependency bound. 115 | 116 | ## 0.3.0 - 2021-06-17 117 | 118 | ### Added 119 | 120 | - Add `Ext` type. 121 | - Support untagged structs. 122 | 123 | ### Removed 124 | 125 | - Hide `msgpack` macro. 126 | - All inherent methods of `Token`. 127 | 128 | ### Changed 129 | 130 | - Change the types of `serialize` and `deserialize`. 131 | - `Serialize` never throws an error. 132 | - `DeserializeError` no longer contains detailed information. 133 | - `Deserializer` and `Serializer` are now structs. 134 | 135 | ## 0.2.1 - 2021-06-15 136 | 137 | ### Added 138 | 139 | - Restore `DeserializeError::InvalidValue` as a unit variant. 140 | 141 | ## 0.2.0 - 2021-06-15 142 | 143 | ### Removed 144 | 145 | - Remove `DeserializeError::InvalidValue` to allow the `DeserializeError` type to be `Send` and `Sync`. 146 | 147 | ## 0.1.6 - 2021-06-12 148 | 149 | ### Added 150 | 151 | - Add `msgpack` macro. 152 | 153 | ### Removed 154 | 155 | - Remove `BinarySerializer` and `BinaryDeserializer`. Use `serialize` and `deserialize` instead. 156 | 157 | ## 0.1.5 - 2021-06-12 158 | 159 | ### Fixed 160 | 161 | - Fix serialization of 0-length map value 162 | - Fix deserialization of FixExt8 and FixExt16 163 | 164 | ## 0.1.4 - 2021-06-12 165 | 166 | ### Fixed 167 | 168 | - Fix doc test failure. 169 | 170 | ## 0.1.3 - 2021-06-12 171 | 172 | This release mainly includes doc improvements and typo fixes. 173 | 174 | ### Removed 175 | 176 | - `Value` 177 | - `TryFromValueError` 178 | - `value::{Serializer, Deserializer, serialize, deserialize}` 179 | 180 | ### Changed 181 | 182 | - Move `Any` to `value::Any` 183 | - Move `Nil` to `value::Nil` 184 | 185 | ## 0.1.2 - 2021-06-10 186 | 187 | ### Added 188 | 189 | - Add a blanket implementation `impl Serialize for &T` 190 | 191 | ## 0.1.1 - 2021-06-08 192 | 193 | Initial version 194 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | default-members = [".", "msgpack-schema-impl", "msgpack-value"] 3 | 4 | [package] 5 | name = "msgpack-schema" 6 | version = "1.1.0" 7 | authors = ["Yuichi Nishiwaki "] 8 | edition = "2021" 9 | description = "A specification language for MessagePack data format" 10 | license = "MIT" 11 | repository = "https://github.com/Idein/msgpack-schema" 12 | documentation = "https://docs.rs/msgpack-schema" 13 | categories = ["encoding"] 14 | 15 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 16 | 17 | [features] 18 | default = ["proptest"] 19 | proptest = ["msgpack-value/proptest"] 20 | 21 | [dependencies] 22 | msgpack-schema-impl = { version = "=1.1.0", path = "./msgpack-schema-impl" } 23 | msgpack-value = { version = "=1.1.0", path = "./msgpack-value", default-features = false } 24 | rmp = "0.8" 25 | thiserror = "^1.0.25" 26 | byteorder = "1" 27 | 28 | [dev-dependencies] 29 | trybuild = "1.0" 30 | proptest = "1" 31 | proptest-derive = "0.3" 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # msgpack-schema [![Crates.io](https://img.shields.io/crates/v/msgpack-schema)](https://crates.io/crates/msgpack-schema) [![docs.rs](https://img.shields.io/docsrs/msgpack-schema)](https://docs.rs/msgpack-schema/) [![CI](https://github.com/Idein/msgpack-schema/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Idein/msgpack-schema/actions/workflows/ci.yml) 2 | 3 | 4 | 5 | _msgpack-schema_ is a schema language for describing data formats encoded in MessagePack. 6 | It provides two derive macros `Serialize` and `Deserialize` that allow you to transcode MessagePack binary data to/from Rust data structures in a type-directed way. 7 | 8 | ```rust 9 | use msgpack_schema::{Deserialize, Serialize}; 10 | 11 | #[derive(Deserialize, Serialize)] 12 | struct Human { 13 | #[tag = 0] 14 | name: String, 15 | #[tag = 2] 16 | #[optional] 17 | age: Option, 18 | } 19 | ``` 20 | 21 | Compared with other schema languages like `rmp-serde`, `msgpack-schema` allows to specify more compact data representation, e.g., fixints as field keys, fixints as variant keys, etc. 22 | 23 | ## Feature flags 24 | 25 | - `proptest`: Enable `proptest::arbitrary::Arbitrary` impls for `msgpack_value::Value`. 26 | 27 | ## Behaviours of serializers and deserializers 28 | 29 | ### Structs with named fields 30 | 31 | Structs with named fields are serialized into a `Map` object where keys are fixints specified by `#[tag]` attributes. 32 | The current implementation serializes fields in order but one must not rely on this behavior. 33 | 34 | The deserializer interprets `Map` objects to create such structs. 35 | Field order is irrelevant to the result. 36 | If `Map` objects contains extra key-value pairs which are not contained in the definition of the struct, the deserializer simply ignores them. 37 | If there are two or more values with the same key within a `Map` object, the preceding value is overwritten by the last value. 38 | 39 | ```rust 40 | #[derive(Serialize, Deserialize)] 41 | struct S { 42 | #[tag = 0] 43 | x: u32, 44 | #[tag = 1] 45 | y: String, 46 | } 47 | 48 | let s = S { 49 | x: 42, 50 | y: "hello".to_owned(), 51 | }; 52 | 53 | let b = b"\x82\x00\x2A\x01\xA5\x68\x65\x6c\x6c\x6f"; // 10 bytes; `{ 0: 42, 1: "hello" }` 54 | assert_eq!(serialize(&s), b); 55 | assert_eq!(s, deserialize(b).unwrap()); 56 | 57 | // ignores irrelevant key-value pairs 58 | let b = b"\x83\x00\x2A\x02\xC3\x01\xA5\x68\x65\x6c\x6c\x6f"; // 12 bytes; `{ 0: 42, 2: true, 1: "hello" }` 59 | assert_eq!(s, deserialize(b).unwrap()); 60 | 61 | // last value wins 62 | let b = b"\x83\x00\xC3\x00\x2A\x01\xA5\x68\x65\x6c\x6c\x6f"; // 12 bytes; `{ 0: true, 0: 42, 1: "hello" }` 63 | assert_eq!(s, deserialize(b).unwrap()); 64 | ``` 65 | 66 | Fields in named structs may be tagged with `#[optional]`. 67 | 68 | - The tagged field must be of type `Option`. 69 | - On serialization, the key-value pair will not be included in the result map object when the field data contains `None`. 70 | - On deserialization, the field of the result struct will be filled with `None` when the given MsgPack map object contains no corresponding key-value pair. 71 | 72 | ```rust 73 | #[derive(Serialize, Deserialize)] 74 | struct S { 75 | #[tag = 0] 76 | x: u32, 77 | #[optional] 78 | #[tag = 1] 79 | y: Option, 80 | } 81 | 82 | let s = S { 83 | x: 42, 84 | y: Some("hello".to_owned()), 85 | }; 86 | let b = b"\x82\x00\x2A\x01\xA5\x68\x65\x6c\x6c\x6f"; // 10 bytes; `{ 0: 42, 1: "hello" }` 87 | assert_eq!(serialize(&s), b); 88 | assert_eq!(s, deserialize(b).unwrap()); 89 | 90 | let s = S { 91 | x: 42, 92 | y: None, 93 | }; 94 | let b = b"\x81\x00\x2A"; // 3 bytes; `{ 0: 42 }` 95 | assert_eq!(serialize(&s), b); 96 | assert_eq!(s, deserialize(b).unwrap()); 97 | ``` 98 | 99 | The `#[flatten]` attribute is used to factor out a single definition of named struct into multiple ones. 100 | 101 | ```rust 102 | #[derive(Serialize)] 103 | struct S1 { 104 | #[tag = 1] 105 | x: u32, 106 | } 107 | 108 | #[derive(Serialize)] 109 | struct S2 { 110 | #[flatten] 111 | s1: S1, 112 | #[tag = 2] 113 | y: u32, 114 | } 115 | 116 | #[derive(Serialize)] 117 | struct S3 { 118 | #[tag = 1] 119 | x: u32, 120 | #[tag = 2] 121 | y: u32, 122 | } 123 | 124 | assert_eq!(serialize(S2 { s1: S1 { x: 42 }, y: 43, }), serialize(S3 { x: 42, y: 43 })); 125 | ``` 126 | 127 | Structs with named fields may be attached `#[untagged]`. 128 | Untagged structs are serialized into an array and will not contain tags. 129 | 130 | ```rust 131 | #[derive(Serialize, Deserialize)] 132 | #[untagged] 133 | struct S { 134 | x: u32, 135 | y: String, 136 | } 137 | 138 | let s = S { 139 | x: 42, 140 | y: "hello".to_owned(), 141 | }; 142 | let b = b"\x92\x2A\xA5\x68\x65\x6c\x6c\x6f"; // 8 bytes; `[ 42, "hello" ]` 143 | 144 | assert_eq!(serialize(&s), b); 145 | assert_eq!(s, deserialize(b).unwrap()); 146 | ``` 147 | 148 | ### Newtype structs 149 | 150 | Tuple structs with only one element are treated transparently. 151 | 152 | ```rust 153 | #[derive(Serialize, Deserialize)] 154 | struct S(u32); 155 | 156 | let s = S(42); 157 | let b = b"\x2A"; // 1 byte; `42` 158 | 159 | assert_eq!(serialize(&s), b); 160 | assert_eq!(s, deserialize(b).unwrap()); 161 | ``` 162 | 163 | ### Unit structs and empty tuple structs 164 | 165 | Serialization and deserialization of unit structs and empty tuple structs are intentionally unsupported. 166 | 167 | ```rust 168 | // It is error to derive `Serialize` / `Deserialize` for these types of structs. 169 | struct S1; 170 | struct S2(); 171 | ``` 172 | 173 | ### Tuple structs 174 | 175 | Tuple structs with more than one element are encoded as an array. 176 | It is validation error to deserialize an array with unmatched length. 177 | 178 | ```rust 179 | #[derive(Serialize, Deserialize)] 180 | struct S(u32, bool); 181 | 182 | let s = S(42, true); 183 | let b = b"\x92\x2A\xC3"; // 3 bytes; `[ 42, true ]` 184 | 185 | assert_eq!(serialize(&s), b); 186 | assert_eq!(s, deserialize(b).unwrap()); 187 | ``` 188 | 189 | ### Unit variants and empty tuple variants 190 | 191 | Unit variants and empty tuple variants are serialized into a single fixint whose value is determined by the tag. 192 | 193 | ```rust 194 | #[derive(Serialize, Deserialize)] 195 | enum E { 196 | #[tag = 3] 197 | Foo 198 | } 199 | 200 | let e = E::Foo; 201 | let b = b"\x03"; // 1 byte; `3` 202 | 203 | assert_eq!(serialize(&e), b); 204 | assert_eq!(e, deserialize(b).unwrap()); 205 | ``` 206 | 207 | ```rust 208 | #[derive(Serialize, Deserialize)] 209 | enum E { 210 | #[tag = 3] 211 | Foo() 212 | } 213 | 214 | let e = E::Foo(); 215 | let b = b"\x03"; // 1 byte; `3` 216 | 217 | assert_eq!(serialize(&e), b); 218 | assert_eq!(e, deserialize(b).unwrap()); 219 | ``` 220 | 221 | ### Newtype variants 222 | 223 | Newtype variants (one-element tuple variants) are serialized into an array of the tag and the inner value. 224 | 225 | ```rust 226 | #[derive(Serialize, Deserialize)] 227 | enum E { 228 | #[tag = 3] 229 | Foo(u32) 230 | } 231 | 232 | let e = E::Foo(42); 233 | let b = b"\x92\x03\x2A"; // 3 bytes; `[ 3, 42 ]` 234 | 235 | assert_eq!(serialize(&e), b); 236 | assert_eq!(e, deserialize(b).unwrap()); 237 | ``` 238 | 239 | ### Untagged variants 240 | 241 | Enums may be attached `#[untagged]` when all variants are newtype variants. 242 | Serializing untagged variants results in the same data layout as the inner type. 243 | The deserializer deserializes into an untagged enum type by trying deserization one by one from the first variant to the last. 244 | 245 | ```rust 246 | #[derive(Serialize, Deserialize)] 247 | #[untagged] 248 | enum E { 249 | Foo(String), 250 | Bar(u32), 251 | } 252 | 253 | let e = E::Bar(42); 254 | let b = b"\x2A"; // 1 byte; `42` 255 | 256 | assert_eq!(serialize(&e), b); 257 | assert_eq!(e, deserialize(b).unwrap()); 258 | ``` 259 | 260 | ## Write your own implementation of `Serialize` and `Deserialize` 261 | 262 | You may want to write your own implementation of `Serialize` and `Deserialize` in the following cases: 263 | 264 | 1. You need `impl` for types that are already defined by someone. 265 | 2. You need extreme efficiency. 266 | 3. Both. 267 | 268 | [IpAddr](std::net::IpAddr) is such a type satisfying (3). 269 | In the most efficient situation, we want it to be 4 or 16 byte length plus one byte for a tag at any time. 270 | This is achieved by giving a hard-written implementation like below. 271 | 272 | ```rust 273 | struct IpAddr(pub std::net::IpAddr); 274 | 275 | impl Serialize for IpAddr { 276 | fn serialize(&self, serializer: &mut Serializer) { 277 | match self.0 { 278 | std::net::IpAddr::V4(v4) => { 279 | serializer.serialize_str(&v4.octets()); // 5 bytes 280 | } 281 | std::net::IpAddr::V6(v6) => { 282 | serializer.serialize_str(&v6.octets()); // 17 bytes 283 | } 284 | } 285 | } 286 | } 287 | 288 | impl Deserialize for IpAddr { 289 | fn deserialize(deserializer: &mut Deserializer) -> Result { 290 | let Str(data) = deserializer.deserialize()?; 291 | let ipaddr = match data.len() { 292 | 4 => std::net::IpAddr::V4(std::net::Ipv4Addr::from( 293 | <[u8; 4]>::try_from(data).unwrap(), 294 | )), 295 | 16 => std::net::IpAddr::V6(std::net::Ipv6Addr::from( 296 | <[u8; 16]>::try_from(data).unwrap(), 297 | )), 298 | _ => return Err(ValidationError.into()), 299 | }; 300 | Ok(Self(ipaddr)) 301 | } 302 | } 303 | ``` 304 | 305 | ## Appendix: Cheatsheet 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 323 | 326 | 329 | 330 | 331 | 339 | 342 | 345 | 346 | 347 | 355 | 358 | 361 | 362 | 363 | 373 | 376 | 379 | 380 | 381 | 384 | 387 | 390 | 391 | 392 | 395 | 398 | 399 | 400 | 401 | 404 | 407 | 408 | 409 | 410 | 413 | 416 | 419 | 420 | 421 | 427 | 430 | 433 | 434 | 435 | 441 | 444 | 447 | 448 | 449 | 455 | 458 | 461 | 462 | 463 | 470 | 473 | 476 | 477 |
schemaRustMessagePack (human readable)
315 |
struct S {
316 |     #[tag = 0]
317 |     x: u32,
318 |     #[tag = 1]
319 |     y: bool,
320 | }
321 | 
322 |
324 | S { x: 42, y: true } 325 | 327 | { 0: 42, 1: true } 328 |
332 |
struct S {
333 |     #[optional]
334 |     #[tag = 0]
335 |     x: Option<u32>,
336 | }
337 | 
338 |
340 | S { x: Some(42) } 341 | 343 | { 0: 42 } 344 |
348 |
struct S {
349 |     #[optional]
350 |     #[tag = 0]
351 |     x: Option<u32>,
352 | }
353 | 
354 |
356 | S { x: None } 357 | 359 | {} 360 |
364 |
#[untagged]
365 | struct S {
366 |     #[tag = 0]
367 |     x: u32,
368 |     #[tag = 1]
369 |     y: bool,
370 | }
371 | 
372 |
374 | S { x: 42, y: true } 375 | 377 | [ 42, true ] 378 |
382 | struct S(u32) 383 | 385 | S(42) 386 | 388 | 42 389 |
393 | struct S 394 | 396 | S 397 | UNSUPPORTED
402 | struct S() 403 | 405 | S() 406 | UNSUPPORTED
411 | struct S(u32, bool) 412 | 414 | S(42, true) 415 | 417 | [ 42, true ] 418 |
422 |
enum E {
423 |     #[tag = 3]
424 |     Foo
425 | }
426 |
428 | E::Foo 429 | 431 | 3 432 |
436 |
enum E {
437 |     #[tag = 3]
438 |     Foo()
439 | }
440 |
442 | E::Foo() 443 | 445 | 3 446 |
450 |
enum E {
451 |     #[tag = 3]
452 |     Foo(u32)
453 | }
454 |
456 | E::Foo(42) 457 | 459 | [ 3, 42 ] 460 |
464 |
#[untagged]
465 | enum E {
466 |     Foo(u32)
467 |     Bar(bool)
468 | }
469 |
471 | E::Bar(true) 472 | 474 | true 475 |
478 | 479 | 480 | 481 | #### License 482 | 483 | 484 | Licensed under MIT license. 485 | 486 | 487 |
488 | 489 | 490 | Unless you explicitly state otherwise, any contribution intentionally submitted 491 | for inclusion in msgpack-schema by you shall be licensed as above, without any additional terms or conditions. 492 | 493 | -------------------------------------------------------------------------------- /msgpack-schema-impl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "msgpack-schema-impl" 3 | version = "1.1.0" 4 | authors = ["Yuichi Nishiwaki "] 5 | edition = "2021" 6 | description = "Implementation detail of the msgpack-schema crate" 7 | license = "MIT" 8 | repository = "https://github.com/Idein/msgpack-schema" 9 | 10 | [lib] 11 | proc-macro = true 12 | 13 | [dependencies] 14 | proc-macro2 = "1.0" 15 | quote = "1.0" 16 | syn = "2.0" 17 | -------------------------------------------------------------------------------- /msgpack-schema-impl/LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /msgpack-schema-impl/src/attr.rs: -------------------------------------------------------------------------------- 1 | use quote::ToTokens; 2 | use syn::{ 3 | parse::{ParseStream, Parser}, 4 | Attribute, Error, LitInt, Result, Token, 5 | }; 6 | 7 | pub struct Attrs<'a> { 8 | pub tag: Option>, 9 | pub optional: Option>, 10 | pub untagged: Option>, 11 | pub flatten: Option>, 12 | } 13 | 14 | #[derive(Clone)] 15 | pub struct Tag<'a> { 16 | pub original: &'a Attribute, 17 | pub tag: u32, 18 | } 19 | 20 | #[derive(Clone)] 21 | pub struct Optional<'a> { 22 | pub original: &'a Attribute, 23 | } 24 | 25 | #[derive(Clone)] 26 | pub struct Untagged<'a> { 27 | pub original: &'a Attribute, 28 | } 29 | 30 | #[derive(Clone)] 31 | pub struct Flatten<'a> { 32 | pub original: &'a Attribute, 33 | } 34 | 35 | pub fn get(attrs: &[Attribute]) -> Result { 36 | let mut output = Attrs { 37 | tag: None, 38 | optional: None, 39 | untagged: None, 40 | flatten: None, 41 | }; 42 | 43 | for attr in attrs { 44 | if attr.path().is_ident("schema") { 45 | parse_schema_attribute(&mut output, attr)?; 46 | } else if attr.path().is_ident("tag") { 47 | let name_value = attr.meta.require_name_value()?; 48 | let parser = |input: ParseStream| { 49 | let lit_int = input.parse::()?; 50 | let tag = lit_int.base10_parse::()?; 51 | Ok(tag) 52 | }; 53 | let tag = parser.parse2(name_value.value.to_token_stream())?; 54 | if output.tag.is_some() { 55 | return Err(Error::new_spanned(attr, "duplicate #[tag] attribute")); 56 | } 57 | output.tag = Some(Tag { 58 | original: attr, 59 | tag, 60 | }) 61 | } else if attr.path().is_ident("untagged") { 62 | attr.meta.require_path_only()?; 63 | if output.untagged.is_some() { 64 | return Err(Error::new_spanned(attr, "duplicate #[untagged] attribute")); 65 | } 66 | output.untagged = Some(Untagged { original: attr }); 67 | } else if attr.path().is_ident("optional") { 68 | attr.meta.require_path_only()?; 69 | if output.optional.is_some() { 70 | return Err(Error::new_spanned(attr, "duplicate #[optional] attribute")); 71 | } 72 | output.optional = Some(Optional { original: attr }); 73 | } else if attr.path().is_ident("flatten") { 74 | attr.meta.require_path_only()?; 75 | if output.flatten.is_some() { 76 | return Err(Error::new_spanned(attr, "duplicate #[flatten] attribute")); 77 | } 78 | output.flatten = Some(Flatten { original: attr }); 79 | } 80 | } 81 | Ok(output) 82 | } 83 | 84 | fn parse_schema_attribute<'a>(output: &mut Attrs<'a>, attr: &'a Attribute) -> Result<()> { 85 | syn::custom_keyword!(optional); 86 | syn::custom_keyword!(tag); 87 | syn::custom_keyword!(untagged); 88 | syn::custom_keyword!(flatten); 89 | 90 | attr.parse_args_with(|input: ParseStream| { 91 | if let Some(_kw) = input.parse::>()? { 92 | if output.optional.is_some() { 93 | return Err(Error::new_spanned(attr, "duplicate #[optional] attribute")); 94 | } 95 | output.optional = Some(Optional { original: attr }); 96 | return Ok(()); 97 | } else if let Some(_kw) = input.parse::>()? { 98 | if output.untagged.is_some() { 99 | return Err(Error::new_spanned(attr, "duplicate #[untagged] attribute")); 100 | } 101 | output.untagged = Some(Untagged { original: attr }); 102 | return Ok(()); 103 | } else if let Some(_kw) = input.parse::>()? { 104 | if output.flatten.is_some() { 105 | return Err(Error::new_spanned(attr, "duplicate #[flatten] attribute")); 106 | } 107 | output.flatten = Some(Flatten { original: attr }); 108 | return Ok(()); 109 | } else if let Some(_kw) = input.parse::>()? { 110 | let _eq_token: Token![=] = input.parse()?; 111 | let lit_int = input.parse::()?; 112 | let tag = lit_int.base10_parse::()?; 113 | if output.tag.is_some() { 114 | return Err(Error::new_spanned(attr, "duplicate #[tag] attribute")); 115 | } 116 | output.tag = Some(Tag { 117 | original: attr, 118 | tag, 119 | }); 120 | return Ok(()); 121 | } 122 | let lit_int: LitInt = input.parse()?; 123 | let tag = lit_int.base10_parse::()?; 124 | if output.tag.is_some() { 125 | return Err(Error::new_spanned(attr, "duplicate #[tag] attribute")); 126 | } 127 | output.tag = Some(Tag { 128 | original: attr, 129 | tag, 130 | }); 131 | Ok(()) 132 | }) 133 | } 134 | 135 | impl<'a> Attrs<'a> { 136 | pub fn disallow_tag(&self) -> Result<()> { 137 | if let Some(tag) = self.tag.clone() { 138 | return Err(Error::new_spanned( 139 | tag.original, 140 | "#[tag] at an invalid position", 141 | )); 142 | } 143 | Ok(()) 144 | } 145 | 146 | pub fn disallow_optional(&self) -> Result<()> { 147 | if let Some(optional) = &self.optional { 148 | return Err(Error::new_spanned( 149 | optional.original, 150 | "#[optional] at an invalid position", 151 | )); 152 | } 153 | Ok(()) 154 | } 155 | 156 | pub fn disallow_untagged(&self) -> Result<()> { 157 | if let Some(untagged) = &self.untagged { 158 | return Err(Error::new_spanned( 159 | untagged.original, 160 | "#[untagged] at an invalid position", 161 | )); 162 | } 163 | Ok(()) 164 | } 165 | 166 | pub fn disallow_flatten(&self) -> Result<()> { 167 | if let Some(flatten) = &self.flatten { 168 | return Err(Error::new_spanned( 169 | flatten.original, 170 | "#[flatten] at an invalid position", 171 | )); 172 | } 173 | Ok(()) 174 | } 175 | 176 | pub fn require_tag(&self, tokens: impl ToTokens) -> Result<()> { 177 | if self.tag.is_none() { 178 | return Err(Error::new_spanned(tokens, "no #[tag] given")); 179 | } 180 | Ok(()) 181 | } 182 | } 183 | 184 | pub fn check_tag_uniqueness(tag: &Tag, tags: &mut Vec) -> Result<()> { 185 | if tags.iter().any(|t| *t == tag.tag) { 186 | return Err(Error::new_spanned( 187 | tag.original, 188 | "tag values must not be duplicate", 189 | )); 190 | } 191 | tags.push(tag.tag); 192 | Ok(()) 193 | } 194 | -------------------------------------------------------------------------------- /msgpack-schema-impl/src/deserialize.rs: -------------------------------------------------------------------------------- 1 | use crate::attr; 2 | use proc_macro2::TokenStream; 3 | use quote::quote; 4 | use syn::{ 5 | Data, DataEnum, DataStruct, DeriveInput, Error, Fields, FieldsNamed, FieldsUnnamed, Result, 6 | }; 7 | 8 | pub fn derive(node: &DeriveInput) -> Result { 9 | let attrs = attr::get(&node.attrs)?; 10 | attrs.disallow_optional()?; 11 | attrs.disallow_tag()?; 12 | attrs.disallow_flatten()?; 13 | match &node.data { 14 | Data::Struct(strut) => match &strut.fields { 15 | Fields::Named(fields) => { 16 | if attrs.untagged.is_some() { 17 | derive_untagged_struct(node, strut, fields) 18 | } else { 19 | derive_struct(node, strut, fields) 20 | } 21 | } 22 | Fields::Unnamed(fields) => { 23 | attrs.disallow_untagged()?; 24 | let len = fields.unnamed.len(); 25 | match len { 26 | 0 => Err(Error::new_spanned( 27 | node, 28 | "empty tuple structs as deserialize are not supported", 29 | )), 30 | 1 => derive_newtype_struct(node, strut, &fields.unnamed[0]), 31 | _ => derive_tuple_struct(node, strut, fields), 32 | } 33 | } 34 | Fields::Unit => { 35 | attrs.disallow_untagged()?; 36 | Err(Error::new_spanned( 37 | node, 38 | "unit structs as deserialize are not supported", 39 | )) 40 | } 41 | }, 42 | Data::Enum(enu) => { 43 | if attrs.untagged.is_some() { 44 | derive_untagged_enum(node, enu) 45 | } else { 46 | derive_enum(node, enu) 47 | } 48 | } 49 | Data::Union(_) => Err(Error::new_spanned( 50 | node, 51 | "union as deserialize are not supported", 52 | )), 53 | } 54 | } 55 | 56 | fn derive_struct( 57 | node: &DeriveInput, 58 | _strut: &DataStruct, 59 | named_fields: &FieldsNamed, 60 | ) -> Result { 61 | let ty = &node.ident; 62 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 63 | 64 | enum FieldKind { 65 | Ordinary(u32), 66 | Optional(u32), 67 | Flatten, 68 | } 69 | 70 | let fields = { 71 | let mut fields = vec![]; 72 | let mut tags = vec![]; 73 | for field in &named_fields.named { 74 | let ident = field.ident.clone().unwrap(); 75 | let ty = field.ty.clone(); 76 | let attrs = attr::get(&field.attrs)?; 77 | attrs.disallow_untagged()?; 78 | let kind = if attrs.flatten.is_some() { 79 | attrs.disallow_tag()?; 80 | attrs.disallow_optional()?; 81 | FieldKind::Flatten 82 | } else { 83 | attrs.require_tag(field)?; 84 | attr::check_tag_uniqueness(attrs.tag.as_ref().unwrap(), &mut tags)?; 85 | let tag = attrs.tag.unwrap().tag; 86 | // TODO: require `#[required]` or `#[optional]` for fields of the Option type 87 | if attrs.optional.is_some() { 88 | FieldKind::Optional(tag) 89 | } else { 90 | FieldKind::Ordinary(tag) 91 | } 92 | }; 93 | fields.push((ident, ty, kind)); 94 | } 95 | fields 96 | }; 97 | 98 | let fn_body = { 99 | let mut init = vec![]; 100 | for (ident, ty, kind) in &fields { 101 | let code = match kind { 102 | FieldKind::Ordinary(_) => { 103 | quote! { 104 | let mut #ident: ::std::option::Option<#ty> = None; 105 | } 106 | } 107 | FieldKind::Optional(_) => { 108 | quote! { 109 | let mut #ident: #ty = None; 110 | } 111 | } 112 | FieldKind::Flatten => { 113 | quote! { 114 | let #ident: #ty = __deserializer.clone().deserialize()?; 115 | } 116 | } 117 | }; 118 | init.push(code); 119 | } 120 | 121 | let mut filters = vec![]; 122 | for (ident, _, kind) in &fields { 123 | match kind { 124 | FieldKind::Ordinary(tag) | FieldKind::Optional(tag) => { 125 | filters.push(quote! { 126 | #tag => { 127 | match __deserializer.deserialize() { 128 | Ok(__value) => { 129 | #ident = Some(__value); 130 | } 131 | Err(::msgpack_schema::DeserializeError::Validation(_)) => { 132 | #ident = None; 133 | } 134 | Err(e @ ::msgpack_schema::DeserializeError::InvalidInput(_)) => { 135 | return Err(e); 136 | } 137 | } 138 | } 139 | }); 140 | } 141 | FieldKind::Flatten => {} 142 | } 143 | } 144 | 145 | let mut ctors = vec![]; 146 | for (ident, _, kind) in &fields { 147 | let code = match kind { 148 | FieldKind::Ordinary(_) => { 149 | quote! { 150 | #ident: #ident.ok_or(::msgpack_schema::ValidationError)?, 151 | } 152 | } 153 | FieldKind::Optional(_) | FieldKind::Flatten => { 154 | quote! { 155 | #ident, 156 | } 157 | } 158 | }; 159 | ctors.push(code); 160 | } 161 | 162 | quote! { 163 | #( #init )* 164 | 165 | let __len = match __deserializer.deserialize_token()? { 166 | ::msgpack_schema::Token::Map(len) => len, 167 | _ => return Err(::msgpack_schema::ValidationError.into()), 168 | }; 169 | for _ in 0..__len { 170 | let __tag: u32 = __deserializer.deserialize()?; 171 | match __tag { 172 | #( #filters )* 173 | _ => { 174 | __deserializer.deserialize_any()?; 175 | } 176 | } 177 | } 178 | Ok(Self { 179 | #( #ctors )* 180 | }) 181 | } 182 | }; 183 | 184 | let gen = quote! { 185 | #[allow(unused_qualifications)] 186 | impl #impl_generics ::msgpack_schema::Deserialize for #ty #ty_generics #where_clause { 187 | fn deserialize(__deserializer: &mut ::msgpack_schema::Deserializer) -> ::std::result::Result { 188 | #fn_body 189 | } 190 | } 191 | }; 192 | 193 | Ok(gen) 194 | } 195 | 196 | fn derive_newtype_struct( 197 | node: &DeriveInput, 198 | _strut: &DataStruct, 199 | field: &syn::Field, 200 | ) -> Result { 201 | let ty = &node.ident; 202 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 203 | 204 | let attrs = attr::get(&field.attrs)?; 205 | attrs.disallow_tag()?; 206 | attrs.disallow_optional()?; 207 | attrs.disallow_untagged()?; 208 | attrs.disallow_flatten()?; 209 | 210 | let fn_body = quote! { 211 | __deserializer.deserialize().map(Self) 212 | }; 213 | 214 | let gen = quote! { 215 | #[allow(unused_qualifications)] 216 | impl #impl_generics ::msgpack_schema::Deserialize for #ty #ty_generics #where_clause { 217 | fn deserialize(__deserializer: &mut ::msgpack_schema::Deserializer) -> ::std::result::Result { 218 | #fn_body 219 | } 220 | } 221 | }; 222 | 223 | Ok(gen) 224 | } 225 | 226 | fn derive_tuple_struct( 227 | node: &DeriveInput, 228 | _strut: &DataStruct, 229 | fields: &FieldsUnnamed, 230 | ) -> Result { 231 | let ty = &node.ident; 232 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 233 | 234 | for field in &fields.unnamed { 235 | let attrs = attr::get(&field.attrs)?; 236 | attrs.disallow_tag()?; 237 | attrs.disallow_optional()?; 238 | attrs.disallow_untagged()?; 239 | attrs.disallow_flatten()?; 240 | } 241 | 242 | let count = fields.unnamed.len() as u32; 243 | 244 | let members = (0..count).map(|_| { 245 | quote! { 246 | __deserializer.deserialize()? 247 | } 248 | }); 249 | 250 | let fn_body = quote! { 251 | match __deserializer.deserialize_token()? { 252 | ::msgpack_schema::Token::Array(len) => { 253 | if len != #count { 254 | return Err(::msgpack_schema::ValidationError.into()) 255 | } 256 | }, 257 | _ => return Err(::msgpack_schema::ValidationError.into()), 258 | }; 259 | 260 | Ok(Self( 261 | #( #members ),* 262 | )) 263 | }; 264 | 265 | let gen = quote! { 266 | #[allow(unused_qualifications)] 267 | impl #impl_generics ::msgpack_schema::Deserialize for #ty #ty_generics #where_clause { 268 | fn deserialize(__deserializer: &mut ::msgpack_schema::Deserializer) -> ::std::result::Result { 269 | #fn_body 270 | } 271 | } 272 | }; 273 | 274 | Ok(gen) 275 | } 276 | 277 | fn derive_enum(node: &DeriveInput, enu: &DataEnum) -> Result { 278 | let ty = &node.ident; 279 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 280 | 281 | let fn_body = { 282 | let mut clauses = vec![]; 283 | let mut tags = vec![]; 284 | for variant in &enu.variants { 285 | let ident = variant.ident.clone(); 286 | let attrs = attr::get(&variant.attrs)?; 287 | attrs.disallow_optional()?; 288 | attrs.disallow_untagged()?; 289 | attrs.disallow_flatten()?; 290 | attrs.require_tag(variant)?; 291 | attr::check_tag_uniqueness(attrs.tag.as_ref().unwrap(), &mut tags)?; 292 | let tag = attrs.tag.unwrap().tag; 293 | match &variant.fields { 294 | Fields::Named(_) => { 295 | return Err(Error::new_spanned( 296 | node, 297 | "variants with fields are not supported", 298 | )); 299 | } 300 | Fields::Unnamed(fields) => { 301 | let len = fields.unnamed.len() as u32; 302 | match len { 303 | 0 => { 304 | clauses.push(quote! { 305 | #tag => { 306 | if __is_array { 307 | return Err(::msgpack_schema::ValidationError.into()); 308 | } 309 | Ok(Self::#ident()) 310 | } 311 | }); 312 | } 313 | 1 => { 314 | let attrs = attr::get(&fields.unnamed[0].attrs)?; 315 | attrs.disallow_optional()?; 316 | attrs.disallow_tag()?; 317 | attrs.disallow_untagged()?; 318 | attrs.disallow_flatten()?; 319 | clauses.push(quote! { 320 | #tag => { 321 | if !__is_array { 322 | return Err(::msgpack_schema::ValidationError.into()); 323 | } 324 | Ok(Self::#ident(__deserializer.deserialize()?)) 325 | } 326 | }); 327 | } 328 | _ => { 329 | return Err(Error::new_spanned( 330 | node, 331 | "tuple variants with more than one elements are not supported", 332 | )); 333 | } 334 | } 335 | } 336 | Fields::Unit => { 337 | clauses.push(quote! { 338 | #tag => { 339 | Ok(Self::#ident) 340 | } 341 | }); 342 | } 343 | } 344 | } 345 | 346 | quote! { 347 | let (__tag, __is_array): (u32, bool) = match __deserializer.deserialize_token()? { 348 | ::msgpack_schema::Token::Int(v) => { 349 | (>::try_from(v).map_err(|_| ::msgpack_schema::ValidationError)?, false) 350 | } 351 | ::msgpack_schema::Token::Array(len) => { 352 | if len != 2 { 353 | return Err(::msgpack_schema::ValidationError.into()); 354 | } 355 | (__deserializer.deserialize::()?, true) 356 | } 357 | _ => { 358 | return Err(::msgpack_schema::ValidationError.into()); 359 | } 360 | }; 361 | match __tag { 362 | #( #clauses )* 363 | _ => Err(::msgpack_schema::ValidationError.into()), 364 | } 365 | } 366 | }; 367 | 368 | let gen = quote! { 369 | #[allow(unused_qualifications)] 370 | impl #impl_generics ::msgpack_schema::Deserialize for #ty #ty_generics #where_clause { 371 | fn deserialize(__deserializer: &mut ::msgpack_schema::Deserializer) -> ::std::result::Result { 372 | #fn_body 373 | } 374 | } 375 | }; 376 | 377 | Ok(gen) 378 | } 379 | 380 | fn derive_untagged_enum(node: &DeriveInput, enu: &DataEnum) -> Result { 381 | let ty = &node.ident; 382 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 383 | 384 | let fn_body = { 385 | let mut members = vec![]; 386 | for variant in &enu.variants { 387 | let attrs = attr::get(&variant.attrs)?; 388 | attrs.disallow_optional()?; 389 | attrs.disallow_tag()?; 390 | attrs.disallow_untagged()?; 391 | attrs.disallow_flatten()?; 392 | match &variant.fields { 393 | Fields::Named(_) => { 394 | return Err(Error::new_spanned( 395 | node, 396 | "struct variants cannot be untagged", 397 | )); 398 | } 399 | Fields::Unnamed(fields) => match fields.unnamed.len() { 400 | 0 => { 401 | return Err(Error::new_spanned( 402 | node, 403 | "empty tuple variants cannot be untagged", 404 | )); 405 | } 406 | 1 => { 407 | let attrs = attr::get(&fields.unnamed[0].attrs)?; 408 | attrs.disallow_optional()?; 409 | attrs.disallow_tag()?; 410 | attrs.disallow_untagged()?; 411 | attrs.disallow_flatten()?; 412 | members.push((variant, &fields.unnamed[0])); 413 | } 414 | _ => { 415 | return Err(Error::new_spanned( 416 | node, 417 | "tuple variants cannot be untagged", 418 | )); 419 | } 420 | }, 421 | Fields::Unit => { 422 | return Err(Error::new_spanned( 423 | node, 424 | "unit variants cannot be supported", 425 | )); 426 | } 427 | } 428 | } 429 | 430 | let mut clauses = vec![]; 431 | for (variant, field) in &members { 432 | let ident = variant.ident.clone(); 433 | let ty = field.ty.clone(); 434 | clauses.push(quote! { 435 | if let Some(x) = __deserializer.try_deserialize::<#ty>()? { 436 | return Ok(Self::#ident(x)); 437 | } 438 | }) 439 | } 440 | 441 | quote! { 442 | #( #clauses )* 443 | Err(::msgpack_schema::ValidationError.into()) 444 | } 445 | }; 446 | 447 | let gen = quote! { 448 | #[allow(unused_qualifications)] 449 | impl #impl_generics ::msgpack_schema::Deserialize for #ty #ty_generics #where_clause { 450 | fn deserialize(__deserializer: &mut ::msgpack_schema::Deserializer) -> ::std::result::Result { 451 | #fn_body 452 | } 453 | } 454 | }; 455 | 456 | Ok(gen) 457 | } 458 | 459 | fn derive_untagged_struct( 460 | node: &DeriveInput, 461 | _strut: &DataStruct, 462 | named_fields: &FieldsNamed, 463 | ) -> Result { 464 | let ty = &node.ident; 465 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 466 | 467 | let fn_body = { 468 | let mut members = vec![]; 469 | for field in &named_fields.named { 470 | let attrs = attr::get(&field.attrs)?; 471 | attrs.disallow_tag()?; 472 | attrs.disallow_optional()?; 473 | attrs.disallow_untagged()?; 474 | attrs.disallow_flatten()?; 475 | let ident = field.ident.clone().unwrap(); 476 | let ty = field.ty.clone(); 477 | members.push((ident, ty)) 478 | } 479 | 480 | let len = members.len() as u32; 481 | 482 | let mut init = vec![]; 483 | for (ident, ty) in &members { 484 | let push = quote! { 485 | let mut #ident: #ty = __deserializer.deserialize()?; 486 | }; 487 | init.push(push); 488 | } 489 | 490 | let mut ctors = vec![]; 491 | for (ident, _ty) in &members { 492 | let push = quote! { 493 | #ident, 494 | }; 495 | ctors.push(push); 496 | } 497 | 498 | quote! { 499 | let __len = match __deserializer.deserialize_token()? { 500 | Token::Array(len) => len, 501 | _ => return Err(::msgpack_schema::ValidationError.into()), 502 | }; 503 | 504 | if __len != #len { 505 | return Err(::msgpack_schema::ValidationError.into()); 506 | } 507 | #( #init )* 508 | Ok(Self { 509 | #( #ctors )* 510 | }) 511 | } 512 | }; 513 | 514 | let gen = quote! { 515 | #[allow(unused_qualifications)] 516 | impl #impl_generics ::msgpack_schema::Deserialize for #ty #ty_generics #where_clause { 517 | fn deserialize(__deserializer: &mut ::msgpack_schema::Deserializer) -> ::std::result::Result { 518 | #fn_body 519 | } 520 | } 521 | }; 522 | 523 | Ok(gen) 524 | } 525 | -------------------------------------------------------------------------------- /msgpack-schema-impl/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod attr; 2 | mod deserialize; 3 | mod serialize; 4 | 5 | use proc_macro::TokenStream; 6 | use syn::{parse_macro_input, DeriveInput}; 7 | 8 | /// The `schema` attribute is experimental. 9 | #[proc_macro_derive(Serialize, attributes(schema, tag, optional, untagged, flatten))] 10 | pub fn derive_serialize(input: TokenStream) -> TokenStream { 11 | let input = parse_macro_input!(input as DeriveInput); 12 | serialize::derive(&input) 13 | .unwrap_or_else(|err| err.to_compile_error()) 14 | .into() 15 | } 16 | 17 | /// The `schema` attribute is experimental. 18 | #[proc_macro_derive(Deserialize, attributes(schema, tag, optional, untagged, flatten))] 19 | pub fn derive_deserialize(input: TokenStream) -> TokenStream { 20 | let input = parse_macro_input!(input as DeriveInput); 21 | deserialize::derive(&input) 22 | .unwrap_or_else(|err| err.to_compile_error()) 23 | .into() 24 | } 25 | -------------------------------------------------------------------------------- /msgpack-schema-impl/src/serialize.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use crate::attr; 4 | use proc_macro2::TokenStream; 5 | use quote::quote; 6 | use syn::{ 7 | Data, DataEnum, DataStruct, DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, 8 | Result, 9 | }; 10 | 11 | pub fn derive(node: &DeriveInput) -> Result { 12 | let attrs = attr::get(&node.attrs)?; 13 | attrs.disallow_optional()?; 14 | attrs.disallow_tag()?; 15 | attrs.disallow_flatten()?; 16 | match &node.data { 17 | Data::Struct(strut) => match &strut.fields { 18 | Fields::Named(fields) => { 19 | if attrs.untagged.is_some() { 20 | derive_untagged_struct(node, strut, fields) 21 | } else { 22 | derive_struct(node, strut, fields) 23 | } 24 | } 25 | Fields::Unnamed(fields) => { 26 | attrs.disallow_untagged()?; 27 | let len = fields.unnamed.len(); 28 | match len { 29 | 0 => Err(Error::new_spanned( 30 | node, 31 | "empty tuple structs as serialize are not supported", 32 | )), 33 | 1 => derive_newtype_struct(node, strut, &fields.unnamed[0]), 34 | _ => derive_tuple_struct(node, strut, fields), 35 | } 36 | } 37 | Fields::Unit => { 38 | attrs.disallow_untagged()?; 39 | Err(Error::new_spanned( 40 | node, 41 | "unit structs as serialize are not supported", 42 | )) 43 | } 44 | }, 45 | Data::Enum(enu) => { 46 | if attrs.untagged.is_some() { 47 | derive_untagged_enum(node, enu) 48 | } else { 49 | derive_enum(node, enu) 50 | } 51 | } 52 | Data::Union(_) => Err(Error::new_spanned( 53 | node, 54 | "union as serialize are not supported", 55 | )), 56 | } 57 | } 58 | 59 | fn derive_struct( 60 | node: &DeriveInput, 61 | _strut: &DataStruct, 62 | named_fields: &FieldsNamed, 63 | ) -> Result { 64 | let ty = &node.ident; 65 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 66 | 67 | enum FieldKind { 68 | Ordinary(u32), 69 | Optional(u32), 70 | Flatten, 71 | } 72 | 73 | let fields = { 74 | let mut fields = vec![]; 75 | let mut tags = vec![]; 76 | for field in &named_fields.named { 77 | let ident = field.ident.clone().unwrap(); 78 | let ty = field.ty.clone(); 79 | let attrs = attr::get(&field.attrs)?; 80 | attrs.disallow_untagged()?; 81 | let kind = if attrs.flatten.is_some() { 82 | attrs.disallow_tag()?; 83 | attrs.disallow_optional()?; 84 | FieldKind::Flatten 85 | } else { 86 | attrs.require_tag(field)?; 87 | attr::check_tag_uniqueness(attrs.tag.as_ref().unwrap(), &mut tags)?; 88 | let tag = attrs.tag.unwrap().tag; 89 | // TODO: require `#[required]` or `#[optional]` for fields of the Option type 90 | if attrs.optional.is_some() { 91 | FieldKind::Optional(tag) 92 | } else { 93 | FieldKind::Ordinary(tag) 94 | } 95 | }; 96 | fields.push((ident, ty, kind)); 97 | } 98 | fields 99 | }; 100 | 101 | let count_fields_body = { 102 | let max_len = named_fields.named.len() as u32; 103 | 104 | let mut decs = vec![]; 105 | for (ident, ty, kind) in &fields { 106 | match kind { 107 | FieldKind::Flatten => { 108 | decs.push(quote! { 109 | max_len -= 1; 110 | max_len += <#ty as ::msgpack_schema::StructSerialize>::count_fields(&self.#ident); 111 | }); 112 | } 113 | FieldKind::Optional(_) => { 114 | decs.push(quote! { 115 | if self.#ident.is_none() { 116 | max_len -= 1; 117 | } 118 | }); 119 | } 120 | FieldKind::Ordinary(_) => {} 121 | } 122 | } 123 | 124 | quote! { 125 | let mut max_len: u32 = #max_len; 126 | #( #decs )* 127 | max_len 128 | } 129 | }; 130 | 131 | let serialize_fields_body = { 132 | let mut pushes = vec![]; 133 | for (ident, ty, kind) in &fields { 134 | let code = match kind { 135 | FieldKind::Ordinary(tag) => { 136 | quote! { 137 | serializer.serialize(#tag); 138 | serializer.serialize(&self.#ident); 139 | } 140 | } 141 | FieldKind::Optional(tag) => { 142 | quote! { 143 | if let Some(value) = &self.#ident { 144 | serializer.serialize(#tag); 145 | serializer.serialize(value); 146 | } 147 | } 148 | } 149 | FieldKind::Flatten => { 150 | quote! { 151 | <#ty as ::msgpack_schema::StructSerialize>::serialize_fields(&self.#ident, serializer); 152 | } 153 | } 154 | }; 155 | pushes.push(code); 156 | } 157 | 158 | quote! { 159 | #( #pushes )* 160 | } 161 | }; 162 | 163 | let gen = quote! { 164 | #[allow(unused_qualifications)] 165 | impl #impl_generics ::msgpack_schema::Serialize for #ty #ty_generics #where_clause { 166 | fn serialize(&self, serializer: &mut ::msgpack_schema::Serializer) { 167 | let count = ::count_fields(self); 168 | serializer.serialize_map(count); 169 | ::serialize_fields(self, serializer); 170 | } 171 | } 172 | 173 | #[allow(unused_qualifications)] 174 | impl #impl_generics ::msgpack_schema::StructSerialize for #ty #ty_generics #where_clause { 175 | fn count_fields(&self) -> u32 { 176 | #count_fields_body 177 | } 178 | 179 | fn serialize_fields(&self, serializer: &mut ::msgpack_schema::Serializer) { 180 | #serialize_fields_body 181 | } 182 | } 183 | }; 184 | 185 | Ok(gen) 186 | } 187 | 188 | fn derive_newtype_struct( 189 | node: &DeriveInput, 190 | _strut: &DataStruct, 191 | field: &Field, 192 | ) -> Result { 193 | let ty = &node.ident; 194 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 195 | 196 | let attrs = attr::get(&field.attrs)?; 197 | attrs.disallow_tag()?; 198 | attrs.disallow_optional()?; 199 | attrs.disallow_untagged()?; 200 | attrs.disallow_flatten()?; 201 | 202 | let fn_body = quote! { 203 | serializer.serialize(&self.0); 204 | }; 205 | 206 | let gen = quote! { 207 | #[allow(unused_qualifications)] 208 | impl #impl_generics ::msgpack_schema::Serialize for #ty #ty_generics #where_clause { 209 | fn serialize(&self, serializer: &mut ::msgpack_schema::Serializer) { 210 | #fn_body 211 | } 212 | } 213 | }; 214 | 215 | Ok(gen) 216 | } 217 | 218 | fn derive_tuple_struct( 219 | node: &DeriveInput, 220 | _strut: &DataStruct, 221 | fields: &FieldsUnnamed, 222 | ) -> Result { 223 | let ty = &node.ident; 224 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 225 | 226 | for field in &fields.unnamed { 227 | let attrs = attr::get(&field.attrs)?; 228 | attrs.disallow_tag()?; 229 | attrs.disallow_optional()?; 230 | attrs.disallow_untagged()?; 231 | attrs.disallow_flatten()?; 232 | } 233 | 234 | let count = fields.unnamed.len() as u32; 235 | let field_specs = (0..count).map(|n| TokenStream::from_str(&format!("{}", n)).unwrap()); 236 | 237 | let fn_body = quote! { 238 | serializer.serialize_array(#count); 239 | #( serializer.serialize(&self.#field_specs); )* 240 | }; 241 | 242 | let gen = quote! { 243 | #[allow(unused_qualifications)] 244 | impl #impl_generics ::msgpack_schema::Serialize for #ty #ty_generics #where_clause { 245 | fn serialize(&self, serializer: &mut ::msgpack_schema::Serializer) { 246 | #fn_body 247 | } 248 | } 249 | }; 250 | 251 | Ok(gen) 252 | } 253 | 254 | fn derive_enum(node: &DeriveInput, enu: &DataEnum) -> Result { 255 | let ty = &node.ident; 256 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 257 | 258 | let fn_body = { 259 | let mut clauses = vec![]; 260 | let mut tags = vec![]; 261 | for variant in &enu.variants { 262 | let ident = variant.ident.clone(); 263 | let attrs = attr::get(&variant.attrs)?; 264 | attrs.disallow_optional()?; 265 | attrs.disallow_untagged()?; 266 | attrs.disallow_flatten()?; 267 | attrs.require_tag(variant)?; 268 | attr::check_tag_uniqueness(attrs.tag.as_ref().unwrap(), &mut tags)?; 269 | let tag = attrs.tag.unwrap().tag; 270 | match &variant.fields { 271 | Fields::Named(_) => { 272 | return Err(Error::new_spanned( 273 | node, 274 | "variants with fields are not supported", 275 | )); 276 | } 277 | Fields::Unnamed(fields) => { 278 | let len = fields.unnamed.len() as u32; 279 | match len { 280 | 0 => { 281 | clauses.push(quote! { 282 | Self::#ident() => { 283 | serializer.serialize(#tag); 284 | } 285 | }); 286 | } 287 | 1 => { 288 | let attrs = attr::get(&fields.unnamed[0].attrs)?; 289 | attrs.disallow_optional()?; 290 | attrs.disallow_tag()?; 291 | attrs.disallow_untagged()?; 292 | attrs.disallow_flatten()?; 293 | clauses.push(quote! { 294 | Self::#ident(value) => { 295 | serializer.serialize_array(2); 296 | serializer.serialize(#tag); 297 | serializer.serialize(value); 298 | } 299 | }); 300 | } 301 | _ => { 302 | return Err(Error::new_spanned( 303 | node, 304 | "tuple variants with more than one elements are not supported", 305 | )); 306 | } 307 | } 308 | } 309 | Fields::Unit => { 310 | clauses.push(quote! { 311 | Self::#ident => { 312 | serializer.serialize(#tag); 313 | } 314 | }); 315 | } 316 | } 317 | } 318 | 319 | quote! { 320 | match self { 321 | #( #clauses )* 322 | } 323 | } 324 | }; 325 | 326 | let gen = quote! { 327 | #[allow(unused_qualifications)] 328 | impl #impl_generics ::msgpack_schema::Serialize for #ty #ty_generics #where_clause { 329 | fn serialize(&self, serializer: &mut ::msgpack_schema::Serializer) { 330 | #fn_body 331 | } 332 | } 333 | }; 334 | 335 | Ok(gen) 336 | } 337 | 338 | fn derive_untagged_enum(node: &DeriveInput, enu: &DataEnum) -> Result { 339 | let ty = &node.ident; 340 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 341 | 342 | let fn_body = { 343 | let mut members = vec![]; 344 | for variant in &enu.variants { 345 | let attrs = attr::get(&variant.attrs)?; 346 | attrs.disallow_optional()?; 347 | attrs.disallow_tag()?; 348 | attrs.disallow_untagged()?; 349 | attrs.disallow_flatten()?; 350 | match &variant.fields { 351 | Fields::Named(_) => { 352 | return Err(Error::new_spanned( 353 | node, 354 | "struct variants cannot be untagged", 355 | )); 356 | } 357 | Fields::Unnamed(fields) => match fields.unnamed.len() { 358 | 0 => { 359 | return Err(Error::new_spanned( 360 | node, 361 | "empty tuple variants cannot be untagged", 362 | )); 363 | } 364 | 1 => { 365 | let attrs = attr::get(&fields.unnamed[0].attrs)?; 366 | attrs.disallow_optional()?; 367 | attrs.disallow_tag()?; 368 | attrs.disallow_untagged()?; 369 | attrs.disallow_flatten()?; 370 | members.push((variant, &fields.unnamed[0])); 371 | } 372 | _ => { 373 | return Err(Error::new_spanned( 374 | node, 375 | "tuple variants cannot be untagged", 376 | )); 377 | } 378 | }, 379 | Fields::Unit => { 380 | return Err(Error::new_spanned( 381 | node, 382 | "unit variants cannot be supported", 383 | )); 384 | } 385 | } 386 | } 387 | 388 | let mut clauses = vec![]; 389 | for (variant, _field) in &members { 390 | let ident = variant.ident.clone(); 391 | clauses.push(quote! { 392 | Self::#ident(value) => { 393 | serializer.serialize(value) 394 | } 395 | }); 396 | } 397 | 398 | quote! { 399 | match self { 400 | #( #clauses )* 401 | } 402 | } 403 | }; 404 | 405 | let gen = quote! { 406 | #[allow(unused_qualifications)] 407 | impl #impl_generics ::msgpack_schema::Serialize for #ty #ty_generics #where_clause { 408 | fn serialize(&self, serializer: &mut ::msgpack_schema::Serializer) { 409 | #fn_body 410 | } 411 | } 412 | }; 413 | 414 | Ok(gen) 415 | } 416 | 417 | fn derive_untagged_struct( 418 | node: &DeriveInput, 419 | _strut: &DataStruct, 420 | named_fields: &FieldsNamed, 421 | ) -> Result { 422 | let ty = &node.ident; 423 | let (impl_generics, ty_generics, where_clause) = node.generics.split_for_impl(); 424 | 425 | let fn_body = { 426 | let mut members = vec![]; 427 | for field in &named_fields.named { 428 | let ident = field.ident.clone().unwrap(); 429 | let attrs = attr::get(&field.attrs)?; 430 | attrs.disallow_tag()?; 431 | attrs.disallow_optional()?; 432 | attrs.disallow_untagged()?; 433 | attrs.disallow_flatten()?; 434 | members.push(ident); 435 | } 436 | 437 | let len = members.len() as u32; 438 | 439 | let mut pushes = vec![]; 440 | for ident in &members { 441 | let push = quote! { 442 | serializer.serialize(&self.#ident); 443 | }; 444 | pushes.push(push); 445 | } 446 | 447 | quote! { 448 | serializer.serialize_array(#len); 449 | #( #pushes )* 450 | } 451 | }; 452 | 453 | let gen = quote! { 454 | #[allow(unused_qualifications)] 455 | impl #impl_generics ::msgpack_schema::Serialize for #ty #ty_generics #where_clause { 456 | fn serialize(&self, serializer: &mut ::msgpack_schema::Serializer) { 457 | #fn_body 458 | } 459 | } 460 | }; 461 | 462 | Ok(gen) 463 | } 464 | -------------------------------------------------------------------------------- /msgpack-value/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "msgpack-value" 3 | version = "1.1.0" 4 | authors = ["Yuichi Nishiwaki "] 5 | edition = "2021" 6 | description = "Types and macros for the MessagePack data model" 7 | license = "MIT" 8 | repository = "https://github.com/Idein/msgpack-schema" 9 | 10 | [features] 11 | default = ["proptest"] 12 | proptest = ["dep:proptest", "dep:proptest-derive"] 13 | 14 | [dependencies] 15 | thiserror = "^1.0.25" 16 | proptest = { version = "1", optional = true } 17 | proptest-derive = { version = "0.3", optional = true } 18 | -------------------------------------------------------------------------------- /msgpack-value/LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /msgpack-value/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The MessagePack Data Model 2 | //! 3 | //! See also the [specification](https://github.com/msgpack/msgpack/blob/master/spec.md). 4 | #[cfg(feature = "proptest")] 5 | use proptest::prelude::*; 6 | #[cfg(feature = "proptest")] 7 | use proptest_derive::Arbitrary; 8 | use std::convert::{TryFrom, TryInto}; 9 | use thiserror::Error; 10 | 11 | /// Integer ranging from `-(2^63)` to `(2^64)-1`. 12 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 13 | pub struct Int { 14 | sign: bool, 15 | /// Whenever `sign` is true, `value & (1 << 63)` is nonzero. 16 | value: u64, 17 | } 18 | 19 | impl From for Int { 20 | fn from(v: u64) -> Self { 21 | Self { 22 | sign: false, 23 | value: v, 24 | } 25 | } 26 | } 27 | 28 | impl From for Int { 29 | fn from(v: i64) -> Self { 30 | if v >= 0 { 31 | (v as u64).into() 32 | } else { 33 | Self { 34 | sign: true, 35 | value: v as u64, 36 | } 37 | } 38 | } 39 | } 40 | 41 | impl From for Int { 42 | fn from(v: u8) -> Self { 43 | (v as u64).into() 44 | } 45 | } 46 | 47 | impl From for Int { 48 | fn from(v: u16) -> Self { 49 | (v as u64).into() 50 | } 51 | } 52 | 53 | impl From for Int { 54 | fn from(v: u32) -> Self { 55 | (v as u64).into() 56 | } 57 | } 58 | 59 | #[cfg(any( 60 | target_pointer_width = "16", 61 | target_pointer_width = "32", 62 | target_pointer_width = "64" 63 | ))] 64 | impl From for Int { 65 | fn from(v: usize) -> Self { 66 | (v as u64).into() 67 | } 68 | } 69 | 70 | impl From for Int { 71 | fn from(v: i8) -> Self { 72 | (v as i64).into() 73 | } 74 | } 75 | 76 | impl From for Int { 77 | fn from(v: i16) -> Self { 78 | (v as i64).into() 79 | } 80 | } 81 | 82 | impl From for Int { 83 | fn from(v: i32) -> Self { 84 | (v as i64).into() 85 | } 86 | } 87 | 88 | #[cfg(any( 89 | target_pointer_width = "16", 90 | target_pointer_width = "32", 91 | target_pointer_width = "64" 92 | ))] 93 | impl From for Int { 94 | fn from(v: isize) -> Self { 95 | (v as i64).into() 96 | } 97 | } 98 | 99 | impl std::fmt::Display for Int { 100 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 101 | if self.sign { 102 | (self.value as i64).fmt(f) 103 | } else { 104 | self.value.fmt(f) 105 | } 106 | } 107 | } 108 | 109 | /// Error type returned by `TryFrom` implementations. 110 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Error)] 111 | #[error("out of range integral type conversion attempted")] 112 | pub struct TryFromIntError(()); 113 | 114 | impl TryFrom for u64 { 115 | type Error = TryFromIntError; 116 | 117 | fn try_from(value: Int) -> Result { 118 | if value.sign { 119 | Err(TryFromIntError(())) 120 | } else { 121 | Ok(value.value) 122 | } 123 | } 124 | } 125 | 126 | impl TryFrom for i64 { 127 | type Error = TryFromIntError; 128 | 129 | fn try_from(value: Int) -> Result { 130 | if value.sign { 131 | Ok(value.value as i64) 132 | } else { 133 | let v = value.value as i64; 134 | if v >= 0 { 135 | Ok(v) 136 | } else { 137 | Err(TryFromIntError(())) 138 | } 139 | } 140 | } 141 | } 142 | 143 | impl TryFrom for u8 { 144 | type Error = TryFromIntError; 145 | 146 | fn try_from(value: Int) -> Result { 147 | u64::try_from(value)? 148 | .try_into() 149 | .map_err(|_| TryFromIntError(())) 150 | } 151 | } 152 | 153 | impl TryFrom for u16 { 154 | type Error = TryFromIntError; 155 | 156 | fn try_from(value: Int) -> Result { 157 | u64::try_from(value)? 158 | .try_into() 159 | .map_err(|_| TryFromIntError(())) 160 | } 161 | } 162 | 163 | impl TryFrom for u32 { 164 | type Error = TryFromIntError; 165 | 166 | fn try_from(value: Int) -> Result { 167 | u64::try_from(value)? 168 | .try_into() 169 | .map_err(|_| TryFromIntError(())) 170 | } 171 | } 172 | 173 | impl TryFrom for usize { 174 | type Error = TryFromIntError; 175 | 176 | fn try_from(value: Int) -> Result { 177 | u64::try_from(value)? 178 | .try_into() 179 | .map_err(|_| TryFromIntError(())) 180 | } 181 | } 182 | 183 | impl TryFrom for i8 { 184 | type Error = TryFromIntError; 185 | 186 | fn try_from(value: Int) -> Result { 187 | i64::try_from(value)? 188 | .try_into() 189 | .map_err(|_| TryFromIntError(())) 190 | } 191 | } 192 | 193 | impl TryFrom for i16 { 194 | type Error = TryFromIntError; 195 | 196 | fn try_from(value: Int) -> Result { 197 | i64::try_from(value)? 198 | .try_into() 199 | .map_err(|_| TryFromIntError(())) 200 | } 201 | } 202 | 203 | impl TryFrom for i32 { 204 | type Error = TryFromIntError; 205 | 206 | fn try_from(value: Int) -> Result { 207 | i64::try_from(value)? 208 | .try_into() 209 | .map_err(|_| TryFromIntError(())) 210 | } 211 | } 212 | 213 | #[cfg(any( 214 | target_pointer_width = "16", 215 | target_pointer_width = "32", 216 | target_pointer_width = "64" 217 | ))] 218 | impl TryFrom for isize { 219 | type Error = TryFromIntError; 220 | 221 | fn try_from(value: Int) -> Result { 222 | i64::try_from(value)? 223 | .try_into() 224 | .map_err(|_| TryFromIntError(())) 225 | } 226 | } 227 | 228 | #[cfg(feature = "proptest")] 229 | impl Arbitrary for Int { 230 | type Parameters = (); 231 | 232 | type Strategy = BoxedStrategy; 233 | 234 | fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { 235 | (any::(), any::()) 236 | .prop_map(|(high, low)| { 237 | if high < 0 { 238 | Int::from(high) 239 | } else { 240 | Int::from((high as u64) << 1 | (low as u64)) 241 | } 242 | }) 243 | .boxed() 244 | } 245 | } 246 | 247 | /// String objects of MessagePack are essentially byte arrays type that may contain any bytes. 248 | /// 249 | /// # String type vs Binary type 250 | /// 251 | /// MessagePack has a complicated history about its distinction between string type and binary type. 252 | /// 253 | /// While an earlier version of MessagePack had only one type for encoding a binary data, namely the raw type, 254 | /// it was later divided into two distinct types for supporting use cases in dynamically-typed languages. [^1] 255 | /// The string type, one of the newly added types, is essentially what was originally called the raw type. 256 | /// Because of this origin, despite its name, string objects of MessagePack can contain not just valid UTF-8 sequences but also any byte sequences. 257 | /// And encoding non-UTF-8 byte sequences as a string object is a *perfectly valid* and *expected* usage by the spec authors. 258 | /// 259 | /// [^1]: [https://github.com/msgpack/msgpack/issues/121](https://github.com/msgpack/msgpack/issues/121) 260 | /// 261 | /// # So which to use in encoding my binary data? 262 | /// 263 | /// When you decide to implement a custom serializer/deserializer for your own binary type, 264 | /// it is recommended to use _string type_ instead of binary type for its encoding scheme for the following reasons. 265 | /// 266 | /// - It just saves some memory. If your byte array is less than 32 byte length, using string type instead of byte array saves one byte per object. 267 | /// - The disiction only matters when _not_ using a data schema. Because this crate offers a statically-typed data schema, and we know how to decode data into a Rust object at compile time, 268 | /// distinction of these types in the input binary data is almost useless, 269 | /// 270 | /// Although we strongly recommend you to use string types rather than binary types, this crate does _not_ force you to do so. 271 | /// The functions and trait implementations provided by this crate are all taking a neutral stand. 272 | #[cfg_attr(feature = "proptest", derive(Arbitrary))] 273 | #[derive(Debug, Clone, PartialEq, Eq)] 274 | pub struct Str(pub Vec); 275 | 276 | impl From for Str { 277 | fn from(x: String) -> Self { 278 | Str(x.into_bytes()) 279 | } 280 | } 281 | 282 | impl Str { 283 | pub fn into_bytes(self) -> Vec { 284 | self.0 285 | } 286 | 287 | pub fn as_bytes(&self) -> &[u8] { 288 | &self.0 289 | } 290 | } 291 | 292 | /// Byte array type. 293 | /// 294 | /// As noted in the comment in [Str], using this type in this crate is almost nonsense, unless your data schema is shared by some external data providers. 295 | #[cfg_attr(feature = "proptest", derive(Arbitrary))] 296 | #[derive(Debug, Clone, PartialEq, Eq)] 297 | pub struct Bin(pub Vec); 298 | 299 | impl Bin { 300 | pub fn into_bytes(self) -> Vec { 301 | self.0 302 | } 303 | 304 | pub fn as_bytes(&self) -> &[u8] { 305 | &self.0 306 | } 307 | } 308 | 309 | /// User-extended type. 310 | #[cfg_attr(feature = "proptest", derive(Arbitrary))] 311 | #[derive(Debug, Clone, PartialEq, Eq)] 312 | pub struct Ext { 313 | pub r#type: i8, 314 | pub data: Vec, 315 | } 316 | 317 | #[derive(Clone, PartialEq, Debug, Default)] 318 | pub enum Value { 319 | #[default] 320 | Nil, 321 | Bool(bool), 322 | Int(Int), 323 | F32(f32), 324 | F64(f64), 325 | Str(Str), 326 | Bin(Bin), 327 | Array(Vec), 328 | Map(Vec<(Value, Value)>), 329 | Ext(Ext), 330 | } 331 | 332 | impl From for Value { 333 | fn from(v: bool) -> Self { 334 | Self::Bool(v) 335 | } 336 | } 337 | 338 | impl From for Value { 339 | fn from(v: Int) -> Self { 340 | Self::Int(v) 341 | } 342 | } 343 | 344 | impl From for Value { 345 | fn from(v: u8) -> Self { 346 | Self::Int(v.into()) 347 | } 348 | } 349 | 350 | impl From for Value { 351 | fn from(v: u16) -> Self { 352 | Self::Int(v.into()) 353 | } 354 | } 355 | 356 | impl From for Value { 357 | fn from(v: u32) -> Self { 358 | Self::Int(v.into()) 359 | } 360 | } 361 | 362 | impl From for Value { 363 | fn from(v: u64) -> Self { 364 | Self::Int(v.into()) 365 | } 366 | } 367 | 368 | impl From for Value { 369 | fn from(v: usize) -> Self { 370 | Self::Int(v.into()) 371 | } 372 | } 373 | 374 | impl From for Value { 375 | fn from(v: i8) -> Self { 376 | Self::Int(v.into()) 377 | } 378 | } 379 | 380 | impl From for Value { 381 | fn from(v: i16) -> Self { 382 | Self::Int(v.into()) 383 | } 384 | } 385 | 386 | impl From for Value { 387 | fn from(v: i32) -> Self { 388 | Self::Int(v.into()) 389 | } 390 | } 391 | 392 | impl From for Value { 393 | fn from(v: i64) -> Self { 394 | Self::Int(v.into()) 395 | } 396 | } 397 | 398 | impl From for Value { 399 | fn from(v: isize) -> Self { 400 | Self::Int(v.into()) 401 | } 402 | } 403 | 404 | impl From for Value { 405 | fn from(v: f32) -> Self { 406 | Self::F32(v) 407 | } 408 | } 409 | 410 | impl From for Value { 411 | fn from(v: f64) -> Self { 412 | Self::F64(v) 413 | } 414 | } 415 | 416 | impl From for Value { 417 | fn from(v: Str) -> Self { 418 | Self::Str(v) 419 | } 420 | } 421 | 422 | impl From for Value { 423 | fn from(v: String) -> Self { 424 | Self::Str(Str(v.into_bytes())) 425 | } 426 | } 427 | 428 | impl From<&str> for Value { 429 | fn from(v: &str) -> Self { 430 | v.to_owned().into() 431 | } 432 | } 433 | 434 | impl From for Value { 435 | fn from(v: Bin) -> Self { 436 | Self::Bin(v) 437 | } 438 | } 439 | 440 | impl From for Value { 441 | fn from(v: Ext) -> Self { 442 | Self::Ext(v) 443 | } 444 | } 445 | 446 | impl From> for Value { 447 | fn from(v: Vec) -> Self { 448 | Self::Array(v) 449 | } 450 | } 451 | 452 | impl From> for Value { 453 | fn from(v: Vec<(Value, Value)>) -> Self { 454 | Self::Map(v) 455 | } 456 | } 457 | 458 | pub trait Index { 459 | fn index<'a>(&self, v: &'a Value) -> &'a Value; 460 | } 461 | 462 | impl Index for &T { 463 | fn index<'a>(&self, v: &'a Value) -> &'a Value { 464 | (*self).index(v) 465 | } 466 | } 467 | 468 | impl Index for str { 469 | fn index<'a>(&self, v: &'a Value) -> &'a Value { 470 | let map = v 471 | .as_map() 472 | .expect("this type of object is not indexable by str"); 473 | for (key, value) in map.iter().rev() { 474 | if let Some(Str(key)) = key.as_str() { 475 | if key == self.as_bytes() { 476 | return value; 477 | } 478 | } 479 | } 480 | panic!("key not found in object"); 481 | } 482 | } 483 | 484 | impl Index for String { 485 | fn index<'a>(&self, v: &'a Value) -> &'a Value { 486 | self.as_str().index(v) 487 | } 488 | } 489 | 490 | impl Index for usize { 491 | fn index<'a>(&self, v: &'a Value) -> &'a Value { 492 | let array = v 493 | .as_array() 494 | .expect("this type of object is not indexable by usize"); 495 | &array[*self] 496 | } 497 | } 498 | 499 | impl core::ops::Index for Value 500 | where 501 | T: Index, 502 | { 503 | type Output = Value; 504 | /// Accessing inner values of `value` using indexing `value[0]` or `value["foo"]`. 505 | /// 506 | /// # Panics 507 | /// 508 | /// This function panics when `self` does not contain given key. 509 | /// 510 | /// # Duplicate keys 511 | /// 512 | /// If `self` is a map object and contains two or more keys matching against the given index, 513 | /// indexing works as if the preceding keys do not exist in the object. 514 | /// This is the same behaviour as [what EMCA-262 specifies](https://stackoverflow.com/a/23195243). 515 | /// 516 | /// ``` 517 | /// # use msgpack_value::{msgpack, Int}; 518 | /// let v = msgpack!({ "a" : 0, "a" : 1 }); 519 | /// assert_eq!(v["a"], Int::from(1u32).into()); 520 | /// ``` 521 | fn index(&self, index: T) -> &Self::Output { 522 | index.index(self) 523 | } 524 | } 525 | 526 | #[test] 527 | fn test_index() { 528 | let v = msgpack!({ 0: 1, "foo" : "bar", "foo" : "baz" }); 529 | let k = &v["foo"]; 530 | // last value wins 531 | assert_eq!(k.as_str().unwrap().as_bytes(), "baz".as_bytes()); 532 | 533 | let v = msgpack!(["foo", "bar", "baz"]); 534 | let k = &v[1]; 535 | assert_eq!(k.as_str().unwrap().as_bytes(), "bar".as_bytes()); 536 | } 537 | 538 | #[test] 539 | #[should_panic] 540 | fn test_index_panic_array_index_by_str() { 541 | let _ = msgpack!([])["foo"]; 542 | } 543 | 544 | #[test] 545 | #[should_panic] 546 | fn test_index_panic_array_out_of_range() { 547 | let _ = msgpack!([])[0]; 548 | } 549 | 550 | #[test] 551 | #[should_panic] 552 | fn test_index_panic_map_key_not_found() { 553 | let _ = msgpack!({"foo":"bar"})["baz"]; 554 | } 555 | 556 | /// Error type returned by `TryFrom` implementations. 557 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Error)] 558 | #[error("value is not of the expected type")] 559 | pub struct TryFromValueError(()); 560 | 561 | impl TryFrom for bool { 562 | type Error = TryFromValueError; 563 | 564 | fn try_from(value: Value) -> Result { 565 | match value { 566 | Value::Bool(v) => Ok(v), 567 | _ => Err(TryFromValueError(())), 568 | } 569 | } 570 | } 571 | 572 | impl TryFrom for Int { 573 | type Error = TryFromValueError; 574 | 575 | fn try_from(value: Value) -> Result { 576 | match value { 577 | Value::Int(v) => Ok(v), 578 | _ => Err(TryFromValueError(())), 579 | } 580 | } 581 | } 582 | 583 | impl TryFrom for f32 { 584 | type Error = TryFromValueError; 585 | 586 | fn try_from(value: Value) -> Result { 587 | match value { 588 | Value::F32(v) => Ok(v), 589 | _ => Err(TryFromValueError(())), 590 | } 591 | } 592 | } 593 | 594 | impl TryFrom for f64 { 595 | type Error = TryFromValueError; 596 | 597 | fn try_from(value: Value) -> Result { 598 | match value { 599 | Value::F64(v) => Ok(v), 600 | _ => Err(TryFromValueError(())), 601 | } 602 | } 603 | } 604 | 605 | impl TryFrom for Vec { 606 | type Error = TryFromValueError; 607 | 608 | fn try_from(value: Value) -> Result { 609 | match value { 610 | Value::Array(v) => Ok(v), 611 | _ => Err(TryFromValueError(())), 612 | } 613 | } 614 | } 615 | 616 | impl TryFrom for Vec<(Value, Value)> { 617 | type Error = TryFromValueError; 618 | 619 | fn try_from(value: Value) -> Result { 620 | match value { 621 | Value::Map(v) => Ok(v), 622 | _ => Err(TryFromValueError(())), 623 | } 624 | } 625 | } 626 | 627 | #[cfg(feature = "proptest")] 628 | impl Arbitrary for Value { 629 | type Parameters = (); 630 | type Strategy = BoxedStrategy; 631 | 632 | fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { 633 | fn arb_value() -> BoxedStrategy { 634 | let leaf = prop_oneof![ 635 | Just(Value::Nil), 636 | any::().prop_map(Value::Bool), 637 | any::().prop_map(Value::Int), 638 | any::().prop_map(Value::F32), 639 | any::().prop_map(Value::F64), 640 | any::().prop_map(Value::Str), 641 | any::().prop_map(Value::Bin), 642 | any::().prop_map(Value::Ext), 643 | ]; 644 | leaf.prop_recursive(8, 256, 10, |inner| { 645 | prop_oneof![ 646 | prop::collection::vec(inner.clone(), 0..10).prop_map(Value::Array), 647 | prop::collection::vec((inner.clone(), inner), 0..10).prop_map(Value::Map), 648 | ] 649 | }) 650 | .boxed() 651 | } 652 | arb_value() 653 | } 654 | } 655 | 656 | impl Value { 657 | pub fn is_nil(&self) -> bool { 658 | matches!(self, Self::Nil) 659 | } 660 | pub fn is_bool(&self) -> bool { 661 | matches!(self, Self::Bool(_)) 662 | } 663 | pub fn is_int(&self) -> bool { 664 | matches!(self, Self::Int(_)) 665 | } 666 | pub fn is_f32(&self) -> bool { 667 | matches!(self, Self::F32(_)) 668 | } 669 | pub fn is_f64(&self) -> bool { 670 | matches!(self, Self::F64(_)) 671 | } 672 | pub fn is_str(&self) -> bool { 673 | matches!(self, Self::Str(_)) 674 | } 675 | pub fn is_bin(&self) -> bool { 676 | matches!(self, Self::Bin(_)) 677 | } 678 | pub fn is_array(&self) -> bool { 679 | matches!(self, Self::Array(_)) 680 | } 681 | pub fn is_map(&self) -> bool { 682 | matches!(self, Self::Map(_)) 683 | } 684 | pub fn is_ext(&self) -> bool { 685 | matches!(self, Self::Ext(_)) 686 | } 687 | pub fn as_bool(&self) -> Option { 688 | match self { 689 | Self::Bool(v) => Some(*v), 690 | _ => None, 691 | } 692 | } 693 | pub fn as_int(&self) -> Option { 694 | match self { 695 | Self::Int(v) => Some(*v), 696 | _ => None, 697 | } 698 | } 699 | pub fn as_f32(&self) -> Option { 700 | match self { 701 | Self::F32(v) => Some(*v), 702 | _ => None, 703 | } 704 | } 705 | pub fn as_f64(&self) -> Option { 706 | match self { 707 | Self::F64(v) => Some(*v), 708 | _ => None, 709 | } 710 | } 711 | pub fn as_str(&self) -> Option<&Str> { 712 | match self { 713 | Self::Str(v) => Some(v), 714 | _ => None, 715 | } 716 | } 717 | pub fn as_str_mut(&mut self) -> Option<&mut Str> { 718 | match self { 719 | Self::Str(v) => Some(v), 720 | _ => None, 721 | } 722 | } 723 | pub fn as_bin(&self) -> Option<&Bin> { 724 | match self { 725 | Self::Bin(v) => Some(v), 726 | _ => None, 727 | } 728 | } 729 | pub fn as_bin_mut(&mut self) -> Option<&mut Bin> { 730 | match self { 731 | Self::Bin(v) => Some(v), 732 | _ => None, 733 | } 734 | } 735 | pub fn as_array(&self) -> Option<&[Value]> { 736 | match self { 737 | Self::Array(v) => Some(v), 738 | _ => None, 739 | } 740 | } 741 | pub fn as_array_mut(&mut self) -> Option<&mut Vec> { 742 | match self { 743 | Self::Array(v) => Some(v), 744 | _ => None, 745 | } 746 | } 747 | pub fn as_map(&self) -> Option<&[(Value, Value)]> { 748 | match self { 749 | Self::Map(v) => Some(v), 750 | _ => None, 751 | } 752 | } 753 | pub fn as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>> { 754 | match self { 755 | Self::Map(v) => Some(v), 756 | _ => None, 757 | } 758 | } 759 | pub fn as_ext(&self) -> Option<&Ext> { 760 | match self { 761 | Self::Ext(v) => Some(v), 762 | _ => None, 763 | } 764 | } 765 | pub fn as_ext_mut(&mut self) -> Option<&mut Ext> { 766 | match self { 767 | Self::Ext(v) => Some(v), 768 | _ => None, 769 | } 770 | } 771 | } 772 | 773 | #[doc(hidden)] 774 | #[macro_export] 775 | macro_rules! msgpack_array { 776 | ($acc: ident) => { 777 | }; 778 | ($acc: ident,) => { 779 | }; 780 | ($acc: ident nil) => { 781 | $acc.push($crate::msgpack_value!(nil)); 782 | }; 783 | ($acc: ident nil, $( $rest: tt )*) => { 784 | $acc.push($crate::msgpack_value!(nil)); 785 | $crate::msgpack_array!($acc $( $rest )*); 786 | }; 787 | ($acc: ident [ $( $tt: tt )* ]) => { 788 | $acc.push($crate::msgpack_value!([ $( $tt )* ])); 789 | }; 790 | ($acc: ident [ $( $tt: tt )* ], $( $rest: tt )*) => { 791 | $acc.push($crate::msgpack_value!([ $( $tt )* ])); 792 | $crate::msgpack_array!($acc $( $rest )*); 793 | }; 794 | ($acc: ident { $( $tt: tt )* }) => { 795 | $acc.push($crate::msgpack_value!({ $( $tt )* })); 796 | }; 797 | ($acc: ident { $( $tt: tt )* }, $( $rest: tt )*) => { 798 | $acc.push($crate::msgpack_value!({ $( $tt )* })); 799 | $crate::msgpack_array!($acc $( $rest )*); 800 | }; 801 | ($acc: ident $expr: expr) => { 802 | $acc.push($crate::msgpack_value!($expr)); 803 | }; 804 | ($acc: ident $expr: expr, $( $rest: tt )*) => { 805 | $acc.push($crate::msgpack_value!($expr)); 806 | $crate::msgpack_array!($acc $( $rest )*); 807 | }; 808 | } 809 | 810 | #[doc(hidden)] 811 | #[macro_export] 812 | macro_rules! msgpack_map { 813 | (@key $acc: ident []) => { 814 | }; 815 | (@key $acc: ident [],) => { 816 | }; 817 | (@key $acc: ident [ $( $key: tt )* ] : $( $rest: tt )*) => { 818 | let key = $crate::msgpack_value!($( $key )*); 819 | $crate::msgpack_map!(@val $acc key $( $rest )*); 820 | }; 821 | (@key $acc: ident [ $( $key: tt )* ] $tt: tt $( $rest: tt )*) => { 822 | $crate::msgpack_map!(@key $acc [ $( $key )* $tt ] $( $rest )*); 823 | }; 824 | (@val $acc: ident $key: ident nil) => { 825 | $acc.push(($key, $crate::msgpack_value!(nil))); 826 | }; 827 | (@val $acc: ident $key: ident nil, $( $rest: tt )*) => { 828 | $acc.push(($key, $crate::msgpack_value!(nil))); 829 | $crate::msgpack_map!(@key $acc [] $( $rest )*); 830 | }; 831 | (@val $acc: ident $key: ident [ $( $tt: tt )* ]) => { 832 | $acc.push(($key, $crate::msgpack_value!([ $( $tt )* ]))); 833 | }; 834 | (@val $acc: ident $key: ident [ $( $tt: tt )* ], $( $rest: tt )*) => { 835 | $acc.push(($key, $crate::msgpack_value!([ $( $tt )* ]))); 836 | $crate::msgpack_map!(@key $acc [] $( $rest )*); 837 | }; 838 | (@val $acc: ident $key: ident { $( $tt: tt )* }) => { 839 | $acc.push(($key, $crate::msgpack_value!({ $( $tt )* }))); 840 | }; 841 | (@val $acc: ident $key: ident { $( $tt: tt )* }, $( $rest: tt )*) => { 842 | $acc.push(($key, $crate::msgpack_value!({ $( $tt )* }))); 843 | $crate::msgpack_map!(@key $acc [] $( $rest )*); 844 | }; 845 | (@val $acc: ident $key: ident $expr: expr) => { 846 | $acc.push(($key, $crate::msgpack_value!($expr))); 847 | }; 848 | (@val $acc: ident $key: ident $expr: expr, $( $rest: tt )*) => { 849 | $acc.push(($key, $crate::msgpack_value!($expr))); 850 | $crate::msgpack_map!(@key $acc [] $( $rest )*); 851 | }; 852 | } 853 | 854 | #[doc(hidden)] 855 | #[macro_export] 856 | macro_rules! msgpack_value { 857 | (nil) => { 858 | $crate::Value::Nil 859 | }; 860 | ([ $( $tt: tt )* ]) => { 861 | { 862 | #[allow(unused_mut)] 863 | let mut array; 864 | #[allow(clippy::vec_init_then_push)] 865 | { 866 | array = vec![]; 867 | $crate::msgpack_array!(array $( $tt )*); 868 | } 869 | $crate::Value::Array(array) 870 | } 871 | }; 872 | ({ $( $tt: tt )* }) => { 873 | { 874 | #[allow(unused_mut)] 875 | let mut map; 876 | #[allow(clippy::vec_init_then_push)] 877 | { 878 | map = vec![]; 879 | $crate::msgpack_map!(@key map [] $( $tt )*); 880 | } 881 | $crate::Value::Map(map) 882 | } 883 | }; 884 | ($other: expr) => { 885 | $crate::Value::from($other) 886 | }; 887 | } 888 | 889 | /// Constructs a [Value] from literal. 890 | /// 891 | /// # Example 892 | /// 893 | /// ``` 894 | /// # use msgpack_value::{msgpack, Bin, Int, Str, Value}; 895 | /// let obj = msgpack!( 896 | /// // array literal 897 | /// [ 898 | /// // numeric literals 899 | /// 0, 900 | /// -42, 901 | /// 3.14, 902 | /// 2.71f32, 903 | /// // actually any expression is allowed (as long as it's a supported type) 904 | /// 1 + 2 + 3, 905 | /// // boolean 906 | /// true, 907 | /// false, 908 | /// // nil is a keyword denoting the nil object 909 | /// nil, 910 | /// // string literal to make a string object 911 | /// "hello", 912 | /// // Use an expression of [Bin] type to create a binary object 913 | /// Bin(vec![0xDE, 0xAD, 0xBE, 0xEF]), 914 | /// // map object 915 | /// { "any value in key": nil }, 916 | /// { 0: 1, "trailing comma is ok": nil, } 917 | /// ] 918 | /// ); 919 | /// 920 | /// assert_eq!( 921 | /// obj, 922 | /// Value::Array(vec![ 923 | /// Value::Int(Int::from(0)), 924 | /// Value::Int(Int::from(-42)), 925 | /// Value::F64(3.14), 926 | /// Value::F32(2.71), 927 | /// Value::Int(Int::from(6)), 928 | /// Value::Bool(true), 929 | /// Value::Bool(false), 930 | /// Value::Nil, 931 | /// Value::Str(Str("hello".to_owned().into_bytes())), 932 | /// Value::Bin(Bin(vec![0xDE, 0xAD, 0xBE, 0xEF])), 933 | /// Value::Map(vec![( 934 | /// Value::Str(Str("any value in key".to_owned().into_bytes())), 935 | /// Value::Nil 936 | /// ),]), 937 | /// Value::Map(vec![ 938 | /// (Value::Int(Int::from(0)), Value::Int(Int::from(1))), 939 | /// ( 940 | /// Value::Str(Str("trailing comma is ok".to_owned().into_bytes())), 941 | /// Value::Nil 942 | /// ), 943 | /// ]) 944 | /// ]) 945 | /// ) 946 | /// # ; 947 | /// ``` 948 | #[macro_export] 949 | macro_rules! msgpack { 950 | ($( $tt: tt )*) => { 951 | $crate::msgpack_value!($( $tt )*) 952 | }; 953 | } 954 | 955 | #[cfg(test)] 956 | mod tests { 957 | use super::*; 958 | 959 | #[test] 960 | fn roundtrip_int() { 961 | assert_eq!(i64::MAX, Int::from(i64::MAX).try_into().unwrap()); 962 | assert_eq!(i64::MIN, Int::from(i64::MIN).try_into().unwrap()); 963 | assert_eq!(u64::MAX, Int::from(u64::MAX).try_into().unwrap()); 964 | assert_eq!(u64::MIN, Int::from(u64::MIN).try_into().unwrap()); 965 | } 966 | 967 | #[test] 968 | fn msgpack_macro() { 969 | assert_eq!(Value::Int(Int::from(42)), msgpack!(42)); 970 | assert_eq!(Value::Int(Int::from(-42)), msgpack!(-42)); 971 | assert_eq!(Value::F64(1.23), msgpack!(1.23)); 972 | assert_eq!(Value::F32(1.23), msgpack!(1.23f32)); 973 | assert_eq!( 974 | Value::Str(Str("hello world".to_owned().into_bytes())), 975 | msgpack!("hello world") 976 | ); 977 | assert_eq!(Value::Bool(true), msgpack!(true)); 978 | assert_eq!(Value::Bool(false), msgpack!(false)); 979 | assert_eq!(Value::Int(Int::from(7)), msgpack!(3 + 4)); 980 | 981 | assert_eq!(Value::Nil, msgpack!(nil)); 982 | 983 | assert_eq!( 984 | Value::Array(vec![ 985 | msgpack!(42), 986 | msgpack!(true), 987 | msgpack!(nil), 988 | msgpack!("hello"), 989 | ]), 990 | msgpack!([42, true, nil, "hello"]) 991 | ); 992 | 993 | assert_eq!( 994 | Value::Array(vec![ 995 | msgpack!(42), 996 | msgpack!(true), 997 | msgpack!(nil), 998 | msgpack!("hello"), 999 | ]), 1000 | msgpack!([42, true, nil, "hello",]) 1001 | ); 1002 | 1003 | assert_eq!( 1004 | Value::Array(vec![ 1005 | msgpack!(42), 1006 | Value::Array(vec![Value::Array(vec![msgpack!(true)]), msgpack!(nil),]), 1007 | msgpack!("hello"), 1008 | ]), 1009 | msgpack!([42, [[true], nil], "hello",]) 1010 | ); 1011 | 1012 | assert_eq!(Value::Array(vec![]), msgpack!([])); 1013 | 1014 | assert_eq!( 1015 | Value::Map(vec![ 1016 | (msgpack!(42), msgpack!(true)), 1017 | (msgpack!(nil), msgpack!("hello")), 1018 | ]), 1019 | msgpack!({ 42: true, nil: "hello", }) 1020 | ); 1021 | 1022 | assert_eq!( 1023 | Value::Map(vec![ 1024 | (msgpack!(0), msgpack!(nil)), 1025 | (msgpack!(1), msgpack!(nil)), 1026 | ]), 1027 | msgpack!({ 0: nil, 1: nil }) 1028 | ); 1029 | 1030 | assert_eq!( 1031 | Value::Map(vec![ 1032 | (msgpack!(0), msgpack!({})), 1033 | (msgpack!(1), msgpack!({})), 1034 | ]), 1035 | msgpack!({ 0: {}, 1: {} }) 1036 | ); 1037 | 1038 | assert_eq!( 1039 | Value::Map(vec![ 1040 | (msgpack!(0), msgpack!([])), 1041 | (msgpack!(1), msgpack!([])), 1042 | ]), 1043 | msgpack!({ 0: [], 1: [] }) 1044 | ); 1045 | 1046 | assert_eq!( 1047 | Value::Map(vec![ 1048 | (msgpack!(0), msgpack!(-1)), 1049 | (msgpack!(-1), msgpack!(0)), 1050 | ]), 1051 | msgpack!({ 0: -1, -1: 0 }) 1052 | ); 1053 | 1054 | assert_eq!( 1055 | Value::Map(vec![ 1056 | (msgpack!(42), msgpack!({ true: false })), 1057 | (msgpack!({ nil: 1.23 }), msgpack!("hello")), 1058 | ]), 1059 | msgpack!({ 42: { true: false }, { nil: 1.23 }: "hello", }) 1060 | ); 1061 | assert_eq!(Value::Map(vec![]), msgpack!({})); 1062 | 1063 | assert_eq!( 1064 | Value::Bin(Bin(vec![0xDEu8, 0xAD, 0xBE, 0xEF])), 1065 | msgpack!(Bin(vec![0xDE, 0xAD, 0xBE, 0xEF])) 1066 | ); 1067 | 1068 | assert_eq!(Value::Array(vec![msgpack!(-42)]), msgpack!([-42])); 1069 | } 1070 | 1071 | #[cfg(feature = "proptest")] 1072 | proptest! { 1073 | #[test] 1074 | fn no_panic_arb_int(_ in any::()) { 1075 | // pass 1076 | } 1077 | 1078 | #[test] 1079 | fn no_panic_arb_value(_ in any::()) { 1080 | // pass 1081 | } 1082 | } 1083 | } 1084 | -------------------------------------------------------------------------------- /proptest-regressions/lib.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc b437da468d02ee1d0c25c1f324721a3d4078839b76e4ce2b74050b00dc7ba098 # shrinks to v = Map([(Nil, Map([(Str(Str([])), Nil)]))]) 8 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! _msgpack-schema_ is a schema language for describing data formats encoded in MessagePack. 2 | //! It provides two derive macros `Serialize` and `Deserialize` that allow you to transcode MessagePack binary data to/from Rust data structures in a type-directed way. 3 | //! 4 | //! ```rust 5 | //! use msgpack_schema::{Deserialize, Serialize}; 6 | //! 7 | //! #[derive(Deserialize, Serialize)] 8 | //! struct Human { 9 | //! #[tag = 0] 10 | //! name: String, 11 | //! #[tag = 2] 12 | //! #[optional] 13 | //! age: Option, 14 | //! } 15 | //! ``` 16 | //! 17 | //! Compared with other schema languages like `rmp-serde`, `msgpack-schema` allows to specify more compact data representation, e.g., fixints as field keys, fixints as variant keys, etc. 18 | //! 19 | //! # Feature flags 20 | //! 21 | //! - `proptest`: Enable `proptest::arbitrary::Arbitrary` impls for `msgpack_value::Value`. 22 | //! 23 | //! # Behaviours of serializers and deserializers 24 | //! 25 | //! ## Structs with named fields 26 | //! 27 | //! Structs with named fields are serialized into a `Map` object where keys are fixints specified by `#[tag]` attributes. 28 | //! The current implementation serializes fields in order but one must not rely on this behavior. 29 | //! 30 | //! The deserializer interprets `Map` objects to create such structs. 31 | //! Field order is irrelevant to the result. 32 | //! If `Map` objects contains extra key-value pairs which are not contained in the definition of the struct, the deserializer simply ignores them. 33 | //! If there are two or more values with the same key within a `Map` object, the preceding value is overwritten by the last value. 34 | //! 35 | //! ``` 36 | //! # use msgpack_schema::*; 37 | //! # #[derive(Debug, PartialEq, Eq)] 38 | //! #[derive(Serialize, Deserialize)] 39 | //! struct S { 40 | //! #[tag = 0] 41 | //! x: u32, 42 | //! #[tag = 1] 43 | //! y: String, 44 | //! } 45 | //! 46 | //! let s = S { 47 | //! x: 42, 48 | //! y: "hello".to_owned(), 49 | //! }; 50 | //! 51 | //! let b = b"\x82\x00\x2A\x01\xA5\x68\x65\x6c\x6c\x6f"; // 10 bytes; `{ 0: 42, 1: "hello" }` 52 | //! assert_eq!(serialize(&s), b); 53 | //! assert_eq!(s, deserialize(b).unwrap()); 54 | //! 55 | //! // ignores irrelevant key-value pairs 56 | //! let b = b"\x83\x00\x2A\x02\xC3\x01\xA5\x68\x65\x6c\x6c\x6f"; // 12 bytes; `{ 0: 42, 2: true, 1: "hello" }` 57 | //! assert_eq!(s, deserialize(b).unwrap()); 58 | //! 59 | //! // last value wins 60 | //! let b = b"\x83\x00\xC3\x00\x2A\x01\xA5\x68\x65\x6c\x6c\x6f"; // 12 bytes; `{ 0: true, 0: 42, 1: "hello" }` 61 | //! assert_eq!(s, deserialize(b).unwrap()); 62 | //! ``` 63 | //! 64 | //! Fields in named structs may be tagged with `#[optional]`. 65 | //! 66 | //! - The tagged field must be of type `Option`. 67 | //! - On serialization, the key-value pair will not be included in the result map object when the field data contains `None`. 68 | //! - On deserialization, the field of the result struct will be filled with `None` when the given MsgPack map object contains no corresponding key-value pair. 69 | //! 70 | //! ``` 71 | //! # use msgpack_schema::*; 72 | //! # #[derive(Debug, PartialEq, Eq)] 73 | //! #[derive(Serialize, Deserialize)] 74 | //! struct S { 75 | //! #[tag = 0] 76 | //! x: u32, 77 | //! #[optional] 78 | //! #[tag = 1] 79 | //! y: Option, 80 | //! } 81 | //! 82 | //! let s = S { 83 | //! x: 42, 84 | //! y: Some("hello".to_owned()), 85 | //! }; 86 | //! let b = b"\x82\x00\x2A\x01\xA5\x68\x65\x6c\x6c\x6f"; // 10 bytes; `{ 0: 42, 1: "hello" }` 87 | //! assert_eq!(serialize(&s), b); 88 | //! assert_eq!(s, deserialize(b).unwrap()); 89 | //! 90 | //! let s = S { 91 | //! x: 42, 92 | //! y: None, 93 | //! }; 94 | //! let b = b"\x81\x00\x2A"; // 3 bytes; `{ 0: 42 }` 95 | //! assert_eq!(serialize(&s), b); 96 | //! assert_eq!(s, deserialize(b).unwrap()); 97 | //! ``` 98 | //! 99 | //! The `#[flatten]` attribute is used to factor out a single definition of named struct into multiple ones. 100 | //! 101 | //! ``` 102 | //! # use msgpack_schema::*; 103 | //! #[derive(Serialize)] 104 | //! struct S1 { 105 | //! #[tag = 1] 106 | //! x: u32, 107 | //! } 108 | //! 109 | //! #[derive(Serialize)] 110 | //! struct S2 { 111 | //! #[flatten] 112 | //! s1: S1, 113 | //! #[tag = 2] 114 | //! y: u32, 115 | //! } 116 | //! 117 | //! #[derive(Serialize)] 118 | //! struct S3 { 119 | //! #[tag = 1] 120 | //! x: u32, 121 | //! #[tag = 2] 122 | //! y: u32, 123 | //! } 124 | //! 125 | //! assert_eq!(serialize(S2 { s1: S1 { x: 42 }, y: 43, }), serialize(S3 { x: 42, y: 43 })); 126 | //! ``` 127 | //! 128 | //! Structs with named fields may be attached `#[untagged]`. 129 | //! Untagged structs are serialized into an array and will not contain tags. 130 | //! 131 | //! ``` 132 | //! # use msgpack_schema::*; 133 | //! # #[derive(Debug, PartialEq, Eq)] 134 | //! #[derive(Serialize, Deserialize)] 135 | //! #[untagged] 136 | //! struct S { 137 | //! x: u32, 138 | //! y: String, 139 | //! } 140 | //! 141 | //! let s = S { 142 | //! x: 42, 143 | //! y: "hello".to_owned(), 144 | //! }; 145 | //! let b = b"\x92\x2A\xA5\x68\x65\x6c\x6c\x6f"; // 8 bytes; `[ 42, "hello" ]` 146 | //! 147 | //! assert_eq!(serialize(&s), b); 148 | //! assert_eq!(s, deserialize(b).unwrap()); 149 | //! ``` 150 | //! 151 | //! ## Newtype structs 152 | //! 153 | //! Tuple structs with only one element are treated transparently. 154 | //! 155 | //! ``` 156 | //! # use msgpack_schema::*; 157 | //! # #[derive(Debug, PartialEq, Eq)] 158 | //! #[derive(Serialize, Deserialize)] 159 | //! struct S(u32); 160 | //! 161 | //! let s = S(42); 162 | //! let b = b"\x2A"; // 1 byte; `42` 163 | //! 164 | //! assert_eq!(serialize(&s), b); 165 | //! assert_eq!(s, deserialize(b).unwrap()); 166 | //! ``` 167 | //! 168 | //! ## Unit structs and empty tuple structs 169 | //! 170 | //! Serialization and deserialization of unit structs and empty tuple structs are intentionally unsupported. 171 | //! 172 | //! ``` 173 | //! // It is error to derive `Serialize` / `Deserialize` for these types of structs. 174 | //! struct S1; 175 | //! struct S2(); 176 | //! ``` 177 | //! 178 | //! ## Tuple structs 179 | //! 180 | //! Tuple structs with more than one element are encoded as an array. 181 | //! It is validation error to deserialize an array with unmatched length. 182 | //! 183 | //! ``` 184 | //! # use msgpack_schema::*; 185 | //! # #[derive(Debug, PartialEq, Eq)] 186 | //! #[derive(Serialize, Deserialize)] 187 | //! struct S(u32, bool); 188 | //! 189 | //! let s = S(42, true); 190 | //! let b = b"\x92\x2A\xC3"; // 3 bytes; `[ 42, true ]` 191 | //! 192 | //! assert_eq!(serialize(&s), b); 193 | //! assert_eq!(s, deserialize(b).unwrap()); 194 | //! ``` 195 | //! 196 | //! ## Unit variants and empty tuple variants 197 | //! 198 | //! Unit variants and empty tuple variants are serialized into a single fixint whose value is determined by the tag. 199 | //! 200 | //! ``` 201 | //! # use msgpack_schema::*; 202 | //! # #[derive(Debug, PartialEq, Eq)] 203 | //! #[derive(Serialize, Deserialize)] 204 | //! enum E { 205 | //! #[tag = 3] 206 | //! Foo 207 | //! } 208 | //! 209 | //! let e = E::Foo; 210 | //! let b = b"\x03"; // 1 byte; `3` 211 | //! 212 | //! assert_eq!(serialize(&e), b); 213 | //! assert_eq!(e, deserialize(b).unwrap()); 214 | //! ``` 215 | //! 216 | //! ``` 217 | //! # use msgpack_schema::*; 218 | //! # #[derive(Debug, PartialEq, Eq)] 219 | //! #[derive(Serialize, Deserialize)] 220 | //! enum E { 221 | //! #[tag = 3] 222 | //! Foo() 223 | //! } 224 | //! 225 | //! let e = E::Foo(); 226 | //! let b = b"\x03"; // 1 byte; `3` 227 | //! 228 | //! assert_eq!(serialize(&e), b); 229 | //! assert_eq!(e, deserialize(b).unwrap()); 230 | //! ``` 231 | //! 232 | //! ## Newtype variants 233 | //! 234 | //! Newtype variants (one-element tuple variants) are serialized into an array of the tag and the inner value. 235 | //! 236 | //! ``` 237 | //! # use msgpack_schema::*; 238 | //! # #[derive(Debug, PartialEq, Eq)] 239 | //! #[derive(Serialize, Deserialize)] 240 | //! enum E { 241 | //! #[tag = 3] 242 | //! Foo(u32) 243 | //! } 244 | //! 245 | //! let e = E::Foo(42); 246 | //! let b = b"\x92\x03\x2A"; // 3 bytes; `[ 3, 42 ]` 247 | //! 248 | //! assert_eq!(serialize(&e), b); 249 | //! assert_eq!(e, deserialize(b).unwrap()); 250 | //! ``` 251 | //! 252 | //! ## Untagged variants 253 | //! 254 | //! Enums may be attached `#[untagged]` when all variants are newtype variants. 255 | //! Serializing untagged variants results in the same data layout as the inner type. 256 | //! The deserializer deserializes into an untagged enum type by trying deserization one by one from the first variant to the last. 257 | //! 258 | //! ``` 259 | //! # use msgpack_schema::*; 260 | //! # #[derive(Debug, PartialEq, Eq)] 261 | //! #[derive(Serialize, Deserialize)] 262 | //! #[untagged] 263 | //! enum E { 264 | //! Foo(String), 265 | //! Bar(u32), 266 | //! } 267 | //! 268 | //! let e = E::Bar(42); 269 | //! let b = b"\x2A"; // 1 byte; `42` 270 | //! 271 | //! assert_eq!(serialize(&e), b); 272 | //! assert_eq!(e, deserialize(b).unwrap()); 273 | //! ``` 274 | //! 275 | //! # Write your own implementation of `Serialize` and `Deserialize` 276 | //! 277 | //! You may want to write your own implementation of `Serialize` and `Deserialize` in the following cases: 278 | //! 279 | //! 1. You need `impl` for types that are already defined by someone. 280 | //! 2. You need extreme efficiency. 281 | //! 3. Both. 282 | //! 283 | //! [IpAddr](std::net::IpAddr) is such a type satisfying (3). 284 | //! In the most efficient situation, we want it to be 4 or 16 byte length plus one byte for a tag at any time. 285 | //! This is achieved by giving a hard-written implementation like below. 286 | //! 287 | //! ``` 288 | //! # use msgpack_schema::*; 289 | //! # use msgpack_value::*; 290 | //! struct IpAddr(pub std::net::IpAddr); 291 | //! 292 | //! impl Serialize for IpAddr { 293 | //! fn serialize(&self, serializer: &mut Serializer) { 294 | //! match self.0 { 295 | //! std::net::IpAddr::V4(v4) => { 296 | //! serializer.serialize_str(&v4.octets()); // 5 bytes 297 | //! } 298 | //! std::net::IpAddr::V6(v6) => { 299 | //! serializer.serialize_str(&v6.octets()); // 17 bytes 300 | //! } 301 | //! } 302 | //! } 303 | //! } 304 | //! 305 | //! impl Deserialize for IpAddr { 306 | //! fn deserialize(deserializer: &mut Deserializer) -> Result { 307 | //! let Str(data) = deserializer.deserialize()?; 308 | //! let ipaddr = match data.len() { 309 | //! 4 => std::net::IpAddr::V4(std::net::Ipv4Addr::from( 310 | //! <[u8; 4]>::try_from(data).unwrap(), 311 | //! )), 312 | //! 16 => std::net::IpAddr::V6(std::net::Ipv6Addr::from( 313 | //! <[u8; 16]>::try_from(data).unwrap(), 314 | //! )), 315 | //! _ => return Err(ValidationError.into()), 316 | //! }; 317 | //! Ok(Self(ipaddr)) 318 | //! } 319 | //! } 320 | //! ``` 321 | //! 322 | //! # Appendix: Cheatsheet 323 | //! 324 | //! 325 | //! 326 | //! 327 | //! 328 | //! 329 | //! 330 | //! 331 | //! 340 | //! 343 | //! 346 | //! 347 | //! 348 | //! 356 | //! 359 | //! 362 | //! 363 | //! 364 | //! 372 | //! 375 | //! 378 | //! 379 | //! 380 | //! 390 | //! 393 | //! 396 | //! 397 | //! 398 | //! 401 | //! 404 | //! 407 | //! 408 | //! 409 | //! 412 | //! 415 | //! 416 | //! 417 | //! 418 | //! 421 | //! 424 | //! 425 | //! 426 | //! 427 | //! 430 | //! 433 | //! 436 | //! 437 | //! 438 | //! 444 | //! 447 | //! 450 | //! 451 | //! 452 | //! 458 | //! 461 | //! 464 | //! 465 | //! 466 | //! 472 | //! 475 | //! 478 | //! 479 | //! 480 | //! 487 | //! 490 | //! 493 | //! 494 | //!
schemaRustMessagePack (human readable)
332 | //!
struct S {
 333 | //!     #[tag = 0]
 334 | //!     x: u32,
 335 | //!     #[tag = 1]
 336 | //!     y: bool,
 337 | //! }
 338 | //! 
339 | //!
341 | //! S { x: 42, y: true } 342 | //! 344 | //! { 0: 42, 1: true } 345 | //!
349 | //!
struct S {
 350 | //!     #[optional]
 351 | //!     #[tag = 0]
 352 | //!     x: Option<u32>,
 353 | //! }
 354 | //! 
355 | //!
357 | //! S { x: Some(42) } 358 | //! 360 | //! { 0: 42 } 361 | //!
365 | //!
struct S {
 366 | //!     #[optional]
 367 | //!     #[tag = 0]
 368 | //!     x: Option<u32>,
 369 | //! }
 370 | //! 
371 | //!
373 | //! S { x: None } 374 | //! 376 | //! {} 377 | //!
381 | //!
#[untagged]
 382 | //! struct S {
 383 | //!     #[tag = 0]
 384 | //!     x: u32,
 385 | //!     #[tag = 1]
 386 | //!     y: bool,
 387 | //! }
 388 | //! 
389 | //!
391 | //! S { x: 42, y: true } 392 | //! 394 | //! [ 42, true ] 395 | //!
399 | //! struct S(u32) 400 | //! 402 | //! S(42) 403 | //! 405 | //! 42 406 | //!
410 | //! struct S 411 | //! 413 | //! S 414 | //! UNSUPPORTED
419 | //! struct S() 420 | //! 422 | //! S() 423 | //! UNSUPPORTED
428 | //! struct S(u32, bool) 429 | //! 431 | //! S(42, true) 432 | //! 434 | //! [ 42, true ] 435 | //!
439 | //!
enum E {
 440 | //!     #[tag = 3]
 441 | //!     Foo
 442 | //! }
443 | //!
445 | //! E::Foo 446 | //! 448 | //! 3 449 | //!
453 | //!
enum E {
 454 | //!     #[tag = 3]
 455 | //!     Foo()
 456 | //! }
457 | //!
459 | //! E::Foo() 460 | //! 462 | //! 3 463 | //!
467 | //!
enum E {
 468 | //!     #[tag = 3]
 469 | //!     Foo(u32)
 470 | //! }
471 | //!
473 | //! E::Foo(42) 474 | //! 476 | //! [ 3, 42 ] 477 | //!
481 | //!
#[untagged]
 482 | //! enum E {
 483 | //!     Foo(u32)
 484 | //!     Bar(bool)
 485 | //! }
486 | //!
488 | //! E::Bar(true) 489 | //! 491 | //! true 492 | //!
495 | //! 496 | 497 | use byteorder::BigEndian; 498 | use byteorder::{self, ReadBytesExt}; 499 | pub use msgpack_schema_impl::*; 500 | use msgpack_value::Value; 501 | use msgpack_value::{Bin, Ext, Int, Str}; 502 | use std::convert::TryFrom; 503 | use std::convert::TryInto; 504 | use std::io::Write; 505 | use thiserror::Error; 506 | 507 | /// This type holds all intermediate states during serialization. 508 | pub struct Serializer { 509 | w: Vec, 510 | } 511 | 512 | impl Serializer { 513 | fn new() -> Self { 514 | Self { w: vec![] } 515 | } 516 | fn with_vec(w: Vec) -> Self { 517 | Self { w } 518 | } 519 | fn into_inner(self) -> Vec { 520 | self.w 521 | } 522 | 523 | pub fn serialize_nil(&mut self) { 524 | rmp::encode::write_nil(&mut self.w).unwrap() 525 | } 526 | pub fn serialize_bool(&mut self, v: bool) { 527 | rmp::encode::write_bool(&mut self.w, v).unwrap() 528 | } 529 | pub fn serialize_int(&mut self, v: Int) { 530 | if let Ok(v) = i64::try_from(v) { 531 | rmp::encode::write_sint(&mut self.w, v).unwrap(); 532 | } else { 533 | rmp::encode::write_uint(&mut self.w, u64::try_from(v).unwrap()).unwrap(); 534 | } 535 | } 536 | pub fn serialize_f32(&mut self, v: f32) { 537 | rmp::encode::write_f32(&mut self.w, v).unwrap(); 538 | } 539 | pub fn serialize_f64(&mut self, v: f64) { 540 | rmp::encode::write_f64(&mut self.w, v).unwrap(); 541 | } 542 | pub fn serialize_str(&mut self, v: &[u8]) { 543 | rmp::encode::write_str_len(&mut self.w, v.len() as u32).unwrap(); 544 | self.w.write_all(v).unwrap(); 545 | } 546 | pub fn serialize_bin(&mut self, v: &[u8]) { 547 | rmp::encode::write_bin(&mut self.w, v).unwrap(); 548 | } 549 | pub fn serialize_array(&mut self, len: u32) { 550 | rmp::encode::write_array_len(&mut self.w, len).unwrap(); 551 | } 552 | pub fn serialize_map(&mut self, len: u32) { 553 | rmp::encode::write_map_len(&mut self.w, len).unwrap(); 554 | } 555 | pub fn serialize_ext(&mut self, tag: i8, data: &[u8]) { 556 | rmp::encode::write_ext_meta(&mut self.w, data.len() as u32, tag).unwrap(); 557 | self.w.write_all(data).unwrap(); 558 | } 559 | 560 | /// Equivalent to `S::serialize(&s, self)`. 561 | pub fn serialize(&mut self, s: S) { 562 | S::serialize(&s, self) 563 | } 564 | } 565 | 566 | pub trait Serialize { 567 | fn serialize(&self, serializer: &mut Serializer); 568 | } 569 | 570 | impl Serialize for &T { 571 | fn serialize(&self, serializer: &mut Serializer) { 572 | T::serialize(*self, serializer) 573 | } 574 | } 575 | 576 | impl Serialize for bool { 577 | fn serialize(&self, serializer: &mut Serializer) { 578 | serializer.serialize_bool(*self) 579 | } 580 | } 581 | 582 | impl Serialize for Int { 583 | fn serialize(&self, serializer: &mut Serializer) { 584 | serializer.serialize_int(*self) 585 | } 586 | } 587 | 588 | impl Serialize for u8 { 589 | fn serialize(&self, serializer: &mut Serializer) { 590 | serializer.serialize_int(Int::from(*self)) 591 | } 592 | } 593 | 594 | impl Serialize for u16 { 595 | fn serialize(&self, serializer: &mut Serializer) { 596 | serializer.serialize_int(Int::from(*self)) 597 | } 598 | } 599 | 600 | impl Serialize for u32 { 601 | fn serialize(&self, serializer: &mut Serializer) { 602 | serializer.serialize_int(Int::from(*self)) 603 | } 604 | } 605 | 606 | impl Serialize for u64 { 607 | fn serialize(&self, serializer: &mut Serializer) { 608 | serializer.serialize_int(Int::from(*self)) 609 | } 610 | } 611 | 612 | impl Serialize for i8 { 613 | fn serialize(&self, serializer: &mut Serializer) { 614 | serializer.serialize_int(Int::from(*self)) 615 | } 616 | } 617 | 618 | impl Serialize for i16 { 619 | fn serialize(&self, serializer: &mut Serializer) { 620 | serializer.serialize_int(Int::from(*self)) 621 | } 622 | } 623 | 624 | impl Serialize for i32 { 625 | fn serialize(&self, serializer: &mut Serializer) { 626 | serializer.serialize_int(Int::from(*self)) 627 | } 628 | } 629 | 630 | impl Serialize for i64 { 631 | fn serialize(&self, serializer: &mut Serializer) { 632 | serializer.serialize_int(Int::from(*self)) 633 | } 634 | } 635 | 636 | impl Serialize for f32 { 637 | fn serialize(&self, serializer: &mut Serializer) { 638 | serializer.serialize_f32(*self) 639 | } 640 | } 641 | 642 | impl Serialize for f64 { 643 | fn serialize(&self, serializer: &mut Serializer) { 644 | serializer.serialize_f64(*self) 645 | } 646 | } 647 | 648 | impl Serialize for Str { 649 | fn serialize(&self, serializer: &mut Serializer) { 650 | serializer.serialize_str(&self.0) 651 | } 652 | } 653 | 654 | impl Serialize for str { 655 | fn serialize(&self, serializer: &mut Serializer) { 656 | serializer.serialize_str(self.as_bytes()) 657 | } 658 | } 659 | 660 | impl Serialize for String { 661 | fn serialize(&self, serializer: &mut Serializer) { 662 | serializer.serialize_str(self.as_bytes()) 663 | } 664 | } 665 | 666 | impl Serialize for [T] { 667 | fn serialize(&self, serializer: &mut Serializer) { 668 | serializer.serialize_array(self.len() as u32); 669 | for x in self { 670 | serializer.serialize(x); 671 | } 672 | } 673 | } 674 | 675 | impl Serialize for Vec { 676 | fn serialize(&self, serializer: &mut Serializer) { 677 | serializer.serialize_array(self.len() as u32); 678 | for x in self { 679 | serializer.serialize(x); 680 | } 681 | } 682 | } 683 | 684 | impl Serialize for Box { 685 | fn serialize(&self, serializer: &mut Serializer) { 686 | serializer.serialize(&**self); 687 | } 688 | } 689 | 690 | impl Serialize for std::rc::Rc { 691 | fn serialize(&self, serializer: &mut Serializer) { 692 | serializer.serialize(&**self); 693 | } 694 | } 695 | 696 | impl Serialize for std::sync::Arc { 697 | fn serialize(&self, serializer: &mut Serializer) { 698 | serializer.serialize(&**self); 699 | } 700 | } 701 | 702 | #[doc(hidden)] 703 | pub trait StructSerialize: Serialize { 704 | fn count_fields(&self) -> u32; 705 | fn serialize_fields(&self, serializer: &mut Serializer); 706 | } 707 | 708 | #[derive(Debug, Clone, PartialEq)] 709 | pub enum Token<'a> { 710 | Nil, 711 | Bool(bool), 712 | Int(Int), 713 | F32(f32), 714 | F64(f64), 715 | Str(&'a [u8]), 716 | Bin(&'a [u8]), 717 | Array(u32), 718 | Map(u32), 719 | Ext { tag: i8, data: &'a [u8] }, 720 | } 721 | 722 | /// This error type represents blob-to-MessegePack transcode errors. 723 | /// 724 | /// This error type is raised during deserialization either 725 | /// 1. when (first bytes of) given binary data is not a message pack object, or 726 | /// 2. when it unexpectedly reaches the end of input. 727 | #[derive(Debug, Error)] 728 | #[error("invalid input")] 729 | pub struct InvalidInputError; 730 | 731 | /// This type holds all intermediate states during deserialization. 732 | #[derive(Clone, Copy)] 733 | pub struct Deserializer<'a> { 734 | r: &'a [u8], 735 | } 736 | 737 | impl<'a> Deserializer<'a> { 738 | fn new(r: &'a [u8]) -> Self { 739 | Self { r } 740 | } 741 | 742 | pub fn deserialize_token(&mut self) -> Result { 743 | let token = match rmp::decode::read_marker(&mut self.r).map_err(|_| InvalidInputError)? { 744 | rmp::Marker::Null => Token::Nil, 745 | rmp::Marker::True => Token::Bool(true), 746 | rmp::Marker::False => Token::Bool(false), 747 | rmp::Marker::FixPos(v) => Token::Int(Int::from(v)), 748 | rmp::Marker::FixNeg(v) => Token::Int(Int::from(v)), 749 | rmp::Marker::U8 => { 750 | Token::Int(Int::from(self.r.read_u8().map_err(|_| InvalidInputError)?)) 751 | } 752 | rmp::Marker::U16 => Token::Int(Int::from( 753 | self.r 754 | .read_u16::() 755 | .map_err(|_| InvalidInputError)?, 756 | )), 757 | rmp::Marker::U32 => Token::Int(Int::from( 758 | self.r 759 | .read_u32::() 760 | .map_err(|_| InvalidInputError)?, 761 | )), 762 | rmp::Marker::U64 => Token::Int(Int::from( 763 | self.r 764 | .read_u64::() 765 | .map_err(|_| InvalidInputError)?, 766 | )), 767 | rmp::Marker::I8 => { 768 | Token::Int(Int::from(self.r.read_i8().map_err(|_| InvalidInputError)?)) 769 | } 770 | rmp::Marker::I16 => Token::Int(Int::from( 771 | self.r 772 | .read_i16::() 773 | .map_err(|_| InvalidInputError)?, 774 | )), 775 | rmp::Marker::I32 => Token::Int(Int::from( 776 | self.r 777 | .read_i32::() 778 | .map_err(|_| InvalidInputError)?, 779 | )), 780 | rmp::Marker::I64 => Token::Int(Int::from( 781 | self.r 782 | .read_i64::() 783 | .map_err(|_| InvalidInputError)?, 784 | )), 785 | rmp::Marker::F32 => Token::F32( 786 | self.r 787 | .read_f32::() 788 | .map_err(|_| InvalidInputError)?, 789 | ), 790 | rmp::Marker::F64 => Token::F64( 791 | self.r 792 | .read_f64::() 793 | .map_err(|_| InvalidInputError)?, 794 | ), 795 | rmp::Marker::FixStr(len) => { 796 | let len = len as usize; 797 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 798 | self.r = self.r.get(len..).unwrap(); 799 | Token::Str(ret) 800 | } 801 | rmp::Marker::Str8 => { 802 | let len = self.r.read_u8().map_err(|_| InvalidInputError)? as usize; 803 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 804 | self.r = self.r.get(len..).unwrap(); 805 | Token::Str(ret) 806 | } 807 | rmp::Marker::Str16 => { 808 | let len = self 809 | .r 810 | .read_u16::() 811 | .map_err(|_| InvalidInputError)? as usize; 812 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 813 | self.r = self.r.get(len..).unwrap(); 814 | Token::Str(ret) 815 | } 816 | rmp::Marker::Str32 => { 817 | let len = self 818 | .r 819 | .read_u32::() 820 | .map_err(|_| InvalidInputError)? as usize; 821 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 822 | self.r = self.r.get(len..).unwrap(); 823 | Token::Str(ret) 824 | } 825 | rmp::Marker::Bin8 => { 826 | let len = self.r.read_u8().map_err(|_| InvalidInputError)? as usize; 827 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 828 | self.r = self.r.get(len..).unwrap(); 829 | Token::Bin(ret) 830 | } 831 | rmp::Marker::Bin16 => { 832 | let len = self 833 | .r 834 | .read_u16::() 835 | .map_err(|_| InvalidInputError)? as usize; 836 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 837 | self.r = self.r.get(len..).unwrap(); 838 | Token::Bin(ret) 839 | } 840 | rmp::Marker::Bin32 => { 841 | let len = self 842 | .r 843 | .read_u32::() 844 | .map_err(|_| InvalidInputError)? as usize; 845 | let ret = self.r.get(0..len).ok_or(InvalidInputError)?; 846 | self.r = self.r.get(len..).unwrap(); 847 | Token::Bin(ret) 848 | } 849 | rmp::Marker::FixArray(len) => Token::Array(len as u32), 850 | rmp::Marker::Array16 => Token::Array( 851 | self.r 852 | .read_u16::() 853 | .map_err(|_| InvalidInputError)? as u32, 854 | ), 855 | rmp::Marker::Array32 => Token::Array( 856 | self.r 857 | .read_u32::() 858 | .map_err(|_| InvalidInputError)?, 859 | ), 860 | rmp::Marker::FixMap(len) => Token::Map(len as u32), 861 | rmp::Marker::Map16 => Token::Map( 862 | self.r 863 | .read_u16::() 864 | .map_err(|_| InvalidInputError)? as u32, 865 | ), 866 | rmp::Marker::Map32 => Token::Map( 867 | self.r 868 | .read_u32::() 869 | .map_err(|_| InvalidInputError)?, 870 | ), 871 | rmp::Marker::FixExt1 => { 872 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 873 | let data = self.r.get(0..1).ok_or(InvalidInputError)?; 874 | self.r = self.r.get(1..).unwrap(); 875 | Token::Ext { tag, data } 876 | } 877 | rmp::Marker::FixExt2 => { 878 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 879 | let data = self.r.get(0..2).ok_or(InvalidInputError)?; 880 | self.r = self.r.get(2..).unwrap(); 881 | Token::Ext { tag, data } 882 | } 883 | rmp::Marker::FixExt4 => { 884 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 885 | let data = self.r.get(0..4).ok_or(InvalidInputError)?; 886 | self.r = self.r.get(4..).unwrap(); 887 | Token::Ext { tag, data } 888 | } 889 | rmp::Marker::FixExt8 => { 890 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 891 | let data = self.r.get(0..8).ok_or(InvalidInputError)?; 892 | self.r = self.r.get(8..).unwrap(); 893 | Token::Ext { tag, data } 894 | } 895 | rmp::Marker::FixExt16 => { 896 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 897 | let data = self.r.get(0..16).ok_or(InvalidInputError)?; 898 | self.r = self.r.get(16..).unwrap(); 899 | Token::Ext { tag, data } 900 | } 901 | rmp::Marker::Ext8 => { 902 | let len = self.r.read_u8().map_err(|_| InvalidInputError)? as usize; 903 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 904 | let data = self.r.get(0..len).ok_or(InvalidInputError)?; 905 | self.r = self.r.get(len..).unwrap(); 906 | Token::Ext { tag, data } 907 | } 908 | rmp::Marker::Ext16 => { 909 | let len = self 910 | .r 911 | .read_u16::() 912 | .map_err(|_| InvalidInputError)? as usize; 913 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 914 | let data = self.r.get(0..len).ok_or(InvalidInputError)?; 915 | self.r = self.r.get(len..).unwrap(); 916 | Token::Ext { tag, data } 917 | } 918 | rmp::Marker::Ext32 => { 919 | let len = self 920 | .r 921 | .read_u32::() 922 | .map_err(|_| InvalidInputError)? as usize; 923 | let tag = self.r.read_i8().map_err(|_| InvalidInputError)?; 924 | let data = self.r.get(0..len).ok_or(InvalidInputError)?; 925 | self.r = self.r.get(len..).unwrap(); 926 | Token::Ext { tag, data } 927 | } 928 | rmp::Marker::Reserved => return Err(InvalidInputError), 929 | }; 930 | Ok(token) 931 | } 932 | 933 | /// Equivalent to `D::deserialize(self)`. 934 | pub fn deserialize(&mut self) -> Result { 935 | D::deserialize(self) 936 | } 937 | 938 | /// Tries to deserialize an object of `D`. 939 | /// If it succeeds it returns `Ok(Some(_))` and the internal state of `self` is changed. 940 | /// If it fails with `ValidationError` it returns `Ok(None)` and the internal state of `self` is left unchanged. 941 | /// If it fails with `InvalidInputError` it passes on the error. 942 | pub fn try_deserialize(&mut self) -> Result, InvalidInputError> { 943 | let mut branch = *self; 944 | match branch.deserialize() { 945 | Ok(v) => { 946 | *self = branch; 947 | Ok(Some(v)) 948 | } 949 | Err(DeserializeError::Validation(_)) => Ok(None), 950 | Err(DeserializeError::InvalidInput(err)) => Err(err), 951 | } 952 | } 953 | 954 | /// Read any single message pack object and discard it. 955 | pub fn deserialize_any(&mut self) -> Result<(), DeserializeError> { 956 | let mut count = 1; 957 | while count > 0 { 958 | count -= 1; 959 | match self.deserialize_token()? { 960 | Token::Nil 961 | | Token::Bool(_) 962 | | Token::Int(_) 963 | | Token::F32(_) 964 | | Token::F64(_) 965 | | Token::Str(_) 966 | | Token::Bin(_) 967 | | Token::Ext { .. } => {} 968 | Token::Array(len) => { 969 | count += len; 970 | } 971 | Token::Map(len) => { 972 | count += len * 2; 973 | } 974 | } 975 | } 976 | Ok(()) 977 | } 978 | } 979 | 980 | /// This error type represents type mismatch errors during deserialization. 981 | #[derive(Debug, Error)] 982 | #[error("validation failed")] 983 | pub struct ValidationError; 984 | 985 | /// This error type represents all possible errors during deserialization. 986 | #[derive(Debug, Error)] 987 | pub enum DeserializeError { 988 | #[error(transparent)] 989 | InvalidInput(#[from] InvalidInputError), 990 | #[error(transparent)] 991 | Validation(#[from] ValidationError), 992 | } 993 | 994 | pub trait Deserialize: Sized { 995 | fn deserialize(deserializer: &mut Deserializer) -> Result; 996 | } 997 | 998 | impl Deserialize for bool { 999 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1000 | if let Token::Bool(v) = deserializer.deserialize_token()? { 1001 | return Ok(v); 1002 | } 1003 | Err(ValidationError.into()) 1004 | } 1005 | } 1006 | 1007 | impl Deserialize for Int { 1008 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1009 | if let Token::Int(v) = deserializer.deserialize_token()? { 1010 | return Ok(v); 1011 | } 1012 | Err(ValidationError.into()) 1013 | } 1014 | } 1015 | 1016 | impl Deserialize for u8 { 1017 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1018 | deserializer 1019 | .deserialize::()? 1020 | .try_into() 1021 | .map_err(|_| ValidationError.into()) 1022 | } 1023 | } 1024 | 1025 | impl Deserialize for u16 { 1026 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1027 | deserializer 1028 | .deserialize::()? 1029 | .try_into() 1030 | .map_err(|_| ValidationError.into()) 1031 | } 1032 | } 1033 | 1034 | impl Deserialize for u32 { 1035 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1036 | deserializer 1037 | .deserialize::()? 1038 | .try_into() 1039 | .map_err(|_| ValidationError.into()) 1040 | } 1041 | } 1042 | 1043 | impl Deserialize for u64 { 1044 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1045 | deserializer 1046 | .deserialize::()? 1047 | .try_into() 1048 | .map_err(|_| ValidationError.into()) 1049 | } 1050 | } 1051 | 1052 | impl Deserialize for i8 { 1053 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1054 | deserializer 1055 | .deserialize::()? 1056 | .try_into() 1057 | .map_err(|_| ValidationError.into()) 1058 | } 1059 | } 1060 | 1061 | impl Deserialize for i16 { 1062 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1063 | deserializer 1064 | .deserialize::()? 1065 | .try_into() 1066 | .map_err(|_| ValidationError.into()) 1067 | } 1068 | } 1069 | 1070 | impl Deserialize for i32 { 1071 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1072 | deserializer 1073 | .deserialize::()? 1074 | .try_into() 1075 | .map_err(|_| ValidationError.into()) 1076 | } 1077 | } 1078 | 1079 | impl Deserialize for i64 { 1080 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1081 | deserializer 1082 | .deserialize::()? 1083 | .try_into() 1084 | .map_err(|_| ValidationError.into()) 1085 | } 1086 | } 1087 | 1088 | impl Deserialize for f32 { 1089 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1090 | if let Token::F32(v) = deserializer.deserialize_token()? { 1091 | return Ok(v); 1092 | } 1093 | Err(ValidationError.into()) 1094 | } 1095 | } 1096 | 1097 | impl Deserialize for f64 { 1098 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1099 | if let Token::F64(v) = deserializer.deserialize_token()? { 1100 | return Ok(v); 1101 | } 1102 | Err(ValidationError.into()) 1103 | } 1104 | } 1105 | 1106 | impl Deserialize for Str { 1107 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1108 | if let Token::Str(v) = deserializer.deserialize_token()? { 1109 | return Ok(Str(v.to_vec())); 1110 | } 1111 | Err(ValidationError.into()) 1112 | } 1113 | } 1114 | 1115 | impl Deserialize for String { 1116 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1117 | let Str(data) = deserializer.deserialize()?; 1118 | let v = String::from_utf8(data).map_err(|_| ValidationError)?; 1119 | Ok(v) 1120 | } 1121 | } 1122 | 1123 | impl Deserialize for Vec { 1124 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1125 | if let Token::Array(len) = deserializer.deserialize_token()? { 1126 | let mut vec = Vec::with_capacity(len as usize); 1127 | for _ in 0..len { 1128 | vec.push(deserializer.deserialize()?); 1129 | } 1130 | return Ok(vec); 1131 | } 1132 | Err(ValidationError.into()) 1133 | } 1134 | } 1135 | 1136 | impl Deserialize for Box { 1137 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1138 | Ok(Box::new(deserializer.deserialize()?)) 1139 | } 1140 | } 1141 | 1142 | impl Deserialize for std::rc::Rc { 1143 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1144 | Ok(Self::new(deserializer.deserialize()?)) 1145 | } 1146 | } 1147 | 1148 | impl Deserialize for std::sync::Arc { 1149 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1150 | Ok(Self::new(deserializer.deserialize()?)) 1151 | } 1152 | } 1153 | 1154 | /// Write out a MessagePack object. 1155 | pub fn serialize(s: S) -> Vec { 1156 | let mut serializer = Serializer::new(); 1157 | serializer.serialize(s); 1158 | serializer.into_inner() 1159 | } 1160 | 1161 | /// Write a MessagePack object into the given buffer. 1162 | /// 1163 | /// This function does not modify the data originally in [buf]. 1164 | pub fn serialize_into(s: S, buf: &mut Vec) { 1165 | let v = std::mem::take(buf); 1166 | let mut serializer = Serializer::with_vec(v); 1167 | serializer.serialize(s); 1168 | *buf = serializer.into_inner(); 1169 | } 1170 | 1171 | /// Read out a MessagePack object. 1172 | /// 1173 | /// If the input contains extra bytes following a valid msgpack object, 1174 | /// this function silently ignores them. 1175 | pub fn deserialize(r: &[u8]) -> Result { 1176 | let mut deserializer = Deserializer::new(r); 1177 | deserializer.deserialize() 1178 | } 1179 | 1180 | #[test] 1181 | fn deserialize_ignores_extra_bytes() { 1182 | let input: Vec = vec![0x01, 0xc1]; 1183 | let v: Int = deserialize(&input).unwrap(); 1184 | assert_eq!(v, Int::from(1u32)); 1185 | } 1186 | 1187 | impl Serialize for Value { 1188 | fn serialize(&self, serializer: &mut Serializer) { 1189 | match self { 1190 | Value::Nil => serializer.serialize_nil(), 1191 | Value::Bool(v) => serializer.serialize_bool(*v), 1192 | Value::Int(v) => serializer.serialize_int(*v), 1193 | Value::F32(v) => serializer.serialize_f32(*v), 1194 | Value::F64(v) => serializer.serialize_f64(*v), 1195 | Value::Str(v) => serializer.serialize_str(&v.0), 1196 | Value::Bin(v) => serializer.serialize_bin(&v.0), 1197 | Value::Array(v) => { 1198 | serializer.serialize_array(v.len() as u32); 1199 | for x in v { 1200 | serializer.serialize(x); 1201 | } 1202 | } 1203 | Value::Map(v) => { 1204 | serializer.serialize_map(v.len() as u32); 1205 | for (k, v) in v { 1206 | serializer.serialize(k); 1207 | serializer.serialize(v); 1208 | } 1209 | } 1210 | Value::Ext(v) => serializer.serialize_ext(v.r#type, &v.data), 1211 | } 1212 | } 1213 | } 1214 | 1215 | impl Deserialize for Value { 1216 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1217 | let x = match deserializer.deserialize_token()? { 1218 | Token::Nil => Value::Nil, 1219 | Token::Bool(v) => v.into(), 1220 | Token::Int(v) => v.into(), 1221 | Token::F32(v) => v.into(), 1222 | Token::F64(v) => v.into(), 1223 | Token::Str(v) => Str(v.to_vec()).into(), 1224 | Token::Bin(v) => Bin(v.to_vec()).into(), 1225 | Token::Array(len) => { 1226 | let mut vec: Vec = vec![]; 1227 | for _ in 0..len { 1228 | vec.push(deserializer.deserialize()?); 1229 | } 1230 | vec.into() 1231 | } 1232 | Token::Map(len) => { 1233 | let mut map: Vec<(Value, Value)> = vec![]; 1234 | for _ in 0..len { 1235 | map.push((deserializer.deserialize()?, deserializer.deserialize()?)); 1236 | } 1237 | map.into() 1238 | } 1239 | Token::Ext { tag, data } => Ext { 1240 | r#type: tag, 1241 | data: data.to_vec(), 1242 | } 1243 | .into(), 1244 | }; 1245 | Ok(x) 1246 | } 1247 | } 1248 | 1249 | // for backward compatibility 1250 | #[doc(hidden)] 1251 | pub mod value { 1252 | use super::*; 1253 | 1254 | pub use msgpack_value::{Bin, Ext, Int, Str, Value}; 1255 | 1256 | /// A special type for serializing and deserializing the `nil` object. 1257 | /// 1258 | /// In our data model `()` does not represent the `nil` object because `()` should be zero-byte but `nil` has a size. 1259 | /// When you want to serialize or deserialize `nil` use this type instead. 1260 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 1261 | pub struct Nil; 1262 | 1263 | impl Serialize for Nil { 1264 | fn serialize(&self, serializer: &mut Serializer) { 1265 | serializer.serialize_nil() 1266 | } 1267 | } 1268 | 1269 | impl Deserialize for Nil { 1270 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1271 | let token = deserializer.deserialize_token()?; 1272 | if token != Token::Nil { 1273 | return Err(ValidationError.into()); 1274 | } 1275 | Ok(Self) 1276 | } 1277 | } 1278 | 1279 | /// A special type used to deserialize any object and discard it. 1280 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 1281 | pub struct Any; 1282 | 1283 | impl Deserialize for Any { 1284 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1285 | deserializer.deserialize_any()?; 1286 | Ok(Any) 1287 | } 1288 | } 1289 | 1290 | /// A special type used to serialize and deserialize the empty map. 1291 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 1292 | pub struct Empty {} 1293 | 1294 | impl Serialize for Empty { 1295 | fn serialize(&self, serializer: &mut Serializer) { 1296 | serializer.serialize_map(0) 1297 | } 1298 | } 1299 | 1300 | impl Deserialize for Empty { 1301 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1302 | let token = deserializer.deserialize_token()?; 1303 | if token != Token::Map(0) { 1304 | return Err(ValidationError.into()); 1305 | } 1306 | Ok(Self {}) 1307 | } 1308 | } 1309 | } 1310 | 1311 | #[cfg(test)] 1312 | mod tests { 1313 | use super::*; 1314 | use msgpack_value::msgpack; 1315 | use proptest::prelude::*; 1316 | use proptest_derive::Arbitrary; 1317 | 1318 | macro_rules! roundtrip { 1319 | ($name:ident, $ty:ty) => { 1320 | #[cfg(test)] 1321 | mod $name { 1322 | use super::*; 1323 | proptest! { 1324 | #[test] 1325 | fn test(v: $ty) { 1326 | assert_eq!(v, deserialize::<$ty>(serialize(&v).as_slice()).unwrap()); 1327 | } 1328 | } 1329 | } 1330 | }; 1331 | } 1332 | 1333 | roundtrip!(roundtrip_bool, bool); 1334 | roundtrip!(roundtrip_i8, i8); 1335 | roundtrip!(roundtrip_i16, i16); 1336 | roundtrip!(roundtrip_i32, i32); 1337 | roundtrip!(roundtrip_i64, i64); 1338 | roundtrip!(roundtrip_u8, u8); 1339 | roundtrip!(roundtrip_u16, u16); 1340 | roundtrip!(roundtrip_u32, u32); 1341 | roundtrip!(roundtrip_u64, u64); 1342 | roundtrip!(roundtrip_f32, f32); 1343 | roundtrip!(roundtrip_f64, f64); 1344 | roundtrip!(roundtrip_str, String); 1345 | roundtrip!(roundtrip_blob, Vec); 1346 | roundtrip!(roundtrip_box, Box); 1347 | roundtrip!(roundtrip_rc, std::rc::Rc); 1348 | roundtrip!(roundtrip_arc, std::sync::Arc); 1349 | 1350 | roundtrip!(roundtrip_value, Value); 1351 | roundtrip!(roundtrip_int, Int); 1352 | 1353 | #[derive(Debug, PartialEq, Eq, Arbitrary)] 1354 | struct Human { 1355 | age: u32, 1356 | name: String, 1357 | } 1358 | 1359 | impl Serialize for Human { 1360 | fn serialize(&self, serializer: &mut Serializer) { 1361 | serializer.serialize_map(2); 1362 | serializer.serialize(0u32); 1363 | serializer.serialize(self.age); 1364 | serializer.serialize(1u32); 1365 | serializer.serialize(&self.name); 1366 | } 1367 | } 1368 | 1369 | impl Deserialize for Human { 1370 | fn deserialize(deserializer: &mut Deserializer) -> Result { 1371 | let len = match deserializer.deserialize_token()? { 1372 | Token::Map(len) => len, 1373 | _ => return Err(ValidationError.into()), 1374 | }; 1375 | 1376 | let mut age: Option = None; 1377 | let mut name: Option = None; 1378 | for _ in 0..len { 1379 | let tag: u32 = deserializer.deserialize()?; 1380 | match tag { 1381 | 0 => { 1382 | if age.is_some() { 1383 | return Err(InvalidInputError.into()); 1384 | } 1385 | age = Some(deserializer.deserialize()?); 1386 | } 1387 | 1 => { 1388 | if name.is_some() { 1389 | return Err(InvalidInputError.into()); 1390 | } 1391 | name = Some(deserializer.deserialize()?); 1392 | } 1393 | _ => { 1394 | deserializer.deserialize_any()?; 1395 | } 1396 | } 1397 | } 1398 | Ok(Self { 1399 | age: age.ok_or(ValidationError)?, 1400 | name: name.ok_or(ValidationError)?, 1401 | }) 1402 | } 1403 | } 1404 | 1405 | roundtrip!(roundtrip_human, Human); 1406 | 1407 | fn check_serialize_result(x: T, v: Value) { 1408 | let buf1 = serialize(&x); 1409 | let buf2 = serialize(v); 1410 | assert_eq!(buf1, buf2); 1411 | } 1412 | 1413 | #[test] 1414 | fn struct_vs_value() { 1415 | check_serialize_result( 1416 | Human { 1417 | age: 42, 1418 | name: "John".into(), 1419 | }, 1420 | msgpack!({ 1421 | 0: 42, 1422 | 1: "John", 1423 | }), 1424 | ); 1425 | } 1426 | 1427 | #[test] 1428 | fn box_vs_value() { 1429 | check_serialize_result(Box::new(42i32), msgpack!(42)); 1430 | } 1431 | 1432 | #[test] 1433 | fn rc_vs_value() { 1434 | check_serialize_result(std::rc::Rc::new(42i32), msgpack!(42)); 1435 | } 1436 | 1437 | #[test] 1438 | fn arc_vs_value() { 1439 | check_serialize_result(std::sync::Arc::new(42i32), msgpack!(42)); 1440 | } 1441 | 1442 | #[test] 1443 | fn serialize_into_keeps_buf() { 1444 | let mut buf = vec![0x12, 0x34, 0x56, 0x78]; 1445 | serialize_into(42, &mut buf); 1446 | assert_eq!(*buf, [0x12, 0x34, 0x56, 0x78, 42]); 1447 | } 1448 | } 1449 | -------------------------------------------------------------------------------- /tests/test.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 1811677003e19d62694116ad5e11457052df61f5d8a534baa6635ece896de85e # shrinks to v = Array([Map([(Ext(0, [97, 97, 11, 97, 32, 65, 97, 32]), Nil)])]) 8 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | use msgpack_value::{msgpack, Bin, Ext, Value}; 3 | use proptest::prelude::*; 4 | 5 | mod value { 6 | use super::*; 7 | 8 | pub fn serialize(x: &S) -> Value { 9 | let buf = crate::serialize(x); 10 | crate::deserialize(&buf).unwrap() 11 | } 12 | 13 | pub fn deserialize(value: Value) -> Result { 14 | let buf = crate::serialize(value); 15 | crate::deserialize::(&buf) 16 | } 17 | } 18 | 19 | #[test] 20 | fn failing() { 21 | let t = trybuild::TestCases::new(); 22 | t.compile_fail("tests/ui/*.rs"); 23 | } 24 | 25 | #[test] 26 | fn serialize_struct_tag() { 27 | #[derive(Serialize)] 28 | struct Human { 29 | #[tag = 0] 30 | age: u32, 31 | #[tag = 2] 32 | name: String, 33 | } 34 | 35 | let val = Human { 36 | age: 42, 37 | name: "John".into(), 38 | }; 39 | assert_eq!( 40 | value::serialize(&val), 41 | Value::Map(vec![ 42 | (Value::Int(0.into()), Value::Int(42.into())), 43 | (Value::Int(2.into()), Value::Str("John".to_owned().into())) 44 | ]) 45 | ); 46 | } 47 | 48 | #[test] 49 | fn deserialize_struct_tag() { 50 | #[derive(Deserialize, PartialEq, Eq, Debug)] 51 | struct Human { 52 | #[tag = 0] 53 | age: u32, 54 | #[tag = 2] 55 | name: String, 56 | } 57 | 58 | let val = Value::Map(vec![ 59 | (Value::Int(0.into()), Value::Int(42.into())), 60 | (Value::Int(2.into()), Value::Str("John".to_owned().into())), 61 | ]); 62 | 63 | assert_eq!( 64 | Human { 65 | age: 42, 66 | name: "John".into(), 67 | }, 68 | value::deserialize(val).unwrap() 69 | ); 70 | } 71 | 72 | #[test] 73 | fn struct_tag_roundtrip() { 74 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] 75 | struct Human { 76 | #[tag = 0] 77 | age: u32, 78 | #[tag = 2] 79 | name: String, 80 | } 81 | 82 | let val = Human { 83 | age: 42, 84 | name: "John".into(), 85 | }; 86 | 87 | assert_eq!(val, value::deserialize(value::serialize(&val)).unwrap()); 88 | 89 | let val = Value::Map(vec![ 90 | (Value::Int(0.into()), Value::Int(42.into())), 91 | (Value::Int(2.into()), Value::Str("John".to_owned().into())), 92 | ]); 93 | 94 | assert_eq!( 95 | val, 96 | value::serialize(&value::deserialize::(val.clone()).unwrap()) 97 | ); 98 | } 99 | 100 | #[test] 101 | fn error_duplicate_tags() { 102 | #[derive(Deserialize, PartialEq, Eq, Debug)] 103 | struct Human { 104 | #[tag = 0] 105 | age: u32, 106 | #[tag = 2] 107 | name: String, 108 | } 109 | 110 | let val = msgpack!({ 111 | 0: 42, 112 | 0: 43, 113 | 2: "John", 114 | }); 115 | 116 | assert_eq!( 117 | value::deserialize::(val).unwrap(), 118 | Human { 119 | age: 43, 120 | name: "John".to_owned() 121 | } 122 | ); 123 | 124 | let val = msgpack!({ 125 | 0: true, 126 | 0: 42, 127 | 2: "John", 128 | }); 129 | 130 | assert_eq!( 131 | value::deserialize::(val).unwrap(), 132 | Human { 133 | age: 42, 134 | name: "John".to_owned() 135 | } 136 | ); 137 | 138 | let val = msgpack!({ 139 | 0: 42, 140 | 0: true, 141 | 2: "John", 142 | }); 143 | 144 | assert!(matches!( 145 | value::deserialize::(val).unwrap_err(), 146 | DeserializeError::Validation(_) 147 | )); 148 | } 149 | 150 | #[test] 151 | fn serialize_struct_optional() { 152 | #[derive(Serialize)] 153 | struct Human { 154 | #[tag = 0] 155 | age: u32, 156 | #[tag = 2] 157 | #[optional] 158 | name: Option, 159 | } 160 | 161 | let val = Human { 162 | age: 42, 163 | name: Some("John".into()), 164 | }; 165 | assert_eq!( 166 | value::serialize(&val), 167 | Value::Map(vec![ 168 | (Value::Int(0.into()), Value::Int(42.into())), 169 | (Value::Int(2.into()), Value::Str("John".to_owned().into())) 170 | ]) 171 | ); 172 | 173 | let val = Human { 174 | age: 42, 175 | name: None, 176 | }; 177 | assert_eq!( 178 | value::serialize(&val), 179 | Value::Map(vec![(Value::Int(0.into()), Value::Int(42.into())),]) 180 | ); 181 | } 182 | 183 | #[test] 184 | fn deserialize_struct_optional() { 185 | #[derive(Deserialize, PartialEq, Eq, Debug)] 186 | struct Human { 187 | #[tag = 0] 188 | age: u32, 189 | #[tag = 2] 190 | #[optional] 191 | name: Option, 192 | } 193 | 194 | let val = Value::Map(vec![ 195 | (Value::Int(0.into()), Value::Int(42.into())), 196 | (Value::Int(2.into()), Value::Str("John".to_owned().into())), 197 | ]); 198 | assert_eq!( 199 | Human { 200 | age: 42, 201 | name: Some("John".into()), 202 | }, 203 | value::deserialize(val).unwrap() 204 | ); 205 | 206 | let val = Value::Map(vec![(Value::Int(0.into()), Value::Int(42.into()))]); 207 | assert_eq!( 208 | Human { 209 | age: 42, 210 | name: None, 211 | }, 212 | value::deserialize(val).unwrap() 213 | ); 214 | } 215 | 216 | #[test] 217 | fn serialize_unit_variants() { 218 | #[derive(Serialize)] 219 | enum Animal { 220 | #[tag = 2] 221 | Dog, 222 | } 223 | 224 | let val = Animal::Dog; 225 | assert_eq!(value::serialize(&val), Value::Int(2.into())); 226 | } 227 | 228 | #[test] 229 | fn deserialize_unit_variants() { 230 | #[derive(Deserialize, Debug, PartialEq, Eq)] 231 | enum Animal { 232 | #[tag = 2] 233 | Dog, 234 | } 235 | 236 | let val = Value::Int(2.into()); 237 | assert_eq!(Animal::Dog, value::deserialize(val).unwrap()); 238 | } 239 | 240 | #[test] 241 | fn serialize_newtype_struct() { 242 | #[derive(Serialize)] 243 | struct S(u32); 244 | 245 | let val = S(42); 246 | assert_eq!(value::serialize(&val), Value::Int(42.into())); 247 | } 248 | 249 | #[test] 250 | fn deserialize_newtype_struct() { 251 | #[derive(Deserialize, PartialEq, Debug)] 252 | struct S(u32); 253 | 254 | let val = Value::Int(42.into()); 255 | assert_eq!(S(42), value::deserialize(val).unwrap()); 256 | } 257 | 258 | #[test] 259 | fn serialize_empty_tuple_variants() { 260 | #[derive(Serialize)] 261 | enum Animal { 262 | #[tag = 2] 263 | Dog(), 264 | } 265 | 266 | let val = Animal::Dog(); 267 | assert_eq!(value::serialize(&val), Value::Int(2.into())); 268 | } 269 | 270 | #[test] 271 | fn deserialize_empty_tuple_variants() { 272 | #[derive(Deserialize, Debug, PartialEq, Eq)] 273 | enum Animal { 274 | #[tag = 2] 275 | Dog(), 276 | } 277 | 278 | let val = Value::Int(2.into()); 279 | assert_eq!(Animal::Dog(), value::deserialize(val).unwrap()); 280 | } 281 | 282 | #[test] 283 | fn serialize_tuple_variants() { 284 | #[derive(Serialize, Debug, PartialEq, Eq)] 285 | enum Animal { 286 | #[tag = 1] 287 | Cat(String), 288 | #[tag = 2] 289 | Dog(u32), 290 | } 291 | 292 | assert_eq!( 293 | value::serialize(&Animal::Cat("hello".to_owned())), 294 | Value::Array(vec![1.into(), "hello".to_owned().into()]) 295 | ); 296 | 297 | assert_eq!( 298 | value::serialize(&Animal::Dog(42u32)), 299 | Value::Array(vec![2.into(), 42u32.into()]) 300 | ); 301 | } 302 | 303 | #[test] 304 | fn deserialize_tuple_variants() { 305 | #[derive(Deserialize, Debug, PartialEq, Eq)] 306 | enum Animal { 307 | #[tag = 1] 308 | Cat(String), 309 | #[tag = 2] 310 | Dog(u32), 311 | #[tag = 3] 312 | Bird, 313 | } 314 | 315 | let val = Value::Int(3.into()); 316 | assert_eq!(Animal::Bird, value::deserialize(val).unwrap()); 317 | 318 | let val = Value::Int(1.into()); 319 | assert!(value::deserialize::(val).is_err()); 320 | 321 | let val = Value::Int(10.into()); 322 | assert!(value::deserialize::(val).is_err()); 323 | 324 | let val = Value::Array(vec![1.into(), 42u32.to_owned().into()]); 325 | assert!(value::deserialize::(val).is_err()); 326 | 327 | let val = Value::Array(vec![1.into(), "hello".to_owned().into()]); 328 | assert_eq!( 329 | Animal::Cat("hello".to_owned()), 330 | value::deserialize(val).unwrap() 331 | ); 332 | } 333 | 334 | #[test] 335 | fn serialize_untagged_enum() { 336 | #[derive(Serialize, Debug, PartialEq, Eq)] 337 | #[untagged] 338 | enum Animal { 339 | Cat(String), 340 | Dog(u32), 341 | } 342 | 343 | let val = Value::Int(3.into()); 344 | assert_eq!(value::serialize(&Animal::Dog(3)), val); 345 | 346 | let val = Value::Str("hello".to_owned().into()); 347 | assert_eq!(value::serialize(&Animal::Cat("hello".to_owned())), val); 348 | } 349 | 350 | #[test] 351 | fn deserialize_untagged_enum() { 352 | #[derive(Deserialize, Debug, PartialEq, Eq)] 353 | #[untagged] 354 | enum Animal { 355 | Cat(String), 356 | Dog(u32), 357 | } 358 | 359 | let val = Value::Int(3.into()); 360 | assert_eq!(Animal::Dog(3), value::deserialize(val).unwrap()); 361 | 362 | let val = Value::Str("hello".to_owned().into()); 363 | assert_eq!( 364 | Animal::Cat("hello".to_owned()), 365 | value::deserialize::(val).unwrap() 366 | ); 367 | 368 | let val = Value::Int((-10).into()); 369 | assert!(value::deserialize::(val).is_err()); 370 | } 371 | 372 | #[test] 373 | fn serialize_untagged_struct() { 374 | #[derive(Serialize, Debug, PartialEq, Eq)] 375 | #[untagged] 376 | struct Human { 377 | name: String, 378 | age: u32, 379 | } 380 | 381 | let val = Human { 382 | name: "John".to_string(), 383 | age: 42, 384 | }; 385 | assert_eq!(value::serialize(&val), msgpack!(["John", 42])); 386 | } 387 | 388 | #[test] 389 | fn deserialize_untagged_struct() { 390 | #[derive(Deserialize, Debug, PartialEq, Eq)] 391 | #[untagged] 392 | struct Human { 393 | name: String, 394 | age: u32, 395 | } 396 | 397 | let val = msgpack!(["John", 42]); 398 | assert_eq!( 399 | Human { 400 | name: "John".to_string(), 401 | age: 42, 402 | }, 403 | value::deserialize(val).unwrap() 404 | ); 405 | 406 | let val = msgpack!(["John", 42, nil]); 407 | assert!(value::deserialize::(val).is_err()); 408 | } 409 | 410 | fn arb_value() -> impl Strategy { 411 | let leaf = prop_oneof![ 412 | Just(Value::Nil), 413 | any::().prop_map(|v| v.into()), 414 | any::().prop_map(|v| v.into()), 415 | any::().prop_map(|v| v.into()), 416 | any::().prop_map(|v| v.into()), 417 | any::().prop_map(|v| v.into()), 418 | ".*".prop_map(|v| v.into()), 419 | ".*".prop_map(|v| Bin(v.into_bytes()).into()), 420 | any::().prop_flat_map(|tag| ".*".prop_map(move |v| Value::Ext(Ext { 421 | r#type: tag, 422 | data: v.into_bytes() 423 | }))), 424 | ]; 425 | leaf.prop_recursive( 426 | 4, // 4 levels deep 427 | 128, // Shoot for maximum size of 128 nodes 428 | 5, // We put up to 5 items per collection 429 | |inner| { 430 | prop_oneof![ 431 | // Take the inner strategy and make the two recursive cases. 432 | prop::collection::vec(inner.clone(), 0..=4).prop_map(|v| v.into()), 433 | prop::collection::vec((inner.clone(), inner), 0..=4).prop_map(|v| v.into()), 434 | ] 435 | }, 436 | ) 437 | } 438 | 439 | proptest! { 440 | #[test] 441 | fn roundtrip_binary(v in arb_value()) { 442 | let buf = msgpack_schema::serialize(&v); 443 | assert_eq!(v, msgpack_schema::deserialize(buf.as_slice()).unwrap()); 444 | } 445 | } 446 | 447 | #[test] 448 | fn serialize_struct_tag_schema() { 449 | #[derive(Serialize)] 450 | struct Human { 451 | #[schema(0)] 452 | age: u32, 453 | #[schema(2)] 454 | name: String, 455 | } 456 | 457 | let val = Human { 458 | age: 42, 459 | name: "John".into(), 460 | }; 461 | assert_eq!( 462 | value::serialize(&val), 463 | Value::Map(vec![ 464 | (Value::Int(0.into()), Value::Int(42.into())), 465 | (Value::Int(2.into()), Value::Str("John".to_owned().into())) 466 | ]) 467 | ); 468 | } 469 | 470 | #[test] 471 | fn serialize_struct_flatten() { 472 | #[derive(Serialize)] 473 | struct S1 { 474 | #[tag = 1] 475 | x: u32, 476 | } 477 | 478 | #[derive(Serialize)] 479 | struct S2 { 480 | #[tag = 2] 481 | x: u32, 482 | #[flatten] 483 | s1: S1, 484 | } 485 | 486 | let val = S2 { 487 | x: 42, 488 | s1: S1 { x: 43 }, 489 | }; 490 | assert_eq!( 491 | value::serialize(&val), 492 | Value::Map(vec![ 493 | (Value::Int(2.into()), Value::Int(42.into())), 494 | (Value::Int(1.into()), Value::Int(43.into())) 495 | ]) 496 | ); 497 | } 498 | 499 | #[test] 500 | fn deserialize_struct_flatten() { 501 | #[derive(Deserialize, PartialEq, Eq, Debug)] 502 | struct S1 { 503 | #[tag = 1] 504 | x: u32, 505 | } 506 | 507 | #[derive(Deserialize, PartialEq, Eq, Debug)] 508 | struct S2 { 509 | #[tag = 2] 510 | x: u32, 511 | #[flatten] 512 | s1: S1, 513 | } 514 | 515 | let val = S2 { 516 | x: 42, 517 | s1: S1 { x: 43 }, 518 | }; 519 | assert_eq!( 520 | val, 521 | value::deserialize(Value::Map(vec![ 522 | (Value::Int(2.into()), Value::Int(42.into())), 523 | (Value::Int(1.into()), Value::Int(43.into())) 524 | ])) 525 | .unwrap() 526 | ); 527 | } 528 | 529 | #[test] 530 | fn serialize_deserialize_empty() { 531 | #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] 532 | struct Empty {} 533 | 534 | let empty = Empty {}; 535 | 536 | assert_eq!(value::serialize(&empty), msgpack!({})); 537 | 538 | assert_eq!(empty, value::deserialize(msgpack!({})).unwrap()); 539 | } 540 | 541 | #[test] 542 | fn serialize_tuple_struct() { 543 | #[derive(Serialize, Debug, PartialEq, Eq)] 544 | struct S(u32, String); 545 | 546 | let s = S(42, "hello".to_owned()); 547 | assert_eq!(value::serialize(&s), msgpack!([42, "hello"])); 548 | } 549 | 550 | #[test] 551 | fn deserialize_tuple_struct() { 552 | #[derive(Deserialize, Debug, PartialEq, Eq)] 553 | struct S(u32, String); 554 | 555 | let s = S(42, "hello".to_owned()); 556 | assert_eq!(s, value::deserialize(msgpack!([42, "hello"])).unwrap()); 557 | } 558 | 559 | #[test] 560 | fn deserialize_tuple_struct_wrong_length() { 561 | #[derive(Deserialize, Debug)] 562 | struct S(u32, bool); 563 | 564 | let v = msgpack!([42]); 565 | 566 | assert!(matches!( 567 | value::deserialize::(v).unwrap_err(), 568 | msgpack_schema::DeserializeError::Validation(_) 569 | )); 570 | } 571 | 572 | #[test] 573 | fn regression_test_variable_capture() { 574 | #[derive(Deserialize, Serialize, Debug, PartialEq, Eq)] 575 | struct S { 576 | #[tag = 0] 577 | value: i32, 578 | #[tag = 1] 579 | serializer: i32, 580 | #[tag = 2] 581 | deserializer: i32, 582 | #[tag = 3] 583 | tag: i32, 584 | #[tag = 4] 585 | max_len: i32, 586 | #[tag = 5] 587 | len: i32, 588 | #[tag = 6] 589 | e: i32, 590 | #[tag = 7] 591 | count: i32, 592 | #[tag = 8] 593 | v: i32, 594 | #[tag = 9] 595 | ident: i32, 596 | #[tag = 10] 597 | r#type: i32, 598 | } 599 | let v = msgpack!({ 600 | 0:123, 601 | 1:456, 602 | 2:789, 603 | 3:123, 604 | 4:456, 605 | 5:789, 606 | 6:123, 607 | 7:456, 608 | 8:789, 609 | 9:123, 610 | 10:456, 611 | }); 612 | assert!(matches!( 613 | value::deserialize::(v).unwrap(), 614 | S { 615 | value: 123, 616 | serializer: 456, 617 | deserializer: 789, 618 | tag: 123, 619 | max_len: 456, 620 | len: 789, 621 | e: 123, 622 | count: 456, 623 | v: 789, 624 | ident: 123, 625 | r#type: 456, 626 | } 627 | )); 628 | } 629 | -------------------------------------------------------------------------------- /tests/ui/duplicate.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | struct S1 { 8 | #[optional] 9 | #[optional] 10 | #[tag = 1] 11 | x: Option, 12 | } 13 | 14 | #[derive(Serialize)] 15 | struct S2 { 16 | #[tag = 1] 17 | #[tag = 2] 18 | x: String, 19 | } 20 | 21 | #[derive(Serialize)] 22 | #[untagged] 23 | #[untagged] 24 | struct S3 {} 25 | 26 | #[derive(Serialize)] 27 | struct S4 { 28 | #[flatten] 29 | #[flatten] 30 | x: S2, 31 | } 32 | } 33 | 34 | mod deserialize { 35 | use super::*; 36 | 37 | #[derive(Deserialize)] 38 | struct S1 { 39 | #[optional] 40 | #[optional] 41 | #[tag = 1] 42 | x: Option, 43 | } 44 | 45 | #[derive(Deserialize)] 46 | struct S2 { 47 | #[tag = 1] 48 | #[tag = 2] 49 | x: String, 50 | } 51 | 52 | #[derive(Deserialize)] 53 | #[untagged] 54 | #[untagged] 55 | struct S3 {} 56 | 57 | #[derive(Deserialize)] 58 | struct S4 { 59 | #[flatten] 60 | #[flatten] 61 | x: S2, 62 | } 63 | } 64 | 65 | fn main() {} 66 | -------------------------------------------------------------------------------- /tests/ui/duplicate.stderr: -------------------------------------------------------------------------------- 1 | error: duplicate #[optional] attribute 2 | --> $DIR/duplicate.rs:9:9 3 | | 4 | 9 | #[optional] 5 | | ^^^^^^^^^^^ 6 | 7 | error: duplicate #[tag] attribute 8 | --> $DIR/duplicate.rs:17:9 9 | | 10 | 17 | #[tag = 2] 11 | | ^^^^^^^^^^ 12 | 13 | error: duplicate #[untagged] attribute 14 | --> $DIR/duplicate.rs:23:5 15 | | 16 | 23 | #[untagged] 17 | | ^^^^^^^^^^^ 18 | 19 | error: duplicate #[flatten] attribute 20 | --> $DIR/duplicate.rs:29:9 21 | | 22 | 29 | #[flatten] 23 | | ^^^^^^^^^^ 24 | 25 | error: duplicate #[optional] attribute 26 | --> $DIR/duplicate.rs:40:9 27 | | 28 | 40 | #[optional] 29 | | ^^^^^^^^^^^ 30 | 31 | error: duplicate #[tag] attribute 32 | --> $DIR/duplicate.rs:48:9 33 | | 34 | 48 | #[tag = 2] 35 | | ^^^^^^^^^^ 36 | 37 | error: duplicate #[untagged] attribute 38 | --> $DIR/duplicate.rs:54:5 39 | | 40 | 54 | #[untagged] 41 | | ^^^^^^^^^^^ 42 | 43 | error: duplicate #[flatten] attribute 44 | --> $DIR/duplicate.rs:60:9 45 | | 46 | 60 | #[flatten] 47 | | ^^^^^^^^^^ 48 | -------------------------------------------------------------------------------- /tests/ui/field.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | struct S1 { 8 | #[untagged] 9 | x: String, 10 | } 11 | 12 | #[derive(Serialize)] 13 | struct S2(#[tag = 1] String); 14 | 15 | #[derive(Serialize)] 16 | struct S3(#[optional] String); 17 | 18 | #[derive(Serialize)] 19 | struct S4(#[untagged] String); 20 | 21 | #[derive(Serialize)] 22 | struct S8(#[flatten] String); 23 | 24 | #[derive(Serialize)] 25 | #[untagged] 26 | struct S5 { 27 | #[tag = 0] 28 | x: String, 29 | } 30 | 31 | #[derive(Serialize)] 32 | #[untagged] 33 | struct S6 { 34 | #[untagged] 35 | x: String, 36 | } 37 | 38 | #[derive(Serialize)] 39 | #[untagged] 40 | struct S7 { 41 | #[optional] 42 | x: String, 43 | } 44 | 45 | #[derive(Serialize)] 46 | #[untagged] 47 | struct S9 { 48 | #[flatten] 49 | x: String, 50 | } 51 | 52 | #[derive(Serialize)] 53 | struct S10 { 54 | #[tag = 1] 55 | #[flatten] 56 | x: String, 57 | } 58 | 59 | #[derive(Serialize)] 60 | struct S11 { 61 | #[optional] 62 | #[flatten] 63 | x: String, 64 | } 65 | 66 | #[derive(Serialize)] 67 | struct S12(u32, #[tag = 1] String); 68 | 69 | #[derive(Serialize)] 70 | struct S13(u32, #[optional] String); 71 | 72 | #[derive(Serialize)] 73 | struct S14(u32, #[untagged] String); 74 | 75 | #[derive(Serialize)] 76 | struct S15(u32, #[flatten] String); 77 | } 78 | 79 | mod deserialize { 80 | use super::*; 81 | 82 | #[derive(Deserialize)] 83 | struct S1 { 84 | #[untagged] 85 | x: String, 86 | } 87 | 88 | #[derive(Deserialize)] 89 | struct S2(#[tag = 1] String); 90 | 91 | #[derive(Deserialize)] 92 | struct S3(#[optional] String); 93 | 94 | #[derive(Deserialize)] 95 | struct S4(#[untagged] String); 96 | 97 | #[derive(Deserialize)] 98 | struct S8(#[flatten] String); 99 | 100 | #[derive(Deserialize)] 101 | #[untagged] 102 | struct S5 { 103 | #[tag = 0] 104 | x: String, 105 | } 106 | 107 | #[derive(Deserialize)] 108 | #[untagged] 109 | struct S6 { 110 | #[untagged] 111 | x: String, 112 | } 113 | 114 | #[derive(Deserialize)] 115 | #[untagged] 116 | struct S7 { 117 | #[optional] 118 | x: String, 119 | } 120 | 121 | #[derive(Deserialize)] 122 | #[untagged] 123 | struct S9 { 124 | #[flatten] 125 | x: String, 126 | } 127 | 128 | #[derive(Deserialize)] 129 | struct S10 { 130 | #[tag = 1] 131 | #[flatten] 132 | x: String, 133 | } 134 | 135 | #[derive(Deserialize)] 136 | struct S11 { 137 | #[optional] 138 | #[flatten] 139 | x: String, 140 | } 141 | 142 | #[derive(Deserialize)] 143 | struct S12(u32, #[tag = 1] String); 144 | 145 | #[derive(Deserialize)] 146 | struct S13(u32, #[optional] String); 147 | 148 | #[derive(Deserialize)] 149 | struct S14(u32, #[untagged] String); 150 | 151 | #[derive(Deserialize)] 152 | struct S15(u32, #[flatten] String); 153 | } 154 | 155 | fn main() {} 156 | -------------------------------------------------------------------------------- /tests/ui/field.stderr: -------------------------------------------------------------------------------- 1 | error: #[untagged] at an invalid position 2 | --> $DIR/field.rs:8:9 3 | | 4 | 8 | #[untagged] 5 | | ^^^^^^^^^^^ 6 | 7 | error: #[tag] at an invalid position 8 | --> $DIR/field.rs:13:15 9 | | 10 | 13 | struct S2(#[tag = 1] String); 11 | | ^^^^^^^^^^ 12 | 13 | error: #[optional] at an invalid position 14 | --> $DIR/field.rs:16:15 15 | | 16 | 16 | struct S3(#[optional] String); 17 | | ^^^^^^^^^^^ 18 | 19 | error: #[untagged] at an invalid position 20 | --> $DIR/field.rs:19:15 21 | | 22 | 19 | struct S4(#[untagged] String); 23 | | ^^^^^^^^^^^ 24 | 25 | error: #[flatten] at an invalid position 26 | --> $DIR/field.rs:22:15 27 | | 28 | 22 | struct S8(#[flatten] String); 29 | | ^^^^^^^^^^ 30 | 31 | error: #[tag] at an invalid position 32 | --> $DIR/field.rs:27:9 33 | | 34 | 27 | #[tag = 0] 35 | | ^^^^^^^^^^ 36 | 37 | error: #[untagged] at an invalid position 38 | --> $DIR/field.rs:34:9 39 | | 40 | 34 | #[untagged] 41 | | ^^^^^^^^^^^ 42 | 43 | error: #[optional] at an invalid position 44 | --> $DIR/field.rs:41:9 45 | | 46 | 41 | #[optional] 47 | | ^^^^^^^^^^^ 48 | 49 | error: #[flatten] at an invalid position 50 | --> $DIR/field.rs:48:9 51 | | 52 | 48 | #[flatten] 53 | | ^^^^^^^^^^ 54 | 55 | error: #[tag] at an invalid position 56 | --> $DIR/field.rs:54:9 57 | | 58 | 54 | #[tag = 1] 59 | | ^^^^^^^^^^ 60 | 61 | error: #[optional] at an invalid position 62 | --> $DIR/field.rs:61:9 63 | | 64 | 61 | #[optional] 65 | | ^^^^^^^^^^^ 66 | 67 | error: #[tag] at an invalid position 68 | --> $DIR/field.rs:67:21 69 | | 70 | 67 | struct S12(u32, #[tag = 1] String); 71 | | ^^^^^^^^^^ 72 | 73 | error: #[optional] at an invalid position 74 | --> $DIR/field.rs:70:21 75 | | 76 | 70 | struct S13(u32, #[optional] String); 77 | | ^^^^^^^^^^^ 78 | 79 | error: #[untagged] at an invalid position 80 | --> $DIR/field.rs:73:21 81 | | 82 | 73 | struct S14(u32, #[untagged] String); 83 | | ^^^^^^^^^^^ 84 | 85 | error: #[flatten] at an invalid position 86 | --> $DIR/field.rs:76:21 87 | | 88 | 76 | struct S15(u32, #[flatten] String); 89 | | ^^^^^^^^^^ 90 | 91 | error: #[untagged] at an invalid position 92 | --> $DIR/field.rs:84:9 93 | | 94 | 84 | #[untagged] 95 | | ^^^^^^^^^^^ 96 | 97 | error: #[tag] at an invalid position 98 | --> $DIR/field.rs:89:15 99 | | 100 | 89 | struct S2(#[tag = 1] String); 101 | | ^^^^^^^^^^ 102 | 103 | error: #[optional] at an invalid position 104 | --> $DIR/field.rs:92:15 105 | | 106 | 92 | struct S3(#[optional] String); 107 | | ^^^^^^^^^^^ 108 | 109 | error: #[untagged] at an invalid position 110 | --> $DIR/field.rs:95:15 111 | | 112 | 95 | struct S4(#[untagged] String); 113 | | ^^^^^^^^^^^ 114 | 115 | error: #[flatten] at an invalid position 116 | --> $DIR/field.rs:98:15 117 | | 118 | 98 | struct S8(#[flatten] String); 119 | | ^^^^^^^^^^ 120 | 121 | error: #[tag] at an invalid position 122 | --> $DIR/field.rs:103:9 123 | | 124 | 103 | #[tag = 0] 125 | | ^^^^^^^^^^ 126 | 127 | error: #[untagged] at an invalid position 128 | --> $DIR/field.rs:110:9 129 | | 130 | 110 | #[untagged] 131 | | ^^^^^^^^^^^ 132 | 133 | error: #[optional] at an invalid position 134 | --> $DIR/field.rs:117:9 135 | | 136 | 117 | #[optional] 137 | | ^^^^^^^^^^^ 138 | 139 | error: #[flatten] at an invalid position 140 | --> $DIR/field.rs:124:9 141 | | 142 | 124 | #[flatten] 143 | | ^^^^^^^^^^ 144 | 145 | error: #[tag] at an invalid position 146 | --> $DIR/field.rs:130:9 147 | | 148 | 130 | #[tag = 1] 149 | | ^^^^^^^^^^ 150 | 151 | error: #[optional] at an invalid position 152 | --> $DIR/field.rs:137:9 153 | | 154 | 137 | #[optional] 155 | | ^^^^^^^^^^^ 156 | 157 | error: #[tag] at an invalid position 158 | --> $DIR/field.rs:143:21 159 | | 160 | 143 | struct S12(u32, #[tag = 1] String); 161 | | ^^^^^^^^^^ 162 | 163 | error: #[optional] at an invalid position 164 | --> $DIR/field.rs:146:21 165 | | 166 | 146 | struct S13(u32, #[optional] String); 167 | | ^^^^^^^^^^^ 168 | 169 | error: #[untagged] at an invalid position 170 | --> $DIR/field.rs:149:21 171 | | 172 | 149 | struct S14(u32, #[untagged] String); 173 | | ^^^^^^^^^^^ 174 | 175 | error: #[flatten] at an invalid position 176 | --> $DIR/field.rs:152:21 177 | | 178 | 152 | struct S15(u32, #[flatten] String); 179 | | ^^^^^^^^^^ 180 | -------------------------------------------------------------------------------- /tests/ui/item.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | #[tag = 1] 8 | struct S1 { 9 | x: String, 10 | } 11 | 12 | #[derive(Serialize)] 13 | #[optional] 14 | struct S2 { 15 | x: String, 16 | } 17 | 18 | #[derive(Serialize)] 19 | #[flatten] 20 | struct S5 { 21 | x: String, 22 | } 23 | 24 | #[derive(Serialize)] 25 | #[untagged] 26 | struct S3(String); 27 | 28 | #[derive(Serialize)] 29 | #[untagged] 30 | struct S4; 31 | 32 | #[derive(Serialize)] 33 | #[untagged] 34 | struct S6(u32, String); 35 | } 36 | 37 | mod deserialize { 38 | use super::*; 39 | 40 | #[derive(Deserialize)] 41 | #[tag = 1] 42 | struct S1 { 43 | x: String, 44 | } 45 | 46 | #[derive(Deserialize)] 47 | #[optional] 48 | struct S2 { 49 | x: String, 50 | } 51 | 52 | #[derive(Deserialize)] 53 | #[flatten] 54 | struct S5 { 55 | x: String, 56 | } 57 | 58 | #[derive(Deserialize)] 59 | #[untagged] 60 | struct S3(String); 61 | 62 | #[derive(Deserialize)] 63 | #[untagged] 64 | struct S4; 65 | 66 | #[derive(Deserialize)] 67 | #[untagged] 68 | struct S6(u32, String); 69 | } 70 | 71 | fn main() {} 72 | -------------------------------------------------------------------------------- /tests/ui/item.stderr: -------------------------------------------------------------------------------- 1 | error: #[tag] at an invalid position 2 | --> $DIR/item.rs:7:5 3 | | 4 | 7 | #[tag = 1] 5 | | ^^^^^^^^^^ 6 | 7 | error: #[optional] at an invalid position 8 | --> $DIR/item.rs:13:5 9 | | 10 | 13 | #[optional] 11 | | ^^^^^^^^^^^ 12 | 13 | error: #[flatten] at an invalid position 14 | --> $DIR/item.rs:19:5 15 | | 16 | 19 | #[flatten] 17 | | ^^^^^^^^^^ 18 | 19 | error: #[untagged] at an invalid position 20 | --> $DIR/item.rs:25:5 21 | | 22 | 25 | #[untagged] 23 | | ^^^^^^^^^^^ 24 | 25 | error: #[untagged] at an invalid position 26 | --> $DIR/item.rs:29:5 27 | | 28 | 29 | #[untagged] 29 | | ^^^^^^^^^^^ 30 | 31 | error: #[untagged] at an invalid position 32 | --> $DIR/item.rs:33:5 33 | | 34 | 33 | #[untagged] 35 | | ^^^^^^^^^^^ 36 | 37 | error: #[tag] at an invalid position 38 | --> $DIR/item.rs:41:5 39 | | 40 | 41 | #[tag = 1] 41 | | ^^^^^^^^^^ 42 | 43 | error: #[optional] at an invalid position 44 | --> $DIR/item.rs:47:5 45 | | 46 | 47 | #[optional] 47 | | ^^^^^^^^^^^ 48 | 49 | error: #[flatten] at an invalid position 50 | --> $DIR/item.rs:53:5 51 | | 52 | 53 | #[flatten] 53 | | ^^^^^^^^^^ 54 | 55 | error: #[untagged] at an invalid position 56 | --> $DIR/item.rs:59:5 57 | | 58 | 59 | #[untagged] 59 | | ^^^^^^^^^^^ 60 | 61 | error: #[untagged] at an invalid position 62 | --> $DIR/item.rs:63:5 63 | | 64 | 63 | #[untagged] 65 | | ^^^^^^^^^^^ 66 | 67 | error: #[untagged] at an invalid position 68 | --> $DIR/item.rs:67:5 69 | | 70 | 67 | #[untagged] 71 | | ^^^^^^^^^^^ 72 | -------------------------------------------------------------------------------- /tests/ui/tag.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | struct S1 { 8 | x: String, 9 | } 10 | 11 | #[derive(Serialize)] 12 | enum E1 { 13 | V, 14 | } 15 | } 16 | 17 | mod deserialize { 18 | use super::*; 19 | 20 | #[derive(Deserialize)] 21 | struct S1 { 22 | x: String, 23 | } 24 | 25 | #[derive(Deserialize)] 26 | enum E1 { 27 | V, 28 | } 29 | } 30 | 31 | fn main() {} 32 | -------------------------------------------------------------------------------- /tests/ui/tag.stderr: -------------------------------------------------------------------------------- 1 | error: no #[tag] given 2 | --> $DIR/tag.rs:8:9 3 | | 4 | 8 | x: String, 5 | | ^^^^^^^^^ 6 | 7 | error: no #[tag] given 8 | --> $DIR/tag.rs:13:9 9 | | 10 | 13 | V, 11 | | ^ 12 | 13 | error: no #[tag] given 14 | --> $DIR/tag.rs:22:9 15 | | 16 | 22 | x: String, 17 | | ^^^^^^^^^ 18 | 19 | error: no #[tag] given 20 | --> $DIR/tag.rs:27:9 21 | | 22 | 27 | V, 23 | | ^ 24 | -------------------------------------------------------------------------------- /tests/ui/tag_uniqueness.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | struct S1 { 8 | #[tag = 0] 9 | x: String, 10 | #[tag = 0] 11 | y: String, 12 | } 13 | 14 | #[derive(Serialize)] 15 | enum E1 { 16 | #[tag = 0] 17 | V1, 18 | #[tag = 0] 19 | V2, 20 | } 21 | } 22 | 23 | mod deserialize { 24 | use super::*; 25 | 26 | #[derive(Deserialize)] 27 | struct S1 { 28 | #[tag = 0] 29 | x: String, 30 | #[tag = 0] 31 | y: String, 32 | } 33 | 34 | #[derive(Deserialize)] 35 | enum E1 { 36 | #[tag = 0] 37 | V1, 38 | #[tag = 0] 39 | V2, 40 | } 41 | } 42 | 43 | fn main() {} 44 | -------------------------------------------------------------------------------- /tests/ui/tag_uniqueness.stderr: -------------------------------------------------------------------------------- 1 | error: tag values must not be duplicate 2 | --> $DIR/tag_uniqueness.rs:10:9 3 | | 4 | 10 | #[tag = 0] 5 | | ^^^^^^^^^^ 6 | 7 | error: tag values must not be duplicate 8 | --> $DIR/tag_uniqueness.rs:18:9 9 | | 10 | 18 | #[tag = 0] 11 | | ^^^^^^^^^^ 12 | 13 | error: tag values must not be duplicate 14 | --> $DIR/tag_uniqueness.rs:30:9 15 | | 16 | 30 | #[tag = 0] 17 | | ^^^^^^^^^^ 18 | 19 | error: tag values must not be duplicate 20 | --> $DIR/tag_uniqueness.rs:38:9 21 | | 22 | 38 | #[tag = 0] 23 | | ^^^^^^^^^^ 24 | -------------------------------------------------------------------------------- /tests/ui/unit.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | struct S1; 8 | 9 | #[derive(Serialize)] 10 | struct S3(); 11 | } 12 | 13 | mod deserialize { 14 | use super::*; 15 | 16 | #[derive(Deserialize)] 17 | struct S2; 18 | 19 | #[derive(Deserialize)] 20 | struct S4(); 21 | } 22 | 23 | fn main() {} 24 | -------------------------------------------------------------------------------- /tests/ui/unit.stderr: -------------------------------------------------------------------------------- 1 | error: unit structs as serialize are not supported 2 | --> $DIR/unit.rs:7:5 3 | | 4 | 7 | struct S1; 5 | | ^^^^^^^^^^ 6 | 7 | error: empty tuple structs as serialize are not supported 8 | --> $DIR/unit.rs:10:5 9 | | 10 | 10 | struct S3(); 11 | | ^^^^^^^^^^^^ 12 | 13 | error: unit structs as deserialize are not supported 14 | --> $DIR/unit.rs:17:5 15 | | 16 | 17 | struct S2; 17 | | ^^^^^^^^^^ 18 | 19 | error: empty tuple structs as deserialize are not supported 20 | --> $DIR/unit.rs:20:5 21 | | 22 | 20 | struct S4(); 23 | | ^^^^^^^^^^^^ 24 | -------------------------------------------------------------------------------- /tests/ui/variant.rs: -------------------------------------------------------------------------------- 1 | use msgpack_schema::*; 2 | 3 | mod serialize { 4 | use super::*; 5 | 6 | #[derive(Serialize)] 7 | enum E1 { 8 | #[optional] 9 | V1, 10 | } 11 | 12 | #[derive(Serialize)] 13 | enum E2 { 14 | #[untagged] 15 | V1, 16 | } 17 | 18 | #[derive(Serialize)] 19 | enum E12 { 20 | #[flatten] 21 | V1, 22 | } 23 | 24 | #[derive(Serialize)] 25 | enum E3 { 26 | #[tag = 1] 27 | V1(#[untagged] String), 28 | } 29 | 30 | #[derive(Serialize)] 31 | enum E4 { 32 | #[tag = 1] 33 | V1(#[optional] String), 34 | } 35 | 36 | #[derive(Serialize)] 37 | enum E5 { 38 | #[tag = 1] 39 | V1(#[tag = 1] String), 40 | } 41 | 42 | #[derive(Serialize)] 43 | enum E13 { 44 | #[tag = 1] 45 | V1(#[flatten] String), 46 | } 47 | 48 | #[derive(Serialize)] 49 | #[untagged] 50 | enum E6 { 51 | #[optional] 52 | V1, 53 | } 54 | 55 | #[derive(Serialize)] 56 | #[untagged] 57 | enum E7 { 58 | #[untagged] 59 | V1, 60 | } 61 | 62 | #[derive(Serialize)] 63 | #[untagged] 64 | enum E8 { 65 | #[tag = 1] 66 | V1, 67 | } 68 | 69 | #[derive(Serialize)] 70 | #[untagged] 71 | enum E14 { 72 | #[flatten] 73 | V1, 74 | } 75 | 76 | #[derive(Serialize)] 77 | #[untagged] 78 | enum E9 { 79 | V1(#[untagged] String), 80 | } 81 | 82 | #[derive(Serialize)] 83 | #[untagged] 84 | enum E10 { 85 | V1(#[optional] String), 86 | } 87 | 88 | #[derive(Serialize)] 89 | #[untagged] 90 | enum E11 { 91 | V1(#[tag = 1] String), 92 | } 93 | 94 | #[derive(Serialize)] 95 | #[untagged] 96 | enum E15 { 97 | V1(#[flatten] String), 98 | } 99 | } 100 | 101 | mod deserialize { 102 | use super::*; 103 | 104 | #[derive(Deserialize)] 105 | enum E1 { 106 | #[optional] 107 | V1, 108 | } 109 | 110 | #[derive(Deserialize)] 111 | enum E2 { 112 | #[untagged] 113 | V1, 114 | } 115 | 116 | #[derive(Deserialize)] 117 | enum E12 { 118 | #[flatten] 119 | V1, 120 | } 121 | 122 | #[derive(Deserialize)] 123 | enum E3 { 124 | #[tag = 1] 125 | V1(#[untagged] String), 126 | } 127 | 128 | #[derive(Deserialize)] 129 | enum E4 { 130 | #[tag = 1] 131 | V1(#[optional] String), 132 | } 133 | 134 | #[derive(Deserialize)] 135 | enum E5 { 136 | #[tag = 1] 137 | V1(#[tag = 1] String), 138 | } 139 | 140 | #[derive(Deserialize)] 141 | enum E13 { 142 | #[tag = 1] 143 | V1(#[flatten] String), 144 | } 145 | 146 | #[derive(Deserialize)] 147 | #[untagged] 148 | enum E6 { 149 | #[optional] 150 | V1, 151 | } 152 | 153 | #[derive(Deserialize)] 154 | #[untagged] 155 | enum E7 { 156 | #[untagged] 157 | V1, 158 | } 159 | 160 | #[derive(Deserialize)] 161 | #[untagged] 162 | enum E8 { 163 | #[tag = 1] 164 | V1, 165 | } 166 | 167 | #[derive(Deserialize)] 168 | #[untagged] 169 | enum E14 { 170 | #[flatten] 171 | V1, 172 | } 173 | 174 | #[derive(Deserialize)] 175 | #[untagged] 176 | enum E9 { 177 | V1(#[untagged] String), 178 | } 179 | 180 | #[derive(Deserialize)] 181 | #[untagged] 182 | enum E10 { 183 | V1(#[optional] String), 184 | } 185 | 186 | #[derive(Deserialize)] 187 | #[untagged] 188 | enum E11 { 189 | V1(#[tag = 1] String), 190 | } 191 | 192 | #[derive(Deserialize)] 193 | #[untagged] 194 | enum E15 { 195 | V1(#[flatten] String), 196 | } 197 | } 198 | 199 | fn main() {} 200 | -------------------------------------------------------------------------------- /tests/ui/variant.stderr: -------------------------------------------------------------------------------- 1 | error: #[optional] at an invalid position 2 | --> $DIR/variant.rs:8:9 3 | | 4 | 8 | #[optional] 5 | | ^^^^^^^^^^^ 6 | 7 | error: #[untagged] at an invalid position 8 | --> $DIR/variant.rs:14:9 9 | | 10 | 14 | #[untagged] 11 | | ^^^^^^^^^^^ 12 | 13 | error: #[flatten] at an invalid position 14 | --> $DIR/variant.rs:20:9 15 | | 16 | 20 | #[flatten] 17 | | ^^^^^^^^^^ 18 | 19 | error: #[untagged] at an invalid position 20 | --> $DIR/variant.rs:27:12 21 | | 22 | 27 | V1(#[untagged] String), 23 | | ^^^^^^^^^^^ 24 | 25 | error: #[optional] at an invalid position 26 | --> $DIR/variant.rs:33:12 27 | | 28 | 33 | V1(#[optional] String), 29 | | ^^^^^^^^^^^ 30 | 31 | error: #[tag] at an invalid position 32 | --> $DIR/variant.rs:39:12 33 | | 34 | 39 | V1(#[tag = 1] String), 35 | | ^^^^^^^^^^ 36 | 37 | error: #[flatten] at an invalid position 38 | --> $DIR/variant.rs:45:12 39 | | 40 | 45 | V1(#[flatten] String), 41 | | ^^^^^^^^^^ 42 | 43 | error: #[optional] at an invalid position 44 | --> $DIR/variant.rs:51:9 45 | | 46 | 51 | #[optional] 47 | | ^^^^^^^^^^^ 48 | 49 | error: #[untagged] at an invalid position 50 | --> $DIR/variant.rs:58:9 51 | | 52 | 58 | #[untagged] 53 | | ^^^^^^^^^^^ 54 | 55 | error: #[tag] at an invalid position 56 | --> $DIR/variant.rs:65:9 57 | | 58 | 65 | #[tag = 1] 59 | | ^^^^^^^^^^ 60 | 61 | error: #[flatten] at an invalid position 62 | --> $DIR/variant.rs:72:9 63 | | 64 | 72 | #[flatten] 65 | | ^^^^^^^^^^ 66 | 67 | error: #[untagged] at an invalid position 68 | --> $DIR/variant.rs:79:12 69 | | 70 | 79 | V1(#[untagged] String), 71 | | ^^^^^^^^^^^ 72 | 73 | error: #[optional] at an invalid position 74 | --> $DIR/variant.rs:85:12 75 | | 76 | 85 | V1(#[optional] String), 77 | | ^^^^^^^^^^^ 78 | 79 | error: #[tag] at an invalid position 80 | --> $DIR/variant.rs:91:12 81 | | 82 | 91 | V1(#[tag = 1] String), 83 | | ^^^^^^^^^^ 84 | 85 | error: #[flatten] at an invalid position 86 | --> $DIR/variant.rs:97:12 87 | | 88 | 97 | V1(#[flatten] String), 89 | | ^^^^^^^^^^ 90 | 91 | error: #[optional] at an invalid position 92 | --> $DIR/variant.rs:106:9 93 | | 94 | 106 | #[optional] 95 | | ^^^^^^^^^^^ 96 | 97 | error: #[untagged] at an invalid position 98 | --> $DIR/variant.rs:112:9 99 | | 100 | 112 | #[untagged] 101 | | ^^^^^^^^^^^ 102 | 103 | error: #[flatten] at an invalid position 104 | --> $DIR/variant.rs:118:9 105 | | 106 | 118 | #[flatten] 107 | | ^^^^^^^^^^ 108 | 109 | error: #[untagged] at an invalid position 110 | --> $DIR/variant.rs:125:12 111 | | 112 | 125 | V1(#[untagged] String), 113 | | ^^^^^^^^^^^ 114 | 115 | error: #[optional] at an invalid position 116 | --> $DIR/variant.rs:131:12 117 | | 118 | 131 | V1(#[optional] String), 119 | | ^^^^^^^^^^^ 120 | 121 | error: #[tag] at an invalid position 122 | --> $DIR/variant.rs:137:12 123 | | 124 | 137 | V1(#[tag = 1] String), 125 | | ^^^^^^^^^^ 126 | 127 | error: #[flatten] at an invalid position 128 | --> $DIR/variant.rs:143:12 129 | | 130 | 143 | V1(#[flatten] String), 131 | | ^^^^^^^^^^ 132 | 133 | error: #[optional] at an invalid position 134 | --> $DIR/variant.rs:149:9 135 | | 136 | 149 | #[optional] 137 | | ^^^^^^^^^^^ 138 | 139 | error: #[untagged] at an invalid position 140 | --> $DIR/variant.rs:156:9 141 | | 142 | 156 | #[untagged] 143 | | ^^^^^^^^^^^ 144 | 145 | error: #[tag] at an invalid position 146 | --> $DIR/variant.rs:163:9 147 | | 148 | 163 | #[tag = 1] 149 | | ^^^^^^^^^^ 150 | 151 | error: #[flatten] at an invalid position 152 | --> $DIR/variant.rs:170:9 153 | | 154 | 170 | #[flatten] 155 | | ^^^^^^^^^^ 156 | 157 | error: #[untagged] at an invalid position 158 | --> $DIR/variant.rs:177:12 159 | | 160 | 177 | V1(#[untagged] String), 161 | | ^^^^^^^^^^^ 162 | 163 | error: #[optional] at an invalid position 164 | --> $DIR/variant.rs:183:12 165 | | 166 | 183 | V1(#[optional] String), 167 | | ^^^^^^^^^^^ 168 | 169 | error: #[tag] at an invalid position 170 | --> $DIR/variant.rs:189:12 171 | | 172 | 189 | V1(#[tag = 1] String), 173 | | ^^^^^^^^^^ 174 | 175 | error: #[flatten] at an invalid position 176 | --> $DIR/variant.rs:195:12 177 | | 178 | 195 | V1(#[flatten] String), 179 | | ^^^^^^^^^^ 180 | --------------------------------------------------------------------------------