├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── lint.yml │ ├── ci.yml │ └── nightly.yml ├── .gitignore ├── src ├── lib.rs ├── container_attributes.rs ├── serde_introspection.rs └── field_attributes.rs ├── Cargo.toml ├── LICENSE └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: iddm 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.swo 4 | *.swp 5 | .vscode 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "22:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # serde-aux 2 | //! 3 | //! A serde auxiliary library. 4 | 5 | #![deny(missing_docs)] 6 | #![deny(warnings)] 7 | 8 | /// Contains helpers for the containers. 9 | pub mod container_attributes; 10 | /// Contains helpers for the fields. 11 | #[macro_use] 12 | pub mod field_attributes; 13 | /// Contains helpers for accessing structure metadata (e.g. struct field names when serialized) using serde. 14 | pub mod serde_introspection; 15 | 16 | /// Prelude module, contains the most needed helpers from this library. 17 | pub mod prelude { 18 | pub use crate::container_attributes::*; 19 | pub use crate::field_attributes::*; 20 | pub use crate::serde_introspection::*; 21 | } 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde-aux" 3 | version = "4.7.0" 4 | authors = ["Victor Polevoy "] 5 | description = "A serde crate's auxiliary library" 6 | readme = "README.md" 7 | license = "MIT" 8 | keywords = ["serde", "serialization", "deserialization"] 9 | edition = "2021" 10 | rust-version = "1.62" 11 | repository = "https://github.com/iddm/serde-aux" 12 | documentation = "https://docs.rs/serde-aux" 13 | 14 | [dependencies] 15 | serde = { version = "1", features = ["derive"] } 16 | serde-value = "0.7.0" 17 | serde_json = "1" 18 | 19 | [dependencies.chrono] 20 | optional = true 21 | version = "0.4" 22 | default-features = false 23 | features = ["alloc", "std", "clock"] 24 | 25 | [dev-dependencies] 26 | serde_qs = ">=0.10" 27 | 28 | [features] 29 | default = ["chrono"] 30 | 31 | [package.metadata.docs.rs] 32 | all-features = true 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Victor Polevoy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serde-aux 2 | [![Crates badge](https://img.shields.io/crates/v/serde_aux.svg)](https://crates.io/crates/serde-aux) 3 | [![CI](https://github.com/iddm/serde-aux/actions/workflows/ci.yml/badge.svg)](https://github.com/iddm/serde-aux/actions/workflows/ci.yml) 4 | [![Documentation](https://docs.rs/serde-aux/badge.svg)](https://docs.rs/serde-aux) 5 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) 6 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/iddm)](https://github.com/sponsors/iddm) 7 | 8 | An auxiliary library for the [`serde`](https://github.com/serde-rs/serde) crate. 9 | 10 | Contains some useful helper stuff. See [docs](https://docs.rs/serde-aux) for more info. 11 | 12 | The library is free for any contributions. The goal of this crate is to improve the user experience of the **serde** 13 | crate. 14 | 15 | ## Rust version 16 | The minimal rust version the library supports: 17 | - Up to version `3.0.0` (excluding) - rustc `1.36`. 18 | - Since `3.0.0` - rustc `1.56`. 19 | - Since `4.3.0` - rustc `1.57`. 20 | - Since `4.5.1` - rustc `1.61`. 21 | - Since `4.7.0` - rustc `1.62`. 22 | 23 | ## License 24 | This project is [licensed under the MIT license](https://github.com/iddm/serde-aux/blob/master/LICENSE). 25 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | # Copied from Twilight's Lint workflow. 2 | # 3 | # https://github.com/twilight-rs/twilight/blob/trunk/.github/workflows/lint.yml 4 | name: Lint 5 | 6 | on: [push, pull_request] 7 | 8 | jobs: 9 | clippy: 10 | name: Clippy 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout sources 15 | uses: actions/checkout@v4 16 | 17 | - name: Install stable toolchain 18 | id: toolchain 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | toolchain: stable 22 | components: clippy 23 | profile: minimal 24 | override: true 25 | 26 | - name: Setup cache 27 | uses: actions/cache@v4 28 | with: 29 | path: | 30 | ~/.cargo/registry 31 | ~/.cargo/git 32 | target 33 | key: ${{ runner.os }}-clippy-rustc-${{ steps.toolchain.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.lock') }} 34 | 35 | - name: Run clippy 36 | uses: actions-rs/clippy-check@v1 37 | with: 38 | token: ${{ secrets.GITHUB_TOKEN }} 39 | args: --workspace --tests 40 | 41 | rustfmt: 42 | name: Format 43 | runs-on: ubuntu-latest 44 | 45 | steps: 46 | - name: Checkout sources 47 | uses: actions/checkout@v4 48 | 49 | - name: Install stable toolchain 50 | uses: actions-rs/toolchain@v1 51 | with: 52 | toolchain: nightly 53 | components: rustfmt 54 | profile: minimal 55 | override: true 56 | 57 | - name: Run cargo fmt 58 | run: cargo fmt --all -- --check 59 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | minrust: 1.62.0 7 | 8 | jobs: 9 | test: 10 | name: Test 11 | runs-on: ${{ matrix.os || 'ubuntu-latest' }} 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | name: 17 | - stable 18 | - beta 19 | - nightly 20 | - macOS 21 | - Windows 22 | 23 | include: 24 | - name: beta 25 | toolchain: beta 26 | - name: nightly 27 | toolchain: nightly 28 | - name: macOS 29 | os: macOS-latest 30 | - name: Windows 31 | os: windows-latest 32 | 33 | steps: 34 | - name: Checkout sources 35 | uses: actions/checkout@v4 36 | 37 | - name: Install toolchain 38 | id: tc 39 | uses: actions-rs/toolchain@v1 40 | with: 41 | toolchain: ${{ matrix.toolchain || 'stable' }} 42 | profile: minimal 43 | override: true 44 | 45 | - name: Setup cache 46 | if: runner.os != 'macOS' 47 | uses: actions/cache@v4 48 | with: 49 | path: | 50 | ~/.cargo/registry 51 | ~/.cargo/git 52 | target 53 | key: ${{ runner.os }}-test-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 54 | 55 | - name: Build all features 56 | if: matrix.features == '' 57 | run: cargo build --all-features 58 | 59 | - name: Test all features 60 | if: matrix.features == '' 61 | run: cargo test --all-features 62 | 63 | - name: Build with no default features 64 | if: matrix.features == '' 65 | run: cargo build --no-default-features 66 | 67 | clippy: 68 | name: Run clippy 69 | runs-on: ubuntu-latest 70 | 71 | steps: 72 | - name: Checkout sources 73 | uses: actions/checkout@v4 74 | 75 | - name: Install toolchain 76 | id: tc 77 | uses: actions-rs/toolchain@v1 78 | with: 79 | toolchain: stable 80 | profile: minimal 81 | override: true 82 | 83 | - name: Setup cache 84 | uses: actions/cache@v4 85 | with: 86 | path: | 87 | ~/.cargo/registry 88 | ~/.cargo/git 89 | target 90 | key: ${{ runner.os }}-clippy-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 91 | 92 | - run: cargo clippy 93 | 94 | MSRV: 95 | runs-on: ubuntu-latest 96 | 97 | steps: 98 | - name: Checkout sources 99 | uses: actions/checkout@v4 100 | 101 | - name: Install toolchain (${{ env.minrust }}) 102 | id: tc 103 | uses: actions-rs/toolchain@v1 104 | with: 105 | toolchain: ${{ env.minrust }} 106 | profile: minimal 107 | override: true 108 | 109 | - name: Setup cache 110 | uses: actions/cache@v4 111 | with: 112 | path: | 113 | ~/.cargo/registry 114 | ~/.cargo/git 115 | target 116 | key: ${{ runner.os }}-msrv-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 117 | 118 | - run: cargo check --all-features 119 | 120 | doc: 121 | name: Build docs 122 | runs-on: ubuntu-latest 123 | 124 | steps: 125 | - name: Checkout sources 126 | uses: actions/checkout@v4 127 | 128 | - name: Install toolchain 129 | id: tc 130 | uses: actions-rs/toolchain@v1 131 | with: 132 | toolchain: nightly 133 | profile: minimal 134 | override: true 135 | 136 | - name: Setup cache 137 | uses: actions/cache@v4 138 | with: 139 | path: | 140 | ~/.cargo/registry 141 | ~/.cargo/git 142 | key: ${{ runner.os }}-docs-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 143 | 144 | - name: Build docs 145 | run: | 146 | cargo doc 147 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Nightly Build 2 | 3 | on: 4 | schedule: 5 | - cron: '0 2 * * *' 6 | 7 | env: 8 | minrust: 1.62.0 9 | 10 | jobs: 11 | test: 12 | name: Test 13 | runs-on: ${{ matrix.os || 'ubuntu-latest' }} 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | name: 19 | - stable 20 | - beta 21 | - nightly 22 | - macOS 23 | - Windows 24 | 25 | include: 26 | - name: beta 27 | toolchain: beta 28 | - name: nightly 29 | toolchain: nightly 30 | - name: macOS 31 | os: macOS-latest 32 | - name: Windows 33 | os: windows-latest 34 | 35 | steps: 36 | - name: Checkout sources 37 | uses: actions/checkout@v4 38 | 39 | - name: Install toolchain 40 | id: tc 41 | uses: actions-rs/toolchain@v1 42 | with: 43 | toolchain: ${{ matrix.toolchain || 'stable' }} 44 | profile: minimal 45 | override: true 46 | 47 | - name: Setup cache 48 | if: runner.os != 'macOS' 49 | uses: actions/cache@v4 50 | with: 51 | path: | 52 | ~/.cargo/registry 53 | ~/.cargo/git 54 | target 55 | key: ${{ runner.os }}-test-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 56 | 57 | - name: Build all features 58 | if: matrix.features == '' 59 | run: cargo build --all-features 60 | 61 | - name: Test all features 62 | if: matrix.features == '' 63 | run: cargo test --all-features 64 | 65 | rustfmt: 66 | name: Format 67 | runs-on: ubuntu-latest 68 | 69 | steps: 70 | - name: Checkout sources 71 | uses: actions/checkout@v4 72 | 73 | - name: Install stable toolchain 74 | uses: actions-rs/toolchain@v1 75 | with: 76 | toolchain: nightly 77 | components: rustfmt 78 | profile: minimal 79 | override: true 80 | 81 | - name: Run cargo fmt 82 | run: cargo fmt --all -- --check 83 | 84 | clippy: 85 | name: Clippy 86 | runs-on: ubuntu-latest 87 | 88 | steps: 89 | - name: Checkout sources 90 | uses: actions/checkout@v4 91 | 92 | - name: Install toolchain 93 | id: tc 94 | uses: actions-rs/toolchain@v1 95 | with: 96 | toolchain: stable 97 | profile: minimal 98 | override: true 99 | 100 | - name: Setup cache 101 | uses: actions/cache@v4 102 | with: 103 | path: | 104 | ~/.cargo/registry 105 | ~/.cargo/git 106 | target 107 | key: ${{ runner.os }}-clippy-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 108 | 109 | - run: cargo clippy 110 | 111 | MSRV: 112 | runs-on: ubuntu-latest 113 | 114 | steps: 115 | - name: Checkout sources 116 | uses: actions/checkout@v4 117 | 118 | - name: Install toolchain (${{ env.minrust }}) 119 | id: tc 120 | uses: actions-rs/toolchain@v1 121 | with: 122 | toolchain: ${{ env.minrust }} 123 | profile: minimal 124 | override: true 125 | 126 | - name: Setup cache 127 | uses: actions/cache@v4 128 | with: 129 | path: | 130 | ~/.cargo/registry 131 | ~/.cargo/git 132 | target 133 | key: ${{ runner.os }}-msrv-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 134 | 135 | - run: cargo check --all-features 136 | 137 | doc: 138 | name: Build docs 139 | runs-on: ubuntu-latest 140 | 141 | steps: 142 | - name: Checkout sources 143 | uses: actions/checkout@v4 144 | 145 | - name: Install toolchain 146 | id: tc 147 | uses: actions-rs/toolchain@v1 148 | with: 149 | toolchain: nightly 150 | profile: minimal 151 | override: true 152 | 153 | - name: Setup cache 154 | uses: actions/cache@v4 155 | with: 156 | path: | 157 | ~/.cargo/registry 158 | ~/.cargo/git 159 | key: ${{ runner.os }}-docs-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }} 160 | 161 | - name: Build docs 162 | run: | 163 | cargo doc 164 | -------------------------------------------------------------------------------- /src/container_attributes.rs: -------------------------------------------------------------------------------- 1 | use serde::de::{DeserializeOwned, Error}; 2 | use serde::{Deserialize, Deserializer}; 3 | 4 | /// Deserializes a struct without checking for the fields case sensititivity. 5 | /// 6 | /// # **Notes** 7 | /// 8 | /// - The following deserializer is incompatible with serde's one. If you wish 9 | /// to use `serde(rename)`, there is a high risk it won't work. Please see 10 | /// for further information. 11 | /// 12 | /// # Example: 13 | /// 14 | /// ```rust 15 | /// use serde_aux::prelude::*; 16 | /// 17 | /// #[derive(serde::Deserialize, Debug)] 18 | /// struct AnotherStruct { 19 | /// aaa: String, 20 | /// } 21 | /// #[derive(serde::Deserialize, Debug)] 22 | /// struct MyStruct { 23 | /// #[serde(deserialize_with = "deserialize_struct_case_insensitive")] 24 | /// another_struct: AnotherStruct, 25 | /// } 26 | /// 27 | /// let s = r#"{ "another_struct": { "AaA": "Test example" } }"#; 28 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 29 | /// assert_eq!(a.another_struct.aaa, "Test example"); 30 | /// ``` 31 | pub fn deserialize_struct_case_insensitive<'de, T, D>(deserializer: D) -> Result 32 | where 33 | T: DeserializeOwned, 34 | D: Deserializer<'de>, 35 | { 36 | use serde_json::Value; 37 | 38 | use std::collections::BTreeMap as Map; 39 | 40 | let map = Map::::deserialize(deserializer)?; 41 | let lower = map 42 | .into_iter() 43 | .map(|(k, v)| (k.to_lowercase(), v)) 44 | .collect(); 45 | T::deserialize(Value::Object(lower)).map_err(Error::custom) 46 | } 47 | 48 | /// This contains both serialization and ser/deserialization of a enum into and from numbers. 49 | /// The [reference implementation](https://serde.rs/enum-number.html) does not work if your 50 | /// enum has negative values. This `enum_number` handles this also. 51 | /// 52 | /// # Example 53 | /// 54 | /// ```rust 55 | /// serde_aux::enum_number_declare!(pub TestEnum { 56 | /// Up = 1, 57 | /// None = 0, 58 | /// Down = -1, 59 | /// }); 60 | /// 61 | /// let s = r#"1"#; 62 | /// let a: TestEnum = serde_json::from_str(s).unwrap(); 63 | /// assert_eq!(a, TestEnum::Up); 64 | /// 65 | /// let s = r#"0"#; 66 | /// let a: TestEnum = serde_json::from_str(s).unwrap(); 67 | /// assert_eq!(a, TestEnum::None); 68 | /// 69 | /// let s = r#"-1"#; 70 | /// let a: TestEnum = serde_json::from_str(s).unwrap(); 71 | /// assert_eq!(a, TestEnum::Down); 72 | /// 73 | /// let s = r#"5"#; 74 | /// assert!(serde_json::from_str::(s).is_err()); 75 | /// ``` 76 | #[macro_export] 77 | macro_rules! enum_number_declare { 78 | ($visibility:vis $name:ident { $($variant:ident = $value:expr, )* }) => { 79 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] 80 | $visibility enum $name { 81 | $($variant = $value,)* 82 | } 83 | 84 | impl<'de> serde::Deserialize<'de> for $name { 85 | fn deserialize(deserializer: D) -> Result 86 | where D: serde::Deserializer<'de> 87 | { 88 | use std::fmt; 89 | struct Visitor; 90 | 91 | impl<'de> serde::de::Visitor<'de> for Visitor { 92 | type Value = $name; 93 | 94 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 95 | formatter.write_str("integer") 96 | } 97 | 98 | fn visit_i64(self, value: i64) -> Result<$name, E> 99 | where E: serde::de::Error 100 | { 101 | // Rust does not come with a simple way of converting a 102 | // number to an enum, so use a big `match`. 103 | match value { 104 | $( $value => Ok($name::$variant), )* 105 | _ => Err(E::custom( 106 | format!("unknown {} value: {}", 107 | stringify!($name), value))), 108 | } 109 | } 110 | 111 | fn visit_u64(self, value: u64) -> Result<$name, E> 112 | where E: serde::de::Error 113 | { 114 | self.visit_i64(value as i64) 115 | } 116 | } 117 | 118 | // Deserialize the enum from a i64. 119 | deserializer.deserialize_i64(Visitor) 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/serde_introspection.rs: -------------------------------------------------------------------------------- 1 | use serde::de::{self, Deserialize, Deserializer, Visitor}; 2 | 3 | /// Gets the serialization names for structs and enums. 4 | /// 5 | /// # Example 6 | /// 7 | /// ```rust 8 | /// use serde_aux::prelude::*; 9 | /// 10 | /// #[derive(serde::Deserialize, Debug)] 11 | /// struct AnotherStruct { 12 | /// #[serde(rename = "a3")] 13 | /// aaa: Option, 14 | /// #[serde(rename = "b3")] 15 | /// bbb: i128, 16 | /// #[serde(rename = "c3")] 17 | /// ccc: u128, 18 | /// } 19 | /// let fields = serde_introspect::(); 20 | /// assert_eq!(fields[0], "a3"); 21 | /// assert_eq!(fields[1], "b3"); 22 | /// assert_eq!(fields[2], "c3"); 23 | /// 24 | /// #[derive(serde::Deserialize, Debug)] 25 | /// enum SomeEnum { 26 | /// #[serde(rename = "a")] 27 | /// EnumA, 28 | /// #[serde(rename = "b")] 29 | /// EnumB 30 | /// } 31 | /// let variants = serde_introspect::(); 32 | /// assert_eq!(variants[0], "a"); 33 | /// assert_eq!(variants[1], "b"); 34 | /// ``` 35 | pub fn serde_introspect<'de, T>() -> &'static [&'static str] 36 | where 37 | T: Deserialize<'de>, 38 | { 39 | struct StructFieldsDeserializer<'a> { 40 | fields: &'a mut Option<&'static [&'static str]>, 41 | } 42 | 43 | impl<'de> Deserializer<'de> for StructFieldsDeserializer<'_> { 44 | type Error = serde::de::value::Error; 45 | 46 | fn deserialize_any(self, _visitor: V) -> Result 47 | where 48 | V: Visitor<'de>, 49 | { 50 | Err(de::Error::custom("I'm just here for the fields")) 51 | } 52 | 53 | fn deserialize_struct( 54 | self, 55 | _name: &'static str, 56 | fields: &'static [&'static str], 57 | _visitor: V, 58 | ) -> Result 59 | where 60 | V: Visitor<'de>, 61 | { 62 | *self.fields = Some(fields); // get the names of the deserialized fields 63 | Err(de::Error::custom("I'm just here for the fields")) 64 | } 65 | 66 | serde::forward_to_deserialize_any! { 67 | bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes 68 | byte_buf option unit unit_struct newtype_struct seq tuple 69 | tuple_struct map enum identifier ignored_any 70 | } 71 | } 72 | 73 | struct EnumVariantsDeserializer<'a> { 74 | variants: &'a mut Option<&'static [&'static str]>, 75 | } 76 | 77 | impl<'de> Deserializer<'de> for EnumVariantsDeserializer<'_> { 78 | type Error = serde::de::value::Error; 79 | 80 | fn deserialize_any(self, _visitor: V) -> Result 81 | where 82 | V: Visitor<'de>, 83 | { 84 | Err(de::Error::custom("I'm just here for the fields")) 85 | } 86 | 87 | fn deserialize_enum( 88 | self, 89 | _name: &'static str, 90 | variants: &'static [&'static str], 91 | _visitor: V, 92 | ) -> Result 93 | where 94 | V: Visitor<'de>, 95 | { 96 | *self.variants = Some(variants); 97 | Err(de::Error::custom("I'm just here for the fields")) 98 | } 99 | 100 | serde::forward_to_deserialize_any! { 101 | bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes 102 | byte_buf option unit unit_struct newtype_struct seq tuple 103 | tuple_struct map struct identifier ignored_any 104 | } 105 | } 106 | 107 | let mut serialized_names = None; 108 | let _ = T::deserialize(EnumVariantsDeserializer { 109 | variants: &mut serialized_names, 110 | }); 111 | let _ = T::deserialize(StructFieldsDeserializer { 112 | fields: &mut serialized_names, 113 | }); 114 | serialized_names.unwrap_or_default() 115 | } 116 | 117 | /// Get the default record for a struct implementing the `serde::Deserialize` 118 | /// trait. 119 | /// 120 | /// This helper function is useful in particular when the `#[serde(default = 121 | /// "path")]` field attribute is used to customize the default record 122 | /// definition, as it avoids the need to implement the `Default` trait manually 123 | /// for the defined struct, paying attention to keep it aligned with Serde's 124 | /// attributes configuration. 125 | /// 126 | /// # Example 127 | /// 128 | /// ```rust 129 | /// use serde_aux::prelude::*; 130 | /// 131 | /// #[derive(serde::Deserialize, PartialEq, Debug)] 132 | /// struct Record { 133 | /// #[serde(default = "default_string")] 134 | /// label: String, 135 | /// #[serde(default = "default_f64")] 136 | /// value1: f64, 137 | /// #[serde(default)] 138 | /// value2: f64, 139 | /// #[serde(skip)] 140 | /// foo: bool, 141 | /// } 142 | /// 143 | /// fn default_string() -> String { 144 | /// String::from("default") 145 | /// } 146 | /// 147 | /// fn default_f64() -> f64 { 148 | /// 1.0 149 | /// } 150 | /// 151 | /// let empty_record = get_default_serde_record::().unwrap(); 152 | /// assert_eq!( 153 | /// empty_record, 154 | /// Record { 155 | /// label: String::from("default"), 156 | /// value1: 1.0, 157 | /// value2: 0.0, 158 | /// foo: false 159 | /// } 160 | /// ); 161 | /// ``` 162 | pub fn get_default_serde_record<'de, T>() -> Result 163 | where 164 | T: Deserialize<'de>, 165 | { 166 | let empty_data = std::iter::empty::<((), ())>(); 167 | let empty_deserializer = 168 | serde::de::value::MapDeserializer::<_, serde::de::value::Error>::new(empty_data); 169 | T::deserialize(empty_deserializer) 170 | } 171 | 172 | #[cfg(test)] 173 | mod tests { 174 | #![allow(dead_code)] 175 | 176 | use crate::prelude::{get_default_serde_record, serde_introspect}; 177 | 178 | #[test] 179 | fn serde_introspect_given_struct_introspect_serialization_names() { 180 | #[derive(serde::Deserialize, Debug)] 181 | enum SomeEnum { 182 | #[serde(rename = "a")] 183 | EnumA, 184 | #[serde(rename = "b")] 185 | EnumB, 186 | } 187 | #[derive(serde::Deserialize, Debug)] 188 | struct AnotherStruct { 189 | #[serde(rename = "a3")] 190 | aaa: Option, 191 | #[serde(rename = "b3")] 192 | bbb: i128, 193 | #[serde(rename = "c3")] 194 | ccc: u128, 195 | #[serde(rename = "d3")] 196 | ddd: SomeEnum, 197 | } 198 | let names = serde_introspect::(); 199 | assert_eq!(names[0], "a3"); 200 | assert_eq!(names[1], "b3"); 201 | assert_eq!(names[2], "c3"); 202 | assert_eq!(names[3], "d3"); 203 | } 204 | 205 | #[test] 206 | fn serde_introspect_enum_struct_introspect_serialization_names() { 207 | #[derive(serde::Deserialize, Debug)] 208 | enum SomeEnum { 209 | #[serde(rename = "a")] 210 | EnumA, 211 | #[serde(rename = "b")] 212 | EnumB, 213 | } 214 | 215 | let names = serde_introspect::(); 216 | assert_eq!(names[0], "a"); 217 | assert_eq!(names[1], "b"); 218 | } 219 | 220 | #[test] 221 | fn get_default_serde_record_from_struct() { 222 | #[derive(serde::Deserialize, PartialEq, Debug)] 223 | struct Record { 224 | #[serde(default = "default_string")] 225 | label: String, 226 | #[serde(default = "default_f64")] 227 | value1: f64, 228 | #[serde(default)] 229 | value2: f64, 230 | #[serde(skip)] 231 | foo: bool, 232 | } 233 | 234 | fn default_string() -> String { 235 | String::from("default") 236 | } 237 | 238 | fn default_f64() -> f64 { 239 | 1.0 240 | } 241 | 242 | let empty_record = get_default_serde_record::().unwrap(); 243 | assert_eq!( 244 | empty_record, 245 | Record { 246 | label: String::from("default"), 247 | value1: 1.0, 248 | value2: 0.0, 249 | foo: false 250 | } 251 | ); 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/field_attributes.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | use std::str::FromStr; 3 | 4 | #[cfg(feature = "chrono")] 5 | use serde::de::Error; 6 | use serde::{Deserialize, Deserializer}; 7 | 8 | /// Allows a `bool` field to be defaulted to `true`, rather than the normal 9 | /// default of `false`. Useful for fields where the default value should be `true`. 10 | /// 11 | /// Example: 12 | /// 13 | /// ```rust 14 | /// use serde_aux::prelude::*; 15 | /// 16 | /// #[derive(serde::Deserialize, Debug)] 17 | /// struct MyStruct { 18 | /// #[serde(default)] 19 | /// default_false: bool, 20 | /// #[serde(default = "bool_true")] 21 | /// default_true: bool, 22 | /// } 23 | /// 24 | /// let s = r#" { } "#; 25 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 26 | /// assert!(!a.default_false); 27 | /// assert!(a.default_true); 28 | /// ``` 29 | #[inline] 30 | pub fn bool_true() -> bool { 31 | true 32 | } 33 | 34 | /// Allows compact setting `u16` field default value. 35 | /// 36 | /// # Example 37 | /// ```rust 38 | /// use serde_aux::prelude::*; 39 | /// 40 | /// #[derive(serde::Deserialize, Debug)] 41 | /// struct MyStruct { 42 | /// #[serde(default = "default_u16::<30>")] 43 | /// default_30: u16, 44 | /// #[serde(default)] 45 | /// default_zero: u16, 46 | /// } 47 | /// 48 | /// let s = r#"{}"#; 49 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 50 | /// assert_eq!(a.default_30, 30); 51 | /// assert_eq!(a.default_zero, 0); 52 | /// ``` 53 | #[inline] 54 | pub const fn default_u16() -> u16 { 55 | V 56 | } 57 | 58 | /// Allows compact setting `u32` field default value. 59 | /// 60 | /// # Example 61 | /// ```rust 62 | /// use serde_aux::prelude::*; 63 | /// 64 | /// #[derive(serde::Deserialize, Debug)] 65 | /// struct MyStruct { 66 | /// #[serde(default = "default_u32::<30>")] 67 | /// default_30: u32, 68 | /// #[serde(default)] 69 | /// default_zero: u32, 70 | /// } 71 | /// 72 | /// let s = r#"{}"#; 73 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 74 | /// assert_eq!(a.default_30, 30); 75 | /// assert_eq!(a.default_zero, 0); 76 | /// ``` 77 | #[inline] 78 | pub const fn default_u32() -> u32 { 79 | V 80 | } 81 | 82 | /// Allows compact setting `u64` field default value. 83 | /// 84 | /// # Example 85 | /// ```rust 86 | /// use serde_aux::prelude::*; 87 | /// 88 | /// #[derive(serde::Deserialize, Debug)] 89 | /// struct MyStruct { 90 | /// #[serde(default = "default_u64::<30>")] 91 | /// default_30: u64, 92 | /// #[serde(default)] 93 | /// default_zero: u64, 94 | /// } 95 | /// 96 | /// let s = r#"{}"#; 97 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 98 | /// assert_eq!(a.default_30, 30); 99 | /// assert_eq!(a.default_zero, 0); 100 | /// ``` 101 | #[inline] 102 | pub const fn default_u64() -> u64 { 103 | V 104 | } 105 | 106 | /// Allows compact setting `i16` field default value. 107 | /// 108 | /// # Example 109 | /// ```rust 110 | /// use serde_aux::prelude::*; 111 | /// 112 | /// #[derive(serde::Deserialize, Debug)] 113 | /// struct MyStruct { 114 | /// #[serde(default = "default_i16::<-30>")] 115 | /// default_30: i16, 116 | /// #[serde(default)] 117 | /// default_zero: i16, 118 | /// } 119 | /// 120 | /// let s = r#"{}"#; 121 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 122 | /// assert_eq!(a.default_30, -30); 123 | /// assert_eq!(a.default_zero, 0); 124 | /// ``` 125 | #[inline] 126 | pub const fn default_i16() -> i16 { 127 | V 128 | } 129 | 130 | /// Allows compact setting `i32` field default value. 131 | /// 132 | /// # Example 133 | /// ```rust 134 | /// use serde_aux::prelude::*; 135 | /// 136 | /// #[derive(serde::Deserialize, Debug)] 137 | /// struct MyStruct { 138 | /// #[serde(default = "default_i32::<-30>")] 139 | /// default_30: i32, 140 | /// #[serde(default)] 141 | /// default_zero: i32, 142 | /// } 143 | /// 144 | /// let s = r#"{}"#; 145 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 146 | /// assert_eq!(a.default_30, -30); 147 | /// assert_eq!(a.default_zero, 0); 148 | /// ``` 149 | #[inline] 150 | pub const fn default_i32() -> i32 { 151 | V 152 | } 153 | 154 | /// Allows compact setting `i64` field default value. 155 | /// 156 | /// # Example 157 | /// ```rust 158 | /// use serde_aux::prelude::*; 159 | /// 160 | /// #[derive(serde::Deserialize, Debug)] 161 | /// struct MyStruct { 162 | /// #[serde(default = "default_i64::<-30>")] 163 | /// default_30: i64, 164 | /// #[serde(default)] 165 | /// default_zero: i64, 166 | /// } 167 | /// 168 | /// let s = r#"{}"#; 169 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 170 | /// assert_eq!(a.default_30, -30); 171 | /// assert_eq!(a.default_zero, 0); 172 | /// ``` 173 | #[inline] 174 | pub const fn default_i64() -> i64 { 175 | V 176 | } 177 | 178 | /// Deserializes a `chrono::DateTime` from a milliseconds time stamp. Useful when the data is coming from a number 179 | /// which is not a seconds time stamp but milliseconds one. It also handles the string to number conversion if the 180 | /// data was passed as a string with number inside like **"1519927261900"**. 181 | /// 182 | /// # Example: 183 | /// 184 | /// ```rust 185 | /// use chrono::prelude::*; 186 | /// use serde_aux::prelude::*; 187 | /// 188 | /// #[derive(serde::Deserialize, Debug)] 189 | /// struct MyStruct { 190 | /// #[serde(deserialize_with = "deserialize_datetime_utc_from_milliseconds")] 191 | /// time: DateTime, 192 | /// } 193 | /// 194 | /// let s = r#" { "time": "1519927261900" } "#; 195 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 196 | /// assert_eq!(a.time.timestamp(), 1519927261); 197 | /// assert_eq!(a.time.timestamp_subsec_millis(), 900); 198 | /// ``` 199 | #[cfg(feature = "chrono")] 200 | pub fn deserialize_datetime_utc_from_milliseconds<'de, D>( 201 | deserializer: D, 202 | ) -> Result, D::Error> 203 | where 204 | D: Deserializer<'de>, 205 | { 206 | use chrono::prelude::*; 207 | 208 | let millis = deserialize_number_from_string::(deserializer)?; 209 | DateTime::::from_timestamp_millis(millis) 210 | .ok_or_else(|| D::Error::custom("Couldn't parse the timestamp")) 211 | } 212 | 213 | /// Deserializes a `chrono::DateTime` from a seconds time stamp. 214 | /// It also handles the string to number conversion if the 215 | /// data was passed as a string with number inside like **"1519927261"**. 216 | /// 217 | /// # Example: 218 | /// 219 | /// ```rust 220 | /// use chrono::prelude::*; 221 | /// use serde_aux::prelude::*; 222 | /// 223 | /// #[derive(serde::Deserialize, Debug)] 224 | /// struct MyStruct { 225 | /// #[serde(deserialize_with = "deserialize_datetime_utc_from_seconds")] 226 | /// time: DateTime, 227 | /// } 228 | /// 229 | /// let s = r#" { "time": "1519927261" } "#; 230 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 231 | /// assert_eq!(a.time.timestamp(), 1519927261); 232 | /// assert_eq!(a.time.timestamp_subsec_millis(), 0); 233 | /// ``` 234 | #[cfg(feature = "chrono")] 235 | pub fn deserialize_datetime_utc_from_seconds<'de, D>( 236 | deserializer: D, 237 | ) -> Result, D::Error> 238 | where 239 | D: Deserializer<'de>, 240 | { 241 | use chrono::prelude::*; 242 | 243 | let seconds = deserialize_number_from_string::(deserializer)?; 244 | DateTime::::from_timestamp(seconds, 0) 245 | .ok_or_else(|| D::Error::custom("Couldn't parse the timestamp")) 246 | } 247 | 248 | /// Deserializes a number from string or a number. 249 | /// 250 | /// # Example: 251 | /// 252 | /// ```rust 253 | /// use serde_aux::prelude::*; 254 | /// 255 | /// #[derive(serde::Deserialize, Debug)] 256 | /// struct MyStruct { 257 | /// #[serde(deserialize_with = "deserialize_number_from_string")] 258 | /// number_from_string: u64, 259 | /// } 260 | /// 261 | /// let s = r#" { "number_from_string": "123" } "#; 262 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 263 | /// assert_eq!(a.number_from_string, 123); 264 | /// 265 | /// let s = r#" { "number_from_string": 444 } "#; 266 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 267 | /// assert_eq!(a.number_from_string, 444); 268 | /// ``` 269 | /// 270 | /// For making it work with strong types you must implement `FromStr` trait. It is quite simple. 271 | /// 272 | /// # Example 273 | /// 274 | /// ```rust 275 | /// use std::str::FromStr; 276 | /// use std::num::{ParseIntError, ParseFloatError}; 277 | /// 278 | /// use serde_aux::prelude::*; 279 | /// 280 | /// #[derive(serde::Deserialize, Debug, PartialEq)] 281 | /// struct IntId(u64); 282 | /// 283 | /// impl FromStr for IntId { 284 | /// type Err = ParseIntError; 285 | /// 286 | /// fn from_str(s: &str) -> Result { 287 | /// Ok(IntId(u64::from_str(s)?)) 288 | /// } 289 | /// } 290 | /// 291 | /// #[derive(serde::Deserialize, Debug)] 292 | /// struct MyStruct { 293 | /// #[serde(deserialize_with = "deserialize_number_from_string")] 294 | /// int_id: IntId, 295 | /// } 296 | /// 297 | /// let s = r#"{ "int_id": "123" }"#; 298 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 299 | /// assert_eq!(a.int_id.0, 123); 300 | /// 301 | /// let s = r#"{ "int_id": 444 }"#; 302 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 303 | /// assert_eq!(a.int_id.0, 444); 304 | /// ``` 305 | pub fn deserialize_number_from_string<'de, T, D>(deserializer: D) -> Result 306 | where 307 | D: Deserializer<'de>, 308 | T: FromStr + Deserialize<'de>, 309 | ::Err: Display, 310 | { 311 | #[derive(Deserialize)] 312 | #[serde(untagged)] 313 | enum StringOrInt { 314 | String(String), 315 | Number(T), 316 | } 317 | 318 | match StringOrInt::::deserialize(deserializer)? { 319 | StringOrInt::String(s) => s.parse::().map_err(serde::de::Error::custom), 320 | StringOrInt::Number(i) => Ok(i), 321 | } 322 | } 323 | 324 | /// Deserializes an option number from string or a number. 325 | /// 326 | /// # Example: 327 | /// 328 | /// ```rust 329 | /// use serde_aux::prelude::*; 330 | /// 331 | /// #[derive(serde::Deserialize, Debug)] 332 | /// struct MyStruct { 333 | /// #[serde(deserialize_with = "deserialize_option_number_from_string")] 334 | /// option_num: Option, 335 | /// #[serde(default, deserialize_with = "deserialize_option_number_from_string")] 336 | /// missing: Option 337 | /// } 338 | /// fn serde_qs_eq(s: &str, result: Option) { 339 | /// let a: MyStruct = serde_qs::from_str(s).unwrap(); 340 | /// assert_eq!(a.option_num, result); 341 | /// assert_eq!(a.missing, None); 342 | /// } 343 | /// fn serde_qs_err(s: &str) { 344 | /// assert!(serde_qs::from_str::(s).is_err()); 345 | /// } 346 | /// fn serde_json_eq(s: &str, result: Option) { 347 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 348 | /// assert_eq!(a.option_num, result); 349 | /// assert_eq!(a.missing, None); 350 | /// } 351 | /// fn serde_json_err(s: &str) { 352 | /// assert!(serde_json::from_str::(s).is_err()); 353 | /// } 354 | /// 355 | /// serde_qs_eq("option_num=1", Some(1.0)); 356 | /// serde_qs_eq("option_num=-1", Some(-1.0)); 357 | /// serde_qs_eq("option_num=0.1", Some(0.1)); 358 | /// serde_qs_eq("option_num=-0.1", Some(-0.1)); 359 | /// serde_qs_eq("option_num=", None); 360 | /// serde_qs_eq("option_num", None); 361 | /// 362 | /// serde_qs_err("option_num=true"); 363 | /// serde_qs_err("option_num=a"); 364 | /// serde_qs_err("option_num[a]="); 365 | /// serde_qs_err("option_num[]="); 366 | /// 367 | /// serde_json_eq(r#" { "option_num": "1" } "#, Some(1.0)); 368 | /// serde_json_eq(r#" { "option_num": "-1" } "#, Some(-1.0)); 369 | /// serde_json_eq(r#" { "option_num": "0.1" } "#, Some(0.1)); 370 | /// serde_json_eq(r#" { "option_num": "-0.1" } "#, Some(-0.1)); 371 | /// serde_json_eq(r#" { "option_num": 1 } "#, Some(1.0)); 372 | /// serde_json_eq(r#" { "option_num": -1 } "#, Some(-1.0)); 373 | /// serde_json_eq(r#" { "option_num": 0.1 } "#, Some(0.1)); 374 | /// serde_json_eq(r#" { "option_num": -0.1 } "#, Some(-0.1)); 375 | /// serde_json_eq(r#" { "option_num": "" } "#, None); 376 | /// serde_json_eq(r#" { "option_num": null } "#, None); 377 | /// 378 | /// serde_json_err(r#" { "option_num": true } "#); 379 | /// serde_json_err(r#" { "option_num": "a" } "#); 380 | /// serde_json_err(r#" { "option_num": {} } "#); 381 | /// serde_json_err(r#" { "option_num": [] } "#); 382 | /// ``` 383 | pub fn deserialize_option_number_from_string<'de, T, D>( 384 | deserializer: D, 385 | ) -> Result, D::Error> 386 | where 387 | D: Deserializer<'de>, 388 | T: FromStr + Deserialize<'de>, 389 | ::Err: Display, 390 | { 391 | #[derive(Deserialize)] 392 | #[serde(untagged)] 393 | enum NumericOrNull<'a, T> { 394 | Str(&'a str), 395 | String(String), 396 | FromStr(T), 397 | Null, 398 | } 399 | 400 | match NumericOrNull::::deserialize(deserializer)? { 401 | NumericOrNull::Str(s) => match s { 402 | "" => Ok(None), 403 | _ => T::from_str(s).map(Some).map_err(serde::de::Error::custom), 404 | }, 405 | NumericOrNull::String(s) => match s.as_str() { 406 | "" => Ok(None), 407 | _ => T::from_str(&s).map(Some).map_err(serde::de::Error::custom), 408 | }, 409 | NumericOrNull::FromStr(i) => Ok(Some(i)), 410 | NumericOrNull::Null => Ok(None), 411 | } 412 | } 413 | 414 | macro_rules! wrap_option_number_from_string_fn { 415 | ( 416 | $(#[doc = $doc:tt])* 417 | $func:ident, 418 | $res:ty 419 | ) => { 420 | $(#[doc = $doc])* 421 | pub fn $func<'de, T, D>(deserializer: D) -> Result<$res, D::Error> 422 | where 423 | D: Deserializer<'de>, 424 | T: FromStr + Deserialize<'de>, 425 | ::Err: Display, 426 | { 427 | #[derive(Deserialize)] 428 | #[serde(untagged)] 429 | enum NumericOrNull<'a, T> { 430 | Str(&'a str), 431 | String(String), 432 | FromStr(T), 433 | Null, 434 | } 435 | 436 | match NumericOrNull::::deserialize(deserializer)? { 437 | NumericOrNull::Str(s) => match s { 438 | "" => Ok(None.into()), 439 | _ => T::from_str(s) 440 | .map(|i| Some(i).into()) 441 | .map_err(serde::de::Error::custom), 442 | }, 443 | NumericOrNull::String(s) => match s.as_str() { 444 | "" => Ok(None.into()), 445 | _ => T::from_str(&s) 446 | .map(|i| Some(i).into()) 447 | .map_err(serde::de::Error::custom), 448 | }, 449 | NumericOrNull::FromStr(i) => Ok(Some(i).into()), 450 | NumericOrNull::Null => Ok(None.into()), 451 | } 452 | } 453 | }; 454 | } 455 | wrap_option_number_from_string_fn!( 456 | /// Deserializes a `Cell` option number from string or a number. Same logic as [`"deserialize_option_number_from_string"`](https://docs.rs/serde-aux/latest/serde_aux/field_attributes/fn.deserialize_option_number_from_string.html). 457 | /// 458 | /// # Example: 459 | /// 460 | /// ```rust 461 | /// use serde_aux::prelude::*; 462 | /// use std::cell::Cell; 463 | /// 464 | /// #[derive(serde::Deserialize, Debug)] 465 | /// struct MyStruct { 466 | /// #[serde(deserialize_with = "deserialize_cell_option_number_from_string")] 467 | /// v: Cell> 468 | /// } 469 | /// 470 | /// let a = serde_qs::from_str::("v=-0.1").unwrap(); 471 | /// assert_eq!(a.v, Cell::new(Some(-0.1))); 472 | /// ``` 473 | deserialize_cell_option_number_from_string, 474 | std::cell::Cell> 475 | ); 476 | wrap_option_number_from_string_fn!( 477 | /// Deserializes a `RefCell` option number from string or a number. Same logic as [`"deserialize_option_number_from_string"`](https://docs.rs/serde-aux/latest/serde_aux/field_attributes/fn.deserialize_option_number_from_string.html). 478 | /// 479 | /// # Example: 480 | /// 481 | /// ```rust 482 | /// use serde_aux::prelude::*; 483 | /// use std::cell::RefCell; 484 | /// 485 | /// #[derive(serde::Deserialize, Debug)] 486 | /// struct MyStruct { 487 | /// #[serde(default, deserialize_with = "deserialize_ref_cell_option_number_from_string")] 488 | /// v: RefCell> 489 | /// } 490 | /// 491 | /// let a = serde_qs::from_str::("v=-0.1").unwrap(); 492 | /// assert_eq!(a.v, RefCell::new(Some(-0.1))); 493 | /// ``` 494 | deserialize_ref_cell_option_number_from_string, 495 | std::cell::RefCell> 496 | ); 497 | wrap_option_number_from_string_fn!( 498 | /// Deserializes a `Mutex` option number from string or a number. Same logic as [`"deserialize_option_number_from_string"`](https://docs.rs/serde-aux/latest/serde_aux/field_attributes/fn.deserialize_option_number_from_string.html). 499 | /// 500 | /// # Example: 501 | /// 502 | /// ```rust 503 | /// use serde_aux::prelude::*; 504 | /// use std::sync::Mutex; 505 | /// 506 | /// #[derive(serde::Deserialize, Debug)] 507 | /// struct MyStruct { 508 | /// #[serde(default, deserialize_with = "deserialize_mutex_option_number_from_string")] 509 | /// v: Mutex> 510 | /// } 511 | /// 512 | /// let a = serde_qs::from_str::("v=-0.1").unwrap(); 513 | /// assert_eq!(*a.v.lock().unwrap(), Some(-0.1)); 514 | /// ``` 515 | deserialize_mutex_option_number_from_string, 516 | std::sync::Mutex> 517 | ); 518 | wrap_option_number_from_string_fn!( 519 | /// Deserializes a `RwLock` option number from string or a number. Same logic as [`"deserialize_option_number_from_string"`](https://docs.rs/serde-aux/latest/serde_aux/field_attributes/fn.deserialize_option_number_from_string.html). 520 | /// 521 | /// # Example: 522 | /// 523 | /// ```rust 524 | /// use serde_aux::prelude::*; 525 | /// use std::sync::RwLock; 526 | /// 527 | /// #[derive(serde::Deserialize, Debug)] 528 | /// struct MyStruct { 529 | /// #[serde(default, deserialize_with = "deserialize_rw_lock_option_number_from_string")] 530 | /// v: RwLock> 531 | /// } 532 | /// 533 | /// let a = serde_qs::from_str::("v=-0.1").unwrap(); 534 | /// assert_eq!(*a.v.read().unwrap(), Some(-0.1)); 535 | /// ``` 536 | deserialize_rw_lock_option_number_from_string, 537 | std::sync::RwLock> 538 | ); 539 | 540 | /// Deserializes boolean from anything (string, number, boolean). If input is a string, 541 | /// it is expected, that it is possible to convert it to a number. The return boolean is 542 | /// `true` if the number was either `1` or `1.0` after parsing. 543 | /// 544 | /// # Example 545 | /// 546 | /// ```rust 547 | /// use serde_aux::prelude::*; 548 | /// 549 | /// #[derive(serde::Deserialize, Debug)] 550 | /// struct MyStruct { 551 | /// #[serde(deserialize_with = "deserialize_bool_from_anything")] 552 | /// boolean: bool, 553 | /// } 554 | /// 555 | /// let s = r#"{ "boolean": 1.0 }"#; 556 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 557 | /// assert!(a.boolean); 558 | /// 559 | /// let s = r#"{ "boolean": 0.0 }"#; 560 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 561 | /// assert!(!a.boolean); 562 | /// 563 | /// let s = r#"{ "boolean": 2.3 }"#; 564 | /// assert!(serde_json::from_str::(s).is_err()); 565 | /// 566 | /// let s = r#"{ "boolean": 1 }"#; 567 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 568 | /// assert!(a.boolean); 569 | /// 570 | /// let s = r#"{ "boolean": 0 }"#; 571 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 572 | /// assert!(!a.boolean); 573 | /// 574 | /// let s = r#"{ "boolean": 2 }"#; 575 | /// assert!(serde_json::from_str::(s).is_err()); 576 | /// 577 | /// let s = r#"{ "boolean": "1.0" }"#; 578 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 579 | /// assert!(a.boolean); 580 | /// 581 | /// let s = r#"{ "boolean": "0.0" }"#; 582 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 583 | /// assert!(!a.boolean); 584 | /// 585 | /// let s = r#"{ "boolean": "2.3" }"#; 586 | /// assert!(serde_json::from_str::(s).is_err()); 587 | /// 588 | /// let s = r#"{ "boolean": "1" }"#; 589 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 590 | /// assert!(a.boolean); 591 | /// 592 | /// let s = r#"{ "boolean": "0" }"#; 593 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 594 | /// assert!(!a.boolean); 595 | /// 596 | /// let s = r#"{ "boolean": "TRUE" }"#; 597 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 598 | /// assert!(a.boolean); 599 | /// 600 | /// let s = r#"{ "boolean": "FALSE" }"#; 601 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 602 | /// assert!(!a.boolean); 603 | /// 604 | /// let s = r#"{ "boolean": "TruE" }"#; 605 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 606 | /// assert!(a.boolean); 607 | /// 608 | /// let s = r#"{ "boolean": "fAlsE" }"#; 609 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 610 | /// assert!(!a.boolean); 611 | /// 612 | /// let s = r#"{ "boolean": "true" }"#; 613 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 614 | /// assert!(a.boolean); 615 | /// 616 | /// let s = r#"{ "boolean": "false" }"#; 617 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 618 | /// assert!(!a.boolean); 619 | /// 620 | /// let s = r#"{ "boolean": "2" }"#; 621 | /// assert!(serde_json::from_str::(s).is_err()); 622 | /// 623 | /// let s = r#"{ "boolean": "foo" }"#; 624 | /// assert!(serde_json::from_str::(s).is_err()); 625 | /// ``` 626 | pub fn deserialize_bool_from_anything<'de, D>(deserializer: D) -> Result 627 | where 628 | D: Deserializer<'de>, 629 | { 630 | #[derive(Deserialize)] 631 | #[serde(untagged)] 632 | enum AnythingOrBool { 633 | String(String), 634 | Int(i64), 635 | Float(f64), 636 | Boolean(bool), 637 | } 638 | 639 | match AnythingOrBool::deserialize(deserializer)? { 640 | AnythingOrBool::Boolean(b) => Ok(b), 641 | AnythingOrBool::Int(i) => match i { 642 | 1 => Ok(true), 643 | 0 => Ok(false), 644 | _ => Err(serde::de::Error::custom("The number is neither 1 nor 0")), 645 | }, 646 | AnythingOrBool::Float(f) => { 647 | if (f - 1.0f64).abs() < f64::EPSILON { 648 | Ok(true) 649 | } else if f == 0.0f64 { 650 | Ok(false) 651 | } else { 652 | Err(serde::de::Error::custom( 653 | "The number is neither 1.0 nor 0.0", 654 | )) 655 | } 656 | } 657 | AnythingOrBool::String(string) => { 658 | if let Ok(b) = string.to_lowercase().parse::() { 659 | Ok(b) 660 | } else if let Ok(i) = string.parse::() { 661 | match i { 662 | 1 => Ok(true), 663 | 0 => Ok(false), 664 | _ => Err(serde::de::Error::custom("The number is neither 1 nor 0")), 665 | } 666 | } else if let Ok(f) = string.parse::() { 667 | if (f - 1.0f64).abs() < f64::EPSILON { 668 | Ok(true) 669 | } else if f == 0.0f64 { 670 | Ok(false) 671 | } else { 672 | Err(serde::de::Error::custom( 673 | "The number is neither 1.0 nor 0.0", 674 | )) 675 | } 676 | } else { 677 | Err(serde::de::Error::custom(format!( 678 | "Could not parse boolean from a string: {}", 679 | string 680 | ))) 681 | } 682 | } 683 | } 684 | } 685 | 686 | /// Deserializes string from a number. If the original value is a number value, 687 | /// it will be converted to a string. 688 | /// 689 | /// # Example: 690 | /// 691 | /// ```rust 692 | /// use serde_aux::prelude::*; 693 | /// 694 | /// #[derive(serde::Deserialize, Debug)] 695 | /// struct MyStruct { 696 | /// #[serde(deserialize_with = "deserialize_string_from_number")] 697 | /// number_as_string: String, 698 | /// } 699 | /// 700 | /// let s = r#" { "number_as_string": "foo" } "#; 701 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 702 | /// assert_eq!(a.number_as_string, "foo"); 703 | /// 704 | /// let s = r#" { "number_as_string": -13 } "#; 705 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 706 | /// assert_eq!(a.number_as_string, "-13"); 707 | /// 708 | /// let s = r#" { "number_as_string": 24.0034 } "#; 709 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 710 | /// assert_eq!(a.number_as_string, "24.0034"); 711 | /// ``` 712 | pub fn deserialize_string_from_number<'de, D>(deserializer: D) -> Result 713 | where 714 | D: Deserializer<'de>, 715 | { 716 | #[derive(Deserialize)] 717 | #[serde(untagged)] 718 | enum StringOrNumber { 719 | String(String), 720 | Number(i64), 721 | Float(f64), 722 | } 723 | 724 | match StringOrNumber::deserialize(deserializer)? { 725 | StringOrNumber::String(s) => Ok(s), 726 | StringOrNumber::Number(i) => Ok(i.to_string()), 727 | StringOrNumber::Float(f) => Ok(f.to_string()), 728 | } 729 | } 730 | 731 | /// Deserializes default value from nullable value. If the original value is `null`, 732 | /// `Default::default()` is used. 733 | /// 734 | /// # Example: 735 | /// 736 | /// ```rust 737 | /// use serde_aux::prelude::*; 738 | /// 739 | /// #[derive(serde::Deserialize, Debug)] 740 | /// struct MyStruct { 741 | /// #[serde(deserialize_with = "deserialize_default_from_null")] 742 | /// null_as_default: u64, 743 | /// } 744 | /// 745 | /// let s = r#" { "null_as_default": 42 } "#; 746 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 747 | /// assert_eq!(a.null_as_default, 42); 748 | /// 749 | /// let s = r#" { "null_as_default": null } "#; 750 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 751 | /// assert_eq!(a.null_as_default, 0); 752 | /// 753 | /// let s = r#" { "null_as_default": "wrong_type" } "#; 754 | /// assert!(serde_json::from_str::(s).is_err()); 755 | /// ``` 756 | pub fn deserialize_default_from_null<'de, D, T>(deserializer: D) -> Result 757 | where 758 | D: Deserializer<'de>, 759 | T: Deserialize<'de> + Default, 760 | { 761 | Ok(Option::deserialize(deserializer)?.unwrap_or_default()) 762 | } 763 | 764 | /// Deserializes default value from nullable value or empty object. If the original value is `null` or `{}`, 765 | /// `Default::default()` is used. 766 | /// 767 | /// # Example: 768 | /// 769 | /// ```rust 770 | /// use serde_aux::prelude::*; 771 | /// 772 | /// #[derive(serde::Deserialize, Debug)] 773 | /// struct MyStruct { 774 | /// #[serde(deserialize_with = "deserialize_default_from_empty_object")] 775 | /// empty_as_default: Option, 776 | /// } 777 | /// 778 | /// #[derive(serde::Deserialize, Debug)] 779 | /// struct MyInnerStruct { 780 | /// mandatory: u64, 781 | /// } 782 | /// 783 | /// let s = r#" { "empty_as_default": { "mandatory": 42 } } "#; 784 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 785 | /// assert_eq!(a.empty_as_default.unwrap().mandatory, 42); 786 | /// 787 | /// let s = r#" { "empty_as_default": null } "#; 788 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 789 | /// assert!(a.empty_as_default.is_none()); 790 | /// 791 | /// let s = r#" { "empty_as_default": {} } "#; 792 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 793 | /// assert!(a.empty_as_default.is_none()); 794 | /// 795 | /// let s = r#" { "empty_as_default": { "unknown": 42 } } "#; 796 | /// assert!(serde_json::from_str::(s).is_err()); 797 | /// ``` 798 | pub fn deserialize_default_from_empty_object<'de, D, T>(deserializer: D) -> Result 799 | where 800 | D: Deserializer<'de>, 801 | T: Deserialize<'de> + Default, 802 | { 803 | #[derive(Debug, Deserialize)] 804 | #[serde(deny_unknown_fields)] 805 | struct EmptyObject {} 806 | 807 | #[derive(Debug, Deserialize)] 808 | #[serde(untagged)] 809 | enum EmptyOrNot { 810 | NonEmpty(Y), 811 | Empty(EmptyObject), 812 | Null, 813 | } 814 | 815 | let empty_or_not: EmptyOrNot = EmptyOrNot::deserialize(deserializer)?; 816 | 817 | match empty_or_not { 818 | EmptyOrNot::NonEmpty(e) => Ok(e), 819 | _ => Ok(T::default()), 820 | } 821 | } 822 | 823 | /// Deserializes a comma separated string into a `Vec`. 824 | /// 825 | /// # Example: 826 | /// 827 | /// ```rust 828 | /// use serde_aux::prelude::*; 829 | /// 830 | /// #[derive(serde::Deserialize, Debug)] 831 | /// struct MyStruct { 832 | /// #[serde(deserialize_with = "deserialize_vec_from_string_or_vec")] 833 | /// list: Vec, 834 | /// } 835 | /// 836 | /// let s = r#" { "list": "1,2,3,4" } "#; 837 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 838 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 839 | /// 840 | /// let s = r#" { "list": [1,2,3,4] } "#; 841 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 842 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 843 | /// ``` 844 | pub fn deserialize_vec_from_string_or_vec<'de, T, D>(deserializer: D) -> Result, D::Error> 845 | where 846 | D: Deserializer<'de>, 847 | T: FromStr + Deserialize<'de> + 'static, 848 | ::Err: std::fmt::Display, 849 | { 850 | StringOrVecToVec::default().into_deserializer()(deserializer) 851 | } 852 | 853 | /// Deserialize to primary or fallback type. 854 | /// 855 | /// This helper function will attempt to deserialize to the primary type first, 856 | /// and if that fails it will attempt to deserialize to the fallback type. If 857 | /// both fail, it will return an error. 858 | /// 859 | /// # Example: 860 | /// 861 | /// ```rust 862 | /// use serde_aux::prelude::*; 863 | /// 864 | /// #[derive(serde::Deserialize, Debug)] 865 | /// struct MyStruct { 866 | /// #[serde(deserialize_with = "deserialize_to_type_or_fallback")] 867 | /// i64_or_f64: Result, 868 | /// #[serde(deserialize_with = "deserialize_to_type_or_fallback")] 869 | /// f64_or_string: Result, 870 | /// } 871 | /// 872 | /// let s = r#" { "i64_or_f64": 1, "f64_or_string": 1 } "#; 873 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 874 | /// assert_eq!(a.i64_or_f64, Ok(1)); 875 | /// assert_eq!(a.f64_or_string, Ok(1.0)); 876 | /// 877 | /// let s = r#" { "i64_or_f64": 1.0, "f64_or_string": 1.0 } "#; 878 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 879 | /// assert_eq!(a.i64_or_f64, Err(1.0)); 880 | /// assert_eq!(a.f64_or_string, Ok(1.0)); 881 | /// 882 | /// let s = r#" { "i64_or_f64": 1.0, "f64_or_string": "foo" } "#; 883 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 884 | /// assert_eq!(a.i64_or_f64, Err(1.0)); 885 | /// assert_eq!(a.f64_or_string, Err(String::from("foo"))); 886 | /// 887 | /// let s = r#" { "i64_or_f64": "foo", "f64_or_string": "foo" } "#; 888 | /// assert!(serde_json::from_str::(s).is_err()); 889 | /// ``` 890 | pub fn deserialize_to_type_or_fallback<'de, D, T, F>( 891 | deserializer: D, 892 | ) -> Result, D::Error> 893 | where 894 | D: Deserializer<'de>, 895 | T: Deserialize<'de>, 896 | F: Deserialize<'de>, 897 | { 898 | #[derive(Deserialize)] 899 | #[serde(untagged)] 900 | enum DeEither { 901 | Type(T), 902 | Fallback(F), 903 | } 904 | 905 | DeEither::::deserialize(deserializer).map(|de| match de { 906 | DeEither::Type(t) => Ok(t), 907 | DeEither::Fallback(f) => Err(f), 908 | }) 909 | } 910 | 911 | /// Deserialize to a given type, while ignoring any invalid fields. 912 | /// 913 | /// This helper function will attempt to deserialize to the given type, and if 914 | /// it fails it will return `None`, therefore never failing. This is different 915 | /// from deserializing directly to `Option`, because this would return `None` 916 | /// only for empty fields, while it would return an error for invalid fields. 917 | /// 918 | /// # Example: 919 | /// 920 | /// ```rust 921 | /// use serde_aux::prelude::*; 922 | /// 923 | /// #[derive(serde::Deserialize, Debug)] 924 | /// struct MyStruct { 925 | /// #[serde(deserialize_with = "deserialize_to_type_or_none")] 926 | /// opt_f64: Option, 927 | /// } 928 | /// 929 | /// let s = r#" { "opt_f64": 1 } "#; 930 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 931 | /// assert_eq!(a.opt_f64, Some(1.0)); 932 | /// 933 | /// let s = r#" { "opt_f64": 1.0 } "#; 934 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 935 | /// assert_eq!(a.opt_f64, Some(1.0)); 936 | /// 937 | /// let s = r#" { "opt_f64": "foo" } "#; 938 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 939 | /// assert_eq!(a.opt_f64, None); 940 | /// ``` 941 | pub fn deserialize_to_type_or_none<'de, D, T>(deserializer: D) -> Result, D::Error> 942 | where 943 | D: Deserializer<'de>, 944 | Option: Deserialize<'de>, 945 | { 946 | Option::::deserialize(deserializer).or_else(|_| Ok(None)) 947 | } 948 | 949 | /// Deserialize to a given type, while returning invalid fields as `String`. 950 | /// 951 | /// This helper function will attempt to deserialize to the given type, and if 952 | /// it fails it will return the invalid field lossily converted to `String`, 953 | /// therefore never failing. 954 | /// 955 | /// # Example: 956 | /// 957 | /// ```rust 958 | /// use serde_aux::prelude::*; 959 | /// 960 | /// #[derive(serde::Deserialize, Debug)] 961 | /// struct MyStruct { 962 | /// #[serde(deserialize_with = "deserialize_to_type_or_string_lossy")] 963 | /// f64_or_string_lossy: Result, 964 | /// } 965 | /// 966 | /// let s = r#" { "f64_or_string_lossy": 1 } "#; 967 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 968 | /// assert_eq!(a.f64_or_string_lossy, Ok(1.0)); 969 | /// 970 | /// let s = r#" { "f64_or_string_lossy": 1.0 } "#; 971 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 972 | /// assert_eq!(a.f64_or_string_lossy, Ok(1.0)); 973 | /// 974 | /// let s = r#" { "f64_or_string_lossy": "foo" } "#; 975 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 976 | /// assert_eq!(a.f64_or_string_lossy, Err(String::from("foo"))); 977 | /// ``` 978 | pub fn deserialize_to_type_or_string_lossy<'de, D, T>( 979 | deserializer: D, 980 | ) -> Result, D::Error> 981 | where 982 | D: Deserializer<'de>, 983 | T: Deserialize<'de>, 984 | { 985 | let value = serde_value::Value::deserialize(deserializer)?; 986 | Ok(T::deserialize(value.clone()).map_err(|_| match value { 987 | serde_value::Value::Bool(b) => b.to_string(), 988 | serde_value::Value::U8(u) => u.to_string(), 989 | serde_value::Value::U16(u) => u.to_string(), 990 | serde_value::Value::U32(u) => u.to_string(), 991 | serde_value::Value::U64(u) => u.to_string(), 992 | serde_value::Value::I8(i) => i.to_string(), 993 | serde_value::Value::I16(i) => i.to_string(), 994 | serde_value::Value::I32(i) => i.to_string(), 995 | serde_value::Value::I64(i) => i.to_string(), 996 | serde_value::Value::F32(f) => f.to_string(), 997 | serde_value::Value::F64(f) => f.to_string(), 998 | serde_value::Value::Char(c) => c.to_string(), 999 | serde_value::Value::String(s) => s, 1000 | serde_value::Value::Unit => String::new(), 1001 | serde_value::Value::Option(opt) => { 1002 | format!("{:?}", opt) 1003 | } 1004 | serde_value::Value::Newtype(nt) => { 1005 | format!("{:?}", nt) 1006 | } 1007 | serde_value::Value::Seq(seq) => format!("{:?}", seq), 1008 | serde_value::Value::Map(map) => format!("{:?}", map), 1009 | serde_value::Value::Bytes(v) => String::from_utf8_lossy(&v).into_owned(), 1010 | })) 1011 | } 1012 | 1013 | /// Create a parser quickly. 1014 | /// 1015 | /// ``` 1016 | /// use serde_aux::prelude::*; 1017 | /// use std::str::FromStr; 1018 | /// 1019 | /// serde_aux::StringOrVecToVecParser!(parse_between_commas, |c| { c == ',' }, true); 1020 | /// 1021 | /// #[derive(serde::Deserialize, Debug)] 1022 | /// struct MyStruct { 1023 | /// #[serde(deserialize_with = "parse_between_commas")] 1024 | /// list: Vec, 1025 | /// } 1026 | /// 1027 | /// let s = r#" { "list": "1,2,3,4" } "#; 1028 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1029 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1030 | /// 1031 | /// let s = r#" { "list": [1,2,3,4] } "#; 1032 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1033 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1034 | /// 1035 | /// 1036 | /// serde_aux::StringOrVecToVecParser!(u8, parse_hex_with_spaces, ' ', |s| { u8::from_str_radix(s, 16) }, true); 1037 | /// 1038 | /// #[derive(serde::Deserialize, Debug)] 1039 | /// struct MyStructHex { 1040 | /// #[serde(deserialize_with = "parse_hex_with_spaces")] 1041 | /// list: Vec, 1042 | /// } 1043 | /// 1044 | /// let s = r#" { "list": "a1 b2 c3 d4 " } "#; 1045 | /// let a: MyStructHex = serde_json::from_str(s).unwrap(); 1046 | /// assert_eq!(&a.list, &[0xa1, 0xb2, 0xc3, 0xd4]); 1047 | /// 1048 | /// let s = r#" { "list": "a1 b2 c3 d4 " } "#; 1049 | /// let a: MyStructHex = serde_json::from_str(s).unwrap(); 1050 | /// assert_eq!(&a.list, &[0xa1, 0xb2, 0xc3, 0xd4]); 1051 | /// ``` 1052 | #[macro_export] 1053 | macro_rules! StringOrVecToVecParser { 1054 | ($name:ident, $separator:expr, $skip_empty:expr) => { 1055 | fn $name<'de, D, T>(deserializer: D) -> Result, D::Error> 1056 | where 1057 | D: serde::Deserializer<'de>, 1058 | T: FromStr + serde::Deserialize<'de> + 'static, 1059 | ::Err: std::fmt::Display, 1060 | { 1061 | let mut parser = $crate::field_attributes::StringOrVecToVec::with_separator($separator); 1062 | parser.skip_empty($skip_empty); 1063 | parser.into_deserializer()(deserializer) 1064 | } 1065 | }; 1066 | 1067 | ($t:ty, $name:ident, $pattern:expr, $converter:expr, $skip_empty:expr) => { 1068 | fn $name<'de, D>(deserializer: D) -> Result, D::Error> 1069 | where 1070 | D: serde::Deserializer<'de>, 1071 | { 1072 | $crate::field_attributes::StringOrVecToVec::new($pattern, $converter, $skip_empty) 1073 | .into_deserializer()(deserializer) 1074 | } 1075 | }; 1076 | } 1077 | 1078 | /// Builder to create a parser, that parses a separated string or a vec into a vec. 1079 | /// 1080 | /// # Example: 1081 | /// 1082 | /// ```rust 1083 | /// use serde_aux::prelude::*; 1084 | /// use std::str::FromStr; 1085 | /// 1086 | /// fn parser<'de, D, T>(deserializer: D) -> Result, D::Error> 1087 | /// where 1088 | /// D: serde::Deserializer<'de>, 1089 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1090 | /// ::Err: std::fmt::Display, 1091 | /// { 1092 | /// StringOrVecToVec::default().into_deserializer()(deserializer) 1093 | /// } 1094 | /// 1095 | /// #[derive(serde::Deserialize, Debug)] 1096 | /// struct MyStruct { 1097 | /// #[serde(deserialize_with = "parser")] 1098 | /// list: Vec, 1099 | /// } 1100 | /// 1101 | /// let s = r#" { "list": "1,2,3,4" } "#; 1102 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1103 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1104 | /// 1105 | /// let s = r#" { "list": [1,2,3,4] } "#; 1106 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1107 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1108 | pub struct StringOrVecToVec<'a, T, E> { 1109 | separator: Pattern<'a>, 1110 | parser: Box>, 1111 | skip_empty: bool, 1112 | } 1113 | 1114 | /// A functor returning a [`Result`] of parsing a string into a vector 1115 | /// of objects of type `T`. 1116 | pub type StringOrVecParser = dyn FnMut(&str) -> Result; 1117 | 1118 | /// Pattern on which a string can be split. 1119 | pub enum Pattern<'a> { 1120 | /// Split on a matching char 1121 | Char(char), 1122 | /// Split on a matching str 1123 | Str(&'a str), 1124 | /// Split if a char matches the predicate 1125 | Pred(Box bool>), 1126 | /// Multiple patterns 1127 | /// 1128 | /// # Example 1129 | /// 1130 | /// ```rust 1131 | /// use serde_aux::prelude::*; 1132 | /// use std::str::FromStr; 1133 | /// 1134 | /// fn parser<'de, D, T>(deserializer: D) -> Result, D::Error> 1135 | /// where 1136 | /// D: serde::Deserializer<'de>, 1137 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1138 | /// ::Err: std::fmt::Display, 1139 | /// { 1140 | /// StringOrVecToVec::with_separator(vec![Pattern::Char('+'), Pattern::Char('-')]).into_deserializer()(deserializer) 1141 | /// } 1142 | /// 1143 | /// #[derive(serde::Deserialize, Debug)] 1144 | /// struct MyStruct { 1145 | /// #[serde(deserialize_with = "parser")] 1146 | /// list: Vec, 1147 | /// } 1148 | /// 1149 | /// let s = r#" { "list": "1-2+3-4" } "#; 1150 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1151 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1152 | /// 1153 | /// let s = r#" { "list": [1,2,3,4] } "#; 1154 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1155 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1156 | /// ``` 1157 | Multiple(Vec>), 1158 | } 1159 | 1160 | impl From for Pattern<'_> { 1161 | fn from(c: char) -> Self { 1162 | Pattern::Char(c) 1163 | } 1164 | } 1165 | 1166 | impl<'a> From<&'a str> for Pattern<'a> { 1167 | fn from(s: &'a str) -> Self { 1168 | Pattern::Str(s) 1169 | } 1170 | } 1171 | 1172 | impl<'a> From>> for Pattern<'a> { 1173 | fn from(patterns: Vec>) -> Self { 1174 | Pattern::Multiple(patterns) 1175 | } 1176 | } 1177 | 1178 | /// # Example 1179 | /// 1180 | /// ```rust 1181 | /// use serde_aux::prelude::*; 1182 | /// use std::str::FromStr; 1183 | /// 1184 | /// fn parser<'de, D, T>(deserializer: D) -> Result, D::Error> 1185 | /// where 1186 | /// D: serde::Deserializer<'de>, 1187 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1188 | /// ::Err: std::fmt::Display, 1189 | /// { 1190 | /// StringOrVecToVec::with_separator(vec!['-', '+'].into_iter().collect::()).into_deserializer()(deserializer) 1191 | /// } 1192 | /// 1193 | /// #[derive(serde::Deserialize, Debug)] 1194 | /// struct MyStruct { 1195 | /// #[serde(deserialize_with = "parser")] 1196 | /// list: Vec, 1197 | /// } 1198 | /// 1199 | /// let s = r#" { "list": "1-2+3-4" } "#; 1200 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1201 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1202 | /// 1203 | /// let s = r#" { "list": [1,2,3,4] } "#; 1204 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1205 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1206 | /// ``` 1207 | impl<'a> std::iter::FromIterator> for Pattern<'a> { 1208 | fn from_iter(iter: I) -> Self 1209 | where 1210 | I: IntoIterator>, 1211 | { 1212 | Pattern::Multiple(iter.into_iter().collect()) 1213 | } 1214 | } 1215 | 1216 | impl std::iter::FromIterator for Pattern<'_> { 1217 | fn from_iter(iter: I) -> Self 1218 | where 1219 | I: IntoIterator, 1220 | { 1221 | Pattern::Multiple(iter.into_iter().map(Pattern::from).collect()) 1222 | } 1223 | } 1224 | 1225 | impl<'a> std::iter::FromIterator<&'a str> for Pattern<'a> { 1226 | fn from_iter(iter: I) -> Self 1227 | where 1228 | I: IntoIterator, 1229 | { 1230 | Pattern::Multiple(iter.into_iter().map(Pattern::from).collect()) 1231 | } 1232 | } 1233 | 1234 | impl

From

for Pattern<'_> 1235 | where 1236 | P: Fn(char) -> bool + 'static, 1237 | { 1238 | fn from(pred: P) -> Self { 1239 | Pattern::Pred(Box::new(pred)) 1240 | } 1241 | } 1242 | 1243 | impl<'de, T> Default for StringOrVecToVec<'_, T, T::Err> 1244 | where 1245 | T: FromStr + Deserialize<'de> + 'static, 1246 | ::Err: std::fmt::Display, 1247 | { 1248 | fn default() -> Self { 1249 | Self::new(|c| c == ',', T::from_str, false) 1250 | } 1251 | } 1252 | 1253 | impl<'a, 'de, T> StringOrVecToVec<'a, T, T::Err> 1254 | where 1255 | T: FromStr + Deserialize<'de> + 'static, 1256 | ::Err: std::fmt::Display, 1257 | { 1258 | /// Create a `StringOrVecToVec` builder with a custom separator. `T::from_str` is used to parse 1259 | /// the elements of the list. 1260 | /// 1261 | /// # Example: 1262 | /// 1263 | /// ```rust 1264 | /// use serde_aux::prelude::*; 1265 | /// use std::str::FromStr; 1266 | /// 1267 | /// fn parser<'de, D, T>(deserializer: D) -> Result, D::Error> 1268 | /// where 1269 | /// D: serde::Deserializer<'de>, 1270 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1271 | /// ::Err: std::fmt::Display, 1272 | /// { 1273 | /// StringOrVecToVec::with_separator(|c| c == '-' || c == '+').into_deserializer()(deserializer) 1274 | /// } 1275 | /// 1276 | /// #[derive(serde::Deserialize, Debug)] 1277 | /// struct MyStruct { 1278 | /// #[serde(deserialize_with = "parser")] 1279 | /// list: Vec, 1280 | /// } 1281 | /// 1282 | /// let s = r#" { "list": "1-2+3-4" } "#; 1283 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1284 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1285 | /// 1286 | /// let s = r#" { "list": [1,2,3,4] } "#; 1287 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1288 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1289 | /// ``` 1290 | pub fn with_separator(separator: impl Into>) -> Self { 1291 | Self::new(separator, T::from_str, false) 1292 | } 1293 | 1294 | /// Sets the flag to skip empty separations. 1295 | /// 1296 | /// ```rust 1297 | /// use serde_aux::prelude::*; 1298 | /// use std::str::FromStr; 1299 | /// 1300 | /// fn parser_skip_empty<'de, D, T>(deserializer: D) -> Result, D::Error> 1301 | /// where 1302 | /// D: serde::Deserializer<'de>, 1303 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1304 | /// ::Err: std::fmt::Display, 1305 | /// { 1306 | /// let mut parser = StringOrVecToVec::with_separator(|c| c == '-' || c == '+'); 1307 | /// parser.skip_empty(true); 1308 | /// parser.into_deserializer()(deserializer) 1309 | /// } 1310 | /// 1311 | /// #[derive(serde::Deserialize, Debug)] 1312 | /// struct MyStructSkipEmpty { 1313 | /// #[serde(deserialize_with = "parser_skip_empty")] 1314 | /// list: Vec, 1315 | /// } 1316 | /// 1317 | /// let s = r#" { "list": "1-2+3-4--++--" } "#; 1318 | /// let a: MyStructSkipEmpty = serde_json::from_str(s).unwrap(); 1319 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1320 | /// ``` 1321 | pub fn skip_empty(&mut self, skip_empty: bool) -> &mut Self { 1322 | self.skip_empty = skip_empty; 1323 | self 1324 | } 1325 | } 1326 | 1327 | impl<'a, T, E> StringOrVecToVec<'a, T, E> { 1328 | /// Create a deserializer with a custom separator and parsing function. 1329 | /// 1330 | /// # Example: 1331 | /// 1332 | /// ```rust 1333 | /// use serde_aux::prelude::*; 1334 | /// use std::str::FromStr; 1335 | /// 1336 | /// fn parser<'de, D, T>(deserializer: D) -> Result, D::Error> 1337 | /// where 1338 | /// D: serde::Deserializer<'de>, 1339 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1340 | /// ::Err: std::fmt::Display, 1341 | /// { 1342 | /// StringOrVecToVec::new('-', |s| s.trim().parse(), false).into_deserializer()(deserializer) 1343 | /// } 1344 | /// 1345 | /// #[derive(serde::Deserialize, Debug)] 1346 | /// struct MyStruct { 1347 | /// #[serde(deserialize_with = "parser")] 1348 | /// list: Vec, 1349 | /// } 1350 | /// 1351 | /// let s = r#" { "list": "1 - 2 - 3- 4 " } "#; 1352 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1353 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1354 | /// 1355 | /// let s = r#" { "list": [1,2,3,4] } "#; 1356 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1357 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1358 | /// ``` 1359 | pub fn new( 1360 | separator: impl Into>, 1361 | parser: impl FnMut(&str) -> Result + 'static, 1362 | skip_empty: bool, 1363 | ) -> Self { 1364 | Self { 1365 | separator: separator.into(), 1366 | parser: Box::new(parser), 1367 | skip_empty, 1368 | } 1369 | } 1370 | 1371 | /// Create a deserializer with a custom parsing function. The input string will be separated on 1372 | /// `,`. 1373 | /// 1374 | /// # Example: 1375 | /// 1376 | /// ```rust 1377 | /// use serde_aux::prelude::*; 1378 | /// use std::str::FromStr; 1379 | /// 1380 | /// fn parser<'de, D, T>(deserializer: D) -> Result, D::Error> 1381 | /// where 1382 | /// D: serde::Deserializer<'de>, 1383 | /// T: FromStr + serde::Deserialize<'de> + 'static, 1384 | /// ::Err: std::fmt::Display, 1385 | /// { 1386 | /// StringOrVecToVec::with_parser(|s| s.trim().parse()).into_deserializer()(deserializer) 1387 | /// } 1388 | /// 1389 | /// #[derive(serde::Deserialize, Debug)] 1390 | /// struct MyStruct { 1391 | /// #[serde(deserialize_with = "parser")] 1392 | /// list: Vec, 1393 | /// } 1394 | /// 1395 | /// let s = r#" { "list": "1 , 2 , 3, 4 " } "#; 1396 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1397 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1398 | /// 1399 | /// let s = r#" { "list": [1,2,3,4] } "#; 1400 | /// let a: MyStruct = serde_json::from_str(s).unwrap(); 1401 | /// assert_eq!(&a.list, &[1, 2, 3, 4]); 1402 | /// ``` 1403 | pub fn with_parser(parser: impl FnMut(&str) -> Result + 'static) -> Self { 1404 | Self::new(|c| c == ',', parser, false) 1405 | } 1406 | 1407 | /// Creates the actual deserializer from this builder. 1408 | pub fn into_deserializer<'de, D>( 1409 | self, 1410 | ) -> impl FnMut(D) -> Result, >::Error> 1411 | where 1412 | 'a: 'de, 1413 | D: Deserializer<'de>, 1414 | T: Deserialize<'de>, 1415 | E: std::fmt::Display, 1416 | { 1417 | #[derive(Deserialize)] 1418 | #[serde(untagged)] 1419 | enum StringOrVec { 1420 | String(String), 1421 | Vec(Vec), 1422 | } 1423 | 1424 | let StringOrVecToVec { 1425 | mut parser, 1426 | separator, 1427 | skip_empty, 1428 | } = self; 1429 | 1430 | move |deserializer| match StringOrVec::::deserialize(deserializer)? { 1431 | StringOrVec::String(s) => Ok(separator 1432 | .split(&s) 1433 | .into_iter() 1434 | .filter(|s| { 1435 | if skip_empty && s.is_empty() { 1436 | return false; 1437 | } 1438 | true 1439 | }) 1440 | .map(&mut parser) 1441 | .collect::, _>>() 1442 | .map_err(serde::de::Error::custom)?), 1443 | StringOrVec::Vec(v) => Ok(v), 1444 | } 1445 | } 1446 | } 1447 | 1448 | impl Pattern<'_> { 1449 | fn split<'b>(&self, input: &'b str) -> Vec<&'b str> { 1450 | match self { 1451 | Pattern::Char(c) => input.split(*c).collect(), 1452 | Pattern::Str(s) => input.split(s).collect(), 1453 | Pattern::Pred(p) => input.split(p).collect(), 1454 | Pattern::Multiple(patterns) => { 1455 | let mut split = vec![input]; 1456 | for pattern in patterns { 1457 | let delete_until = split.len(); 1458 | let mut new_split = Vec::new(); 1459 | for s in &split { 1460 | new_split.append(&mut pattern.split(s)); 1461 | } 1462 | 1463 | if !new_split.is_empty() { 1464 | split = split.split_off(delete_until); 1465 | } 1466 | 1467 | split.append(&mut new_split); 1468 | } 1469 | split 1470 | } 1471 | } 1472 | } 1473 | } 1474 | 1475 | #[cfg(test)] 1476 | mod tests { 1477 | use crate::prelude::*; 1478 | use std::{ 1479 | cell::{Cell, RefCell}, 1480 | sync::{Mutex, RwLock}, 1481 | }; 1482 | #[derive(Debug, serde::Deserialize)] 1483 | struct MyStruct { 1484 | #[serde( 1485 | default, 1486 | deserialize_with = "deserialize_cell_option_number_from_string" 1487 | )] 1488 | cell: Cell>, 1489 | #[serde( 1490 | default, 1491 | deserialize_with = "deserialize_ref_cell_option_number_from_string" 1492 | )] 1493 | ref_cell: RefCell>, 1494 | #[serde( 1495 | default, 1496 | deserialize_with = "deserialize_mutex_option_number_from_string" 1497 | )] 1498 | mutex: Mutex>, 1499 | #[serde( 1500 | default, 1501 | deserialize_with = "deserialize_rw_lock_option_number_from_string" 1502 | )] 1503 | rw_lock: RwLock>, 1504 | } 1505 | macro_rules! serde_qs_eq { 1506 | ($s:literal, $result:expr) => { 1507 | let a: MyStruct = serde_qs::from_str($s).unwrap(); 1508 | assert_eq!(a.cell, Cell::new($result)); 1509 | assert_eq!(a.ref_cell, RefCell::new($result)); 1510 | assert_eq!(*a.mutex.lock().unwrap(), $result); 1511 | assert_eq!(*a.rw_lock.read().unwrap(), $result); 1512 | }; 1513 | } 1514 | macro_rules! serde_qs_err { 1515 | ($rest:literal) => { 1516 | assert!(serde_qs::from_str::(concat!("cell", $rest)).is_err()); 1517 | assert!(serde_qs::from_str::(concat!("ref_cell", $rest)).is_err()); 1518 | assert!(serde_qs::from_str::(concat!("mutex", $rest)).is_err()); 1519 | assert!(serde_qs::from_str::(concat!("rw_lock", $rest)).is_err()); 1520 | }; 1521 | } 1522 | macro_rules! serde_json_eq { 1523 | ($s:literal, $result:expr) => { 1524 | let a: MyStruct = serde_json::from_str($s).unwrap(); 1525 | assert_eq!(a.cell, Cell::new($result)); 1526 | assert_eq!(a.ref_cell, RefCell::new($result)); 1527 | assert_eq!(*a.mutex.lock().unwrap(), $result); 1528 | assert_eq!(*a.rw_lock.read().unwrap(), $result); 1529 | }; 1530 | } 1531 | macro_rules! serde_json_err { 1532 | ($v:tt) => { 1533 | assert!(serde_json::from_str::(r#" { "cell": $v } "#).is_err()); 1534 | assert!(serde_json::from_str::(r#" { "ref_cell": $v } "#).is_err()); 1535 | assert!(serde_json::from_str::(r#" { "mutex": $v } "#).is_err()); 1536 | assert!(serde_json::from_str::(r#" { "rw_lock": $v } "#).is_err()); 1537 | }; 1538 | } 1539 | #[test] 1540 | fn test_deserialize_wrap_option_number_from_string() { 1541 | serde_qs_eq!("cell=1&ref_cell=1&mutex=1&rw_lock=1", Some(1.0)); 1542 | serde_qs_eq!("cell=-1&ref_cell=-1&mutex=-1&rw_lock=-1", Some(-1.0)); 1543 | serde_qs_eq!("cell=0.1&ref_cell=0.1&mutex=0.1&rw_lock=0.1", Some(0.1)); 1544 | serde_qs_eq!( 1545 | "cell=-0.1&ref_cell=-0.1&mutex=-0.1&rw_lock=-0.1", 1546 | Some(-0.1) 1547 | ); 1548 | serde_qs_eq!("cell=&ref_cell=&mutex=&rw_lock=", None); 1549 | serde_qs_eq!("cell&ref_cell&mutex&rw_lock", None); 1550 | 1551 | serde_qs_err!("=true"); 1552 | serde_qs_err!("=a"); 1553 | serde_qs_err!("[a]="); 1554 | serde_qs_err!("[]="); 1555 | 1556 | serde_json_eq!( 1557 | r#" { "cell":"1","ref_cell":"1","mutex":"1","rw_lock":"1" } "#, 1558 | Some(1.0) 1559 | ); 1560 | serde_json_eq!( 1561 | r#" { "cell":"-1","ref_cell":"-1","mutex":"-1","rw_lock":"-1" } "#, 1562 | Some(-1.0) 1563 | ); 1564 | serde_json_eq!( 1565 | r#" { "cell":"0.1","ref_cell":"0.1","mutex":"0.1","rw_lock":"0.1" } "#, 1566 | Some(0.1) 1567 | ); 1568 | serde_json_eq!( 1569 | r#" { "cell":"-0.1","ref_cell":"-0.1","mutex":"-0.1","rw_lock":"-0.1" } "#, 1570 | Some(-0.1) 1571 | ); 1572 | serde_json_eq!( 1573 | r#" { "cell":1,"ref_cell":1,"mutex":1,"rw_lock":1 } "#, 1574 | Some(1.0) 1575 | ); 1576 | serde_json_eq!( 1577 | r#" { "cell":-1,"ref_cell":-1,"mutex":-1,"rw_lock":-1 } "#, 1578 | Some(-1.0) 1579 | ); 1580 | serde_json_eq!( 1581 | r#" { "cell":0.1,"ref_cell":0.1,"mutex":0.1,"rw_lock":0.1 } "#, 1582 | Some(0.1) 1583 | ); 1584 | serde_json_eq!( 1585 | r#" { "cell":-0.1,"ref_cell":-0.1,"mutex":-0.1,"rw_lock":-0.1 } "#, 1586 | Some(-0.1) 1587 | ); 1588 | serde_json_eq!( 1589 | r#" { "cell":"","ref_cell":"","mutex":"","rw_lock":"" } "#, 1590 | None 1591 | ); 1592 | serde_json_eq!( 1593 | r#" { "cell":null,"ref_cell":null,"mutex":null,"rw_lock":null } "#, 1594 | None 1595 | ); 1596 | 1597 | serde_json_err!(true); 1598 | serde_json_err!("a"); 1599 | serde_json_err!({}); 1600 | serde_json_err!([]); 1601 | } 1602 | 1603 | #[derive(Debug, serde::Deserialize)] 1604 | struct TestStruct { 1605 | #[serde(default, deserialize_with = "deserialize_option_number_from_string")] 1606 | value: Option, 1607 | } 1608 | 1609 | #[test] 1610 | fn deserialize_string_variant_valid_number() { 1611 | let json = r#"{"value": "4\u0032.5"}"#; 1612 | let result: TestStruct = serde_json::from_str(json).unwrap(); 1613 | assert_eq!(result.value, Some(42.5)); 1614 | } 1615 | } 1616 | --------------------------------------------------------------------------------