serde_yaml-0.8.26/.cargo_vcs_info.json0000644000000001360000000000100132550ustar { "git": { "sha1": "c19c09da06363f1db297f97c2f9b50e4ee31d463" }, "path_in_vcs": "" }serde_yaml-0.8.26/.clippy.toml000064400000000000000000000000201046102023000143100ustar 00000000000000msrv = "1.56.0" serde_yaml-0.8.26/.github/workflows/ci.yml000064400000000000000000000032551046102023000165650ustar 00000000000000name: CI on: push: pull_request: schedule: [cron: "40 1 * * *"] env: RUSTFLAGS: -Dwarnings jobs: test: name: Rust ${{matrix.rust}} runs-on: ubuntu-latest strategy: fail-fast: false matrix: rust: [nightly, beta, stable, 1.56.0] steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} - run: cargo build - run: cargo test clippy: name: Clippy runs-on: ubuntu-latest if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic miri: name: Miri runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@miri - run: cargo miri test env: MIRIFLAGS: -Zmiri-strict-provenance minimal: name: Minimal versions runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - run: cargo update -Z minimal-versions - run: cargo check fuzz: name: Fuzz runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-fuzz - run: cargo fuzz build -O outdated: name: Outdated runs-on: ubuntu-latest if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v3 - uses: dtolnay/install@cargo-outdated - run: cargo outdated --workspace --exit-code 1 - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1 serde_yaml-0.8.26/.gitignore000064400000000000000000000000221046102023000140270ustar 00000000000000target Cargo.lock serde_yaml-0.8.26/Cargo.toml0000644000000023500000000000100112530ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56" name = "serde_yaml" version = "0.8.26" authors = ["David Tolnay "] description = "YAML support for Serde" documentation = "https://docs.rs/serde_yaml/" readme = "README.md" keywords = [ "yaml", "serde", ] categories = ["encoding"] license = "MIT OR Apache-2.0" repository = "https://github.com/dtolnay/serde-yaml" resolver = "2" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [dependencies.indexmap] version = "1.5.2" features = ["std"] [dependencies.ryu] version = "1.0" [dependencies.serde] version = "1.0.69" [dependencies.yaml-rust] version = "0.4.5" [dev-dependencies.anyhow] version = "1.0" [dev-dependencies.indoc] version = "1.0" [dev-dependencies.serde_derive] version = "1.0" serde_yaml-0.8.26/Cargo.toml.orig000064400000000000000000000012741046102023000147400ustar 00000000000000[package] name = "serde_yaml" version = "0.8.26" # remember to update html_root_url, and readme for major versions authors = ["David Tolnay "] edition = "2021" rust-version = "1.56" license = "MIT OR Apache-2.0" description = "YAML support for Serde" repository = "https://github.com/dtolnay/serde-yaml" documentation = "https://docs.rs/serde_yaml/" readme = "README.md" keywords = ["yaml", "serde"] categories = ["encoding"] [dependencies] ryu = "1.0" indexmap = { version = "1.5.2", features = ["std"] } serde = "1.0.69" yaml-rust = "0.4.5" [dev-dependencies] anyhow = "1.0" indoc = "1.0" serde_derive = "1.0" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] serde_yaml-0.8.26/LICENSE-APACHE000064400000000000000000000251371046102023000140010ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. serde_yaml-0.8.26/LICENSE-MIT000064400000000000000000000017771046102023000135150ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serde_yaml-0.8.26/README.md000064400000000000000000000057461046102023000133400ustar 00000000000000Serde YAML ========== [github](https://github.com/dtolnay/serde-yaml) [crates.io](https://crates.io/crates/serde_yaml) [docs.rs](https://docs.rs/serde_yaml) [build status](https://github.com/dtolnay/serde-yaml/actions?query=branch%3Amaster) This crate is a Rust library for using the [Serde] serialization framework with data in [YAML] file format. [Serde]: https://github.com/serde-rs/serde [YAML]: https://yaml.org/ This library does not reimplement a YAML parser; it uses [yaml-rust] which is a pure Rust YAML 1.2 implementation. [yaml-rust]: https://github.com/chyh1990/yaml-rust ## Dependency ```toml [dependencies] serde = "1.0" serde_yaml = "0.8" ``` Release notes are available under [GitHub releases]. [GitHub releases]: https://github.com/dtolnay/serde-yaml/releases ## Using Serde YAML [API documentation is available in rustdoc form][docs.rs] but the general idea is: [docs.rs]: https://docs.rs/serde_yaml ```rust use std::collections::BTreeMap; fn main() -> Result<(), serde_yaml::Error> { // You have some type. let mut map = BTreeMap::new(); map.insert("x".to_string(), 1.0); map.insert("y".to_string(), 2.0); // Serialize it to a YAML string. let s = serde_yaml::to_string(&map)?; assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); // Deserialize it back to a Rust type. let deserialized_map: BTreeMap = serde_yaml::from_str(&s)?; assert_eq!(map, deserialized_map); Ok(()) } ``` It can also be used with Serde's derive macros to handle structs and enums defined by your program. ```toml [dependencies] serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8" ``` ```rust use serde::{Serialize, Deserialize}; #[derive(Debug, PartialEq, Serialize, Deserialize)] struct Point { x: f64, y: f64, } fn main() -> Result<(), serde_yaml::Error> { let point = Point { x: 1.0, y: 2.0 }; let s = serde_yaml::to_string(&point)?; assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); let deserialized_point: Point = serde_yaml::from_str(&s)?; assert_eq!(point, deserialized_point); Ok(()) } ```
#### License Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. serde_yaml-0.8.26/src/de.rs000064400000000000000000001310001046102023000135650ustar 00000000000000use crate::error::{self, Error, ErrorImpl, Result}; use crate::path::Path; use serde::de::{ self, Deserialize, DeserializeOwned, DeserializeSeed, Expected, IgnoredAny as Ignore, IntoDeserializer, Unexpected, Visitor, }; use std::collections::BTreeMap; use std::f64; use std::fmt; use std::io; use std::marker::PhantomData; use std::mem; use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use yaml_rust::parser::{Event as YamlEvent, MarkedEventReceiver, Parser}; use yaml_rust::scanner::{Marker, TScalarStyle, TokenType}; /// A structure that deserializes YAML into Rust values. /// /// # Examples /// /// Deserializing a single document: /// /// ``` /// use anyhow::Result; /// use serde::Deserialize; /// use serde_yaml::Value; /// /// fn main() -> Result<()> { /// let input = "---\nk: 107\n"; /// let de = serde_yaml::Deserializer::from_str(input); /// let value = Value::deserialize(de)?; /// println!("{:?}", value); /// Ok(()) /// } /// ``` /// /// Deserializing multi-doc YAML: /// /// ``` /// use anyhow::Result; /// use serde::Deserialize; /// use serde_yaml::Value; /// /// fn main() -> Result<()> { /// let input = "---\nk: 107\n...\n---\nj: 106\n"; /// /// for document in serde_yaml::Deserializer::from_str(input) { /// let value = Value::deserialize(document)?; /// println!("{:?}", value); /// } /// /// Ok(()) /// } /// ``` pub struct Deserializer<'a> { input: Input<'a>, } enum Input<'a> { Str(&'a str), Slice(&'a [u8]), Read(Box), Multidoc(Arc), Fail(Arc), } impl<'a> Deserializer<'a> { /// Creates a YAML deserializer from a `&str`. pub fn from_str(s: &'a str) -> Self { let input = Input::Str(s); Deserializer { input } } /// Creates a YAML deserializer from a `&[u8]`. pub fn from_slice(v: &'a [u8]) -> Self { let input = Input::Slice(v); Deserializer { input } } /// Creates a YAML deserializer from an `io::Read`. /// /// Reader-based deserializers do not support deserializing borrowed types /// like `&str`, since the `std::io::Read` trait has no non-copying methods /// -- everything it does involves copying bytes out of the data source. pub fn from_reader(rdr: R) -> Self where R: io::Read + 'a, { let input = Input::Read(Box::new(rdr)); Deserializer { input } } fn de(self, f: impl FnOnce(&mut DeserializerFromEvents) -> Result) -> Result { if let Input::Multidoc(multidoc) = &self.input { let mut pos = multidoc.pos.load(Ordering::Relaxed); let t = f(&mut DeserializerFromEvents { events: &multidoc.loader.events, aliases: &multidoc.loader.aliases, pos: &mut pos, path: Path::Root, remaining_depth: 128, })?; multidoc.pos.store(pos, Ordering::Relaxed); return Ok(t); } let loader = loader(self.input)?; if loader.events.is_empty() { return Err(error::end_of_stream()); } let mut pos = 0; let t = f(&mut DeserializerFromEvents { events: &loader.events, aliases: &loader.aliases, pos: &mut pos, path: Path::Root, remaining_depth: 128, })?; if pos == loader.events.len() { Ok(t) } else { Err(error::more_than_one_document()) } } } fn loader(input: Input) -> Result { enum Input2<'a> { Str(&'a str), Slice(&'a [u8]), } let mut buffer; let input = match input { Input::Str(s) => Input2::Str(s), Input::Slice(bytes) => Input2::Slice(bytes), Input::Read(mut rdr) => { buffer = Vec::new(); rdr.read_to_end(&mut buffer).map_err(error::io)?; Input2::Slice(&buffer) } Input::Multidoc(_) => unreachable!(), Input::Fail(err) => return Err(error::shared(err)), }; let input = match input { Input2::Str(s) => s, Input2::Slice(bytes) => str::from_utf8(bytes).map_err(error::str_utf8)?, }; let mut parser = Parser::new(input.chars()); let mut loader = Loader { events: Vec::new(), aliases: BTreeMap::new(), }; parser.load(&mut loader, true).map_err(error::scanner)?; Ok(loader) } struct Multidoc { loader: Loader, pos: AtomicUsize, } impl<'de> Iterator for Deserializer<'de> { type Item = Self; fn next(&mut self) -> Option { match &self.input { Input::Multidoc(multidoc) => { let pos = multidoc.pos.load(Ordering::Relaxed); return if pos < multidoc.loader.events.len() { Some(Deserializer { input: Input::Multidoc(Arc::clone(multidoc)), }) } else { None }; } Input::Fail(err) => { return Some(Deserializer { input: Input::Fail(Arc::clone(err)), }); } _ => {} } let dummy = Input::Str(""); let input = mem::replace(&mut self.input, dummy); match loader(input) { Ok(loader) => { let multidoc = Arc::new(Multidoc { loader, pos: AtomicUsize::new(0), }); self.input = Input::Multidoc(Arc::clone(&multidoc)); if multidoc.loader.events.is_empty() { None } else { Some(Deserializer { input: Input::Multidoc(multidoc), }) } } Err(err) => { let fail = err.shared(); self.input = Input::Fail(Arc::clone(&fail)); Some(Deserializer { input: Input::Fail(fail), }) } } } } impl<'de> de::Deserializer<'de> for Deserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_any(visitor)) } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_bool(visitor)) } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i8(visitor)) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i16(visitor)) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i32(visitor)) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i64(visitor)) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_i128(visitor)) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u8(visitor)) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u16(visitor)) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u32(visitor)) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u64(visitor)) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_u128(visitor)) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_f32(visitor)) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_f64(visitor)) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_char(visitor)) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_str(visitor)) } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_string(visitor)) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_bytes(visitor)) } fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_byte_buf(visitor)) } fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_option(visitor)) } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_unit(visitor)) } fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_unit_struct(name, visitor)) } fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_newtype_struct(name, visitor)) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_seq(visitor)) } fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_tuple(len, visitor)) } fn deserialize_tuple_struct( self, name: &'static str, len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_tuple_struct(name, len, visitor)) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_map(visitor)) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_struct(name, fields, visitor)) } fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_enum(name, variants, visitor)) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_identifier(visitor)) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.de(|state| state.deserialize_ignored_any(visitor)) } } pub struct Loader { events: Vec<(Event, Marker)>, /// Map from alias id to index in events. aliases: BTreeMap, } impl MarkedEventReceiver for Loader { fn on_event(&mut self, event: YamlEvent, marker: Marker) { let event = match event { YamlEvent::Nothing | YamlEvent::StreamStart | YamlEvent::StreamEnd | YamlEvent::DocumentStart | YamlEvent::DocumentEnd => return, YamlEvent::Alias(id) => Event::Alias(id), YamlEvent::Scalar(value, style, id, tag) => { self.aliases.insert(id, self.events.len()); Event::Scalar(value, style, tag) } YamlEvent::SequenceStart(id) => { self.aliases.insert(id, self.events.len()); Event::SequenceStart } YamlEvent::SequenceEnd => Event::SequenceEnd, YamlEvent::MappingStart(id) => { self.aliases.insert(id, self.events.len()); Event::MappingStart } YamlEvent::MappingEnd => Event::MappingEnd, }; self.events.push((event, marker)); } } #[derive(Debug, PartialEq)] enum Event { Alias(usize), Scalar(String, TScalarStyle, Option), SequenceStart, SequenceEnd, MappingStart, MappingEnd, } struct DeserializerFromEvents<'a> { events: &'a [(Event, Marker)], /// Map from alias id to index in events. aliases: &'a BTreeMap, pos: &'a mut usize, path: Path<'a>, remaining_depth: u8, } impl<'a> DeserializerFromEvents<'a> { fn peek(&self) -> Result<(&'a Event, Marker)> { match self.events.get(*self.pos) { Some(event) => Ok((&event.0, event.1)), None => Err(error::end_of_stream()), } } fn next(&mut self) -> Result<(&'a Event, Marker)> { self.opt_next().ok_or_else(error::end_of_stream) } fn opt_next(&mut self) -> Option<(&'a Event, Marker)> { self.events.get(*self.pos).map(|event| { *self.pos += 1; (&event.0, event.1) }) } fn jump(&'a self, pos: &'a mut usize) -> Result> { match self.aliases.get(pos) { Some(&found) => { *pos = found; Ok(DeserializerFromEvents { events: self.events, aliases: self.aliases, pos, path: Path::Alias { parent: &self.path }, remaining_depth: self.remaining_depth, }) } None => panic!("unresolved alias: {}", *pos), } } fn ignore_any(&mut self) { enum Nest { Sequence, Mapping, } let mut stack = Vec::new(); while let Some((event, _)) = self.opt_next() { match event { Event::Alias(_) | Event::Scalar(_, _, _) => {} Event::SequenceStart => { stack.push(Nest::Sequence); } Event::MappingStart => { stack.push(Nest::Mapping); } Event::SequenceEnd => match stack.pop() { Some(Nest::Sequence) => {} None | Some(Nest::Mapping) => { panic!("unexpected end of sequence"); } }, Event::MappingEnd => match stack.pop() { Some(Nest::Mapping) => {} None | Some(Nest::Sequence) => { panic!("unexpected end of mapping"); } }, } if stack.is_empty() { return; } } if !stack.is_empty() { panic!("missing end event"); } } fn visit_sequence<'de, V>(&mut self, visitor: V) -> Result where V: Visitor<'de>, { let (value, len) = self.recursion_check(|de| { let mut seq = SeqAccess { de, len: 0 }; let value = visitor.visit_seq(&mut seq)?; Ok((value, seq.len)) })?; self.end_sequence(len)?; Ok(value) } fn visit_mapping<'de, V>(&mut self, visitor: V) -> Result where V: Visitor<'de>, { let (value, len) = self.recursion_check(|de| { let mut map = MapAccess { de, len: 0, key: None, }; let value = visitor.visit_map(&mut map)?; Ok((value, map.len)) })?; self.end_mapping(len)?; Ok(value) } fn end_sequence(&mut self, len: usize) -> Result<()> { let total = { let mut seq = SeqAccess { de: self, len }; while de::SeqAccess::next_element::(&mut seq)?.is_some() {} seq.len }; assert_eq!(Event::SequenceEnd, *self.next()?.0); if total == len { Ok(()) } else { struct ExpectedSeq(usize); impl Expected for ExpectedSeq { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { if self.0 == 1 { write!(formatter, "sequence of 1 element") } else { write!(formatter, "sequence of {} elements", self.0) } } } Err(de::Error::invalid_length(total, &ExpectedSeq(len))) } } fn end_mapping(&mut self, len: usize) -> Result<()> { let total = { let mut map = MapAccess { de: self, len, key: None, }; while de::MapAccess::next_entry::(&mut map)?.is_some() {} map.len }; assert_eq!(Event::MappingEnd, *self.next()?.0); if total == len { Ok(()) } else { struct ExpectedMap(usize); impl Expected for ExpectedMap { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { if self.0 == 1 { write!(formatter, "map containing 1 entry") } else { write!(formatter, "map containing {} entries", self.0) } } } Err(de::Error::invalid_length(total, &ExpectedMap(len))) } } fn recursion_check Result, T>(&mut self, f: F) -> Result { let previous_depth = self.remaining_depth; self.remaining_depth = previous_depth .checked_sub(1) .ok_or_else(error::recursion_limit_exceeded)?; let result = f(self); self.remaining_depth = previous_depth; result } } fn visit_scalar<'de, V>( v: &str, style: TScalarStyle, tag: &Option, visitor: V, ) -> Result where V: Visitor<'de>, { if let Some(TokenType::Tag(handle, suffix)) = tag { if handle == "!!" { match suffix.as_ref() { "bool" => match v.parse::() { Ok(v) => visitor.visit_bool(v), Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a boolean")), }, "int" => match v.parse::() { Ok(v) => visitor.visit_i64(v), Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"an integer")), }, "float" => match v.parse::() { Ok(v) => visitor.visit_f64(v), Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a float")), }, "null" => match v { "~" | "null" => visitor.visit_unit(), _ => Err(de::Error::invalid_value(Unexpected::Str(v), &"null")), }, _ => visitor.visit_str(v), } } else { visitor.visit_str(v) } } else if style == TScalarStyle::Plain { visit_untagged_str(visitor, v) } else { visitor.visit_str(v) } } struct SeqAccess<'a: 'r, 'r> { de: &'r mut DeserializerFromEvents<'a>, len: usize, } impl<'de, 'a, 'r> de::SeqAccess<'de> for SeqAccess<'a, 'r> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { match self.de.peek()?.0 { Event::SequenceEnd => Ok(None), _ => { let mut element_de = DeserializerFromEvents { events: self.de.events, aliases: self.de.aliases, pos: self.de.pos, path: Path::Seq { parent: &self.de.path, index: self.len, }, remaining_depth: self.de.remaining_depth, }; self.len += 1; seed.deserialize(&mut element_de).map(Some) } } } } struct MapAccess<'a: 'r, 'r> { de: &'r mut DeserializerFromEvents<'a>, len: usize, key: Option<&'a str>, } impl<'de, 'a, 'r> de::MapAccess<'de> for MapAccess<'a, 'r> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: DeserializeSeed<'de>, { match self.de.peek()?.0 { Event::MappingEnd => Ok(None), Event::Scalar(key, _, _) => { self.len += 1; self.key = Some(key); seed.deserialize(&mut *self.de).map(Some) } _ => { self.len += 1; self.key = None; seed.deserialize(&mut *self.de).map(Some) } } } fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de>, { let mut value_de = DeserializerFromEvents { events: self.de.events, aliases: self.de.aliases, pos: self.de.pos, path: if let Some(key) = self.key { Path::Map { parent: &self.de.path, key, } } else { Path::Unknown { parent: &self.de.path, } }, remaining_depth: self.de.remaining_depth, }; seed.deserialize(&mut value_de) } } struct EnumAccess<'a: 'r, 'r> { de: &'r mut DeserializerFromEvents<'a>, name: &'static str, tag: Option<&'static str>, } impl<'de, 'a, 'r> de::EnumAccess<'de> for EnumAccess<'a, 'r> { type Error = Error; type Variant = DeserializerFromEvents<'r>; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { #[derive(Debug)] enum Nope {} struct BadKey { name: &'static str, } impl<'de> Visitor<'de> for BadKey { type Value = Nope; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "variant of enum `{}`", self.name) } } let variant = if let Some(tag) = self.tag { tag } else { match self.de.next()?.0 { Event::Scalar(s, _, _) => &**s, _ => { *self.de.pos -= 1; let bad = BadKey { name: self.name }; return Err(de::Deserializer::deserialize_any(&mut *self.de, bad).unwrap_err()); } } }; let str_de = IntoDeserializer::::into_deserializer(variant); let ret = seed.deserialize(str_de)?; let variant_visitor = DeserializerFromEvents { events: self.de.events, aliases: self.de.aliases, pos: self.de.pos, path: Path::Map { parent: &self.de.path, key: variant, }, remaining_depth: self.de.remaining_depth, }; Ok((ret, variant_visitor)) } } impl<'de, 'a> de::VariantAccess<'de> for DeserializerFromEvents<'a> { type Error = Error; fn unit_variant(mut self) -> Result<()> { Deserialize::deserialize(&mut self) } fn newtype_variant_seed(mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { seed.deserialize(&mut self) } fn tuple_variant(mut self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { de::Deserializer::deserialize_seq(&mut self, visitor) } fn struct_variant(mut self, fields: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de>, { de::Deserializer::deserialize_struct(&mut self, "", fields, visitor) } } struct UnitVariantAccess<'a: 'r, 'r> { de: &'r mut DeserializerFromEvents<'a>, } impl<'de, 'a, 'r> de::EnumAccess<'de> for UnitVariantAccess<'a, 'r> { type Error = Error; type Variant = Self; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { Ok((seed.deserialize(&mut *self.de)?, self)) } } impl<'de, 'a, 'r> de::VariantAccess<'de> for UnitVariantAccess<'a, 'r> { type Error = Error; fn unit_variant(self) -> Result<()> { Ok(()) } fn newtype_variant_seed(self, _seed: T) -> Result where T: DeserializeSeed<'de>, { Err(de::Error::invalid_type( Unexpected::UnitVariant, &"newtype variant", )) } fn tuple_variant(self, _len: usize, _visitor: V) -> Result where V: Visitor<'de>, { Err(de::Error::invalid_type( Unexpected::UnitVariant, &"tuple variant", )) } fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result where V: Visitor<'de>, { Err(de::Error::invalid_type( Unexpected::UnitVariant, &"struct variant", )) } } fn visit_untagged_str<'de, V>(visitor: V, v: &str) -> Result where V: Visitor<'de>, { if v == "~" || v == "null" { return visitor.visit_unit(); } if v == "true" { return visitor.visit_bool(true); } if v == "false" { return visitor.visit_bool(false); } if let Some(rest) = Option::or(v.strip_prefix("0x"), v.strip_prefix("+0x")) { if let Ok(n) = u64::from_str_radix(rest, 16) { return visitor.visit_u64(n); } } if let Some(rest) = v.strip_prefix("-0x") { let negative = format!("-{}", rest); if let Ok(n) = i64::from_str_radix(&negative, 16) { return visitor.visit_i64(n); } } if let Some(rest) = Option::or(v.strip_prefix("0o"), v.strip_prefix("+0o")) { if let Ok(n) = u64::from_str_radix(rest, 8) { return visitor.visit_u64(n); } } if let Some(rest) = v.strip_prefix("-0o") { let negative = format!("-{}", rest); if let Ok(n) = i64::from_str_radix(&negative, 8) { return visitor.visit_i64(n); } } if let Some(rest) = Option::or(v.strip_prefix("0b"), v.strip_prefix("+0b")) { if let Ok(n) = u64::from_str_radix(rest, 2) { return visitor.visit_u64(n); } } if let Some(rest) = v.strip_prefix("-0b") { let negative = format!("-{}", rest); if let Ok(n) = i64::from_str_radix(&negative, 2) { return visitor.visit_i64(n); } } if { let v = v.trim_start_matches(&['-', '+'][..]); v.len() > 1 && v.starts_with('0') && v[1..].bytes().all(|b| b.is_ascii_digit()) } { // After handling the different number encodings above if we are left // with leading zero(s) followed by numeric characters this is in fact a // string according to the YAML 1.2 spec. // https://yaml.org/spec/1.2/spec.html#id2761292 return visitor.visit_str(v); } if let Ok(n) = v.parse() { return visitor.visit_u64(n); } if let Ok(n) = v.parse() { return visitor.visit_u128(n); } if let Ok(n) = v.parse() { return visitor.visit_i64(n); } if let Ok(n) = v.parse() { return visitor.visit_i128(n); } match v.trim_start_matches('+') { ".inf" | ".Inf" | ".INF" => return visitor.visit_f64(f64::INFINITY), _ => (), } if v == "-.inf" || v == "-.Inf" || v == "-.INF" { return visitor.visit_f64(f64::NEG_INFINITY); } if v == ".nan" || v == ".NaN" || v == ".NAN" { return visitor.visit_f64(f64::NAN); } if let Ok(n) = v.parse::() { if n.is_finite() { return visitor.visit_f64(n); } } visitor.visit_str(v) } fn invalid_type(event: &Event, exp: &dyn Expected) -> Error { enum Void {} struct InvalidType<'a> { exp: &'a dyn Expected, } impl<'de, 'a> Visitor<'de> for InvalidType<'a> { type Value = Void; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { self.exp.fmt(formatter) } } match event { Event::Alias(_) => unreachable!(), Event::Scalar(v, style, tag) => { let get_type = InvalidType { exp }; match visit_scalar(v, *style, tag, get_type) { Ok(void) => match void {}, Err(invalid_type) => invalid_type, } } Event::SequenceStart => de::Error::invalid_type(Unexpected::Seq, exp), Event::MappingStart => de::Error::invalid_type(Unexpected::Map, exp), Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), } } impl<'a> DeserializerFromEvents<'a> { fn deserialize_scalar<'de, V>(&mut self, visitor: V) -> Result where V: Visitor<'de>, { let (next, marker) = self.next()?; match next { Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_scalar(visitor), Event::Scalar(v, style, tag) => visit_scalar(v, *style, tag, visitor), other => Err(invalid_type(other, &visitor)), } .map_err(|err| error::fix_marker(err, marker, self.path)) } } impl<'de, 'a, 'r> de::Deserializer<'de> for &'r mut DeserializerFromEvents<'a> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, marker) = self.next()?; match next { Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_any(visitor), Event::Scalar(v, style, tag) => visit_scalar(v, *style, tag, visitor), Event::SequenceStart => self.visit_sequence(visitor), Event::MappingStart => self.visit_mapping(visitor), Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), } // The de::Error impl creates errors with unknown line and column. Fill // in the position here by looking at the current index in the input. .map_err(|err| error::fix_marker(err, marker, self.path)) } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, marker) = self.next()?; match next { Event::Scalar(v, _, _) => visitor.visit_str(v), Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_str(visitor), other => Err(invalid_type(other, &visitor)), } .map_err(|err: Error| error::fix_marker(err, marker, self.path)) } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_any(visitor) } fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_bytes(visitor) } /// Parses `null` as None and any other values as `Some(...)`. fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { let is_some = match self.peek()?.0 { Event::Alias(mut pos) => { *self.pos += 1; return self.jump(&mut pos)?.deserialize_option(visitor); } Event::Scalar(v, style, tag) => { if *style != TScalarStyle::Plain { true } else if let Some(TokenType::Tag(handle, suffix)) = tag { if handle == "!!" && suffix == "null" { if v == "~" || v == "null" { false } else { return Err(de::Error::invalid_value(Unexpected::Str(v), &"null")); } } else { true } } else { v != "~" && v != "null" } } Event::SequenceStart | Event::MappingStart => true, Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), }; if is_some { visitor.visit_some(self) } else { *self.pos += 1; visitor.visit_none() } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_scalar(visitor) } fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } /// Parses a newtype struct as the underlying value. fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, marker) = self.next()?; match next { Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_seq(visitor), Event::SequenceStart => self.visit_sequence(visitor), other => Err(invalid_type(other, &visitor)), } .map_err(|err| error::fix_marker(err, marker, self.path)) } fn deserialize_tuple(self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_tuple_struct( self, _name: &'static str, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { let (next, marker) = self.next()?; match next { Event::Alias(mut pos) => self.jump(&mut pos)?.deserialize_map(visitor), Event::MappingStart => self.visit_mapping(visitor), other => Err(invalid_type(other, &visitor)), } .map_err(|err| error::fix_marker(err, marker, self.path)) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let (next, marker) = self.next()?; match next { Event::Alias(mut pos) => self .jump(&mut pos)? .deserialize_struct(name, fields, visitor), Event::SequenceStart => self.visit_sequence(visitor), Event::MappingStart => self.visit_mapping(visitor), other => Err(invalid_type(other, &visitor)), } .map_err(|err| error::fix_marker(err, marker, self.path)) } /// Parses an enum as a single key:value pair where the key identifies the /// variant and the value gives the content. A String will also parse correctly /// to a unit enum value. fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let (next, marker) = self.peek()?; match next { Event::Alias(mut pos) => { *self.pos += 1; self.jump(&mut pos)? .deserialize_enum(name, variants, visitor) } Event::Scalar(_, _, t) => { if let Some(TokenType::Tag(handle, suffix)) = t { if handle == "!" { if let Some(tag) = variants.iter().find(|v| *v == suffix) { return visitor.visit_enum(EnumAccess { de: self, name, tag: Some(tag), }); } } } visitor.visit_enum(UnitVariantAccess { de: self }) } Event::MappingStart => { *self.pos += 1; let value = visitor.visit_enum(EnumAccess { de: self, name, tag: None, })?; self.end_mapping(1)?; Ok(value) } Event::SequenceStart => { let err = de::Error::invalid_type(Unexpected::Seq, &"string or singleton map"); Err(error::fix_marker(err, marker, self.path)) } Event::SequenceEnd => panic!("unexpected end of sequence"), Event::MappingEnd => panic!("unexpected end of mapping"), } } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.ignore_any(); visitor.visit_unit() } } /// Deserialize an instance of type `T` from a string of YAML text. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. /// /// YAML currently does not support zero-copy deserialization. pub fn from_str(s: &str) -> Result where T: DeserializeOwned, { from_str_seed(s, PhantomData) } /// Deserialize an instance of type `T` from a string of YAML text with a seed. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. /// /// YAML currently does not support zero-copy deserialization. pub fn from_str_seed(s: &str, seed: S) -> Result where S: for<'de> DeserializeSeed<'de, Value = T>, { seed.deserialize(Deserializer::from_str(s)) } /// Deserialize an instance of type `T` from an IO stream of YAML. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. pub fn from_reader(rdr: R) -> Result where R: io::Read, T: DeserializeOwned, { from_reader_seed(rdr, PhantomData) } /// Deserialize an instance of type `T` from an IO stream of YAML with a seed. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. pub fn from_reader_seed(rdr: R, seed: S) -> Result where R: io::Read, S: for<'de> DeserializeSeed<'de, Value = T>, { seed.deserialize(Deserializer::from_reader(rdr)) } /// Deserialize an instance of type `T` from bytes of YAML text. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. /// /// YAML currently does not support zero-copy deserialization. pub fn from_slice(v: &[u8]) -> Result where T: DeserializeOwned, { from_slice_seed(v, PhantomData) } /// Deserialize an instance of type `T` from bytes of YAML text with a seed. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. /// /// YAML currently does not support zero-copy deserialization. pub fn from_slice_seed(v: &[u8], seed: S) -> Result where S: for<'de> DeserializeSeed<'de, Value = T>, { seed.deserialize(Deserializer::from_slice(v)) } serde_yaml-0.8.26/src/error.rs000064400000000000000000000163041046102023000143370ustar 00000000000000use crate::path::Path; use serde::{de, ser}; use std::error; use std::fmt::{self, Debug, Display}; use std::io; use std::result; use std::str; use std::string; use std::sync::Arc; use yaml_rust::emitter; use yaml_rust::scanner::{self, Marker, ScanError}; /// An error that happened serializing or deserializing YAML data. pub struct Error(Box); /// Alias for a `Result` with the error type `serde_yaml::Error`. pub type Result = result::Result; #[derive(Debug)] pub enum ErrorImpl { Message(String, Option), Emit(emitter::EmitError), Scan(scanner::ScanError), Io(io::Error), Utf8(str::Utf8Error), FromUtf8(string::FromUtf8Error), EndOfStream, MoreThanOneDocument, RecursionLimitExceeded, Shared(Arc), } #[derive(Debug)] pub struct Pos { marker: Marker, path: String, } /// The input location that an error occured. #[derive(Debug)] pub struct Location { index: usize, line: usize, column: usize, } impl Location { /// The byte index of the error pub fn index(&self) -> usize { self.index } /// The line of the error pub fn line(&self) -> usize { self.line } /// The column of the error pub fn column(&self) -> usize { self.column } // This is to keep decoupled with the yaml crate #[doc(hidden)] fn from_marker(marker: &Marker) -> Self { Location { // `col` returned from the `yaml` crate is 0-indexed but all error messages add + 1 to this value column: marker.col() + 1, index: marker.index(), line: marker.line(), } } } impl Error { /// Returns the Location from the error if one exists. /// /// Not all types of errors have a location so this can return `None`. /// /// # Examples /// /// ``` /// # use serde_yaml::{Value, Error}; /// # /// // The `@` character as the first character makes this invalid yaml /// let invalid_yaml: Result = serde_yaml::from_str("@invalid_yaml"); /// /// let location = invalid_yaml.unwrap_err().location().unwrap(); /// /// assert_eq!(location.line(), 1); /// assert_eq!(location.column(), 1); /// ``` pub fn location(&self) -> Option { match self.0.as_ref() { ErrorImpl::Message(_, Some(pos)) => Some(Location::from_marker(&pos.marker)), ErrorImpl::Scan(scan) => Some(Location::from_marker(scan.marker())), _ => None, } } } pub(crate) fn end_of_stream() -> Error { Error(Box::new(ErrorImpl::EndOfStream)) } pub(crate) fn more_than_one_document() -> Error { Error(Box::new(ErrorImpl::MoreThanOneDocument)) } pub(crate) fn io(err: io::Error) -> Error { Error(Box::new(ErrorImpl::Io(err))) } pub(crate) fn emitter(err: emitter::EmitError) -> Error { Error(Box::new(ErrorImpl::Emit(err))) } pub(crate) fn scanner(err: scanner::ScanError) -> Error { Error(Box::new(ErrorImpl::Scan(err))) } pub(crate) fn str_utf8(err: str::Utf8Error) -> Error { Error(Box::new(ErrorImpl::Utf8(err))) } pub(crate) fn string_utf8(err: string::FromUtf8Error) -> Error { Error(Box::new(ErrorImpl::FromUtf8(err))) } pub(crate) fn recursion_limit_exceeded() -> Error { Error(Box::new(ErrorImpl::RecursionLimitExceeded)) } pub(crate) fn shared(shared: Arc) -> Error { Error(Box::new(ErrorImpl::Shared(shared))) } pub(crate) fn fix_marker(mut error: Error, marker: Marker, path: Path) -> Error { if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() { *none = Some(Pos { marker, path: path.to_string(), }); } error } impl Error { pub(crate) fn shared(self) -> Arc { if let ErrorImpl::Shared(err) = *self.0 { err } else { Arc::from(self.0) } } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { self.0.source() } } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.display(f) } } // Remove two layers of verbosity from the debug representation. Humans often // end up seeing this representation because it is what unwrap() shows. impl Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.debug(f) } } impl ser::Error for Error { fn custom(msg: T) -> Self { Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) } } impl de::Error for Error { fn custom(msg: T) -> Self { Error(Box::new(ErrorImpl::Message(msg.to_string(), None))) } } impl ErrorImpl { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { ErrorImpl::Scan(err) => Some(err), ErrorImpl::Io(err) => Some(err), ErrorImpl::Utf8(err) => Some(err), ErrorImpl::FromUtf8(err) => Some(err), ErrorImpl::Shared(err) => err.source(), _ => None, } } fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { ErrorImpl::Message(msg, None) => Display::fmt(msg, f), ErrorImpl::Message(msg, Some(Pos { marker, path })) => { if path == "." { write!(f, "{}", ScanError::new(*marker, msg)) } else { write!(f, "{}: {}", path, ScanError::new(*marker, msg)) } } ErrorImpl::Emit(emitter::EmitError::FmtError(_)) => f.write_str("yaml-rust fmt error"), ErrorImpl::Emit(emitter::EmitError::BadHashmapKey) => f.write_str("bad hash map key"), ErrorImpl::Scan(err) => Display::fmt(err, f), ErrorImpl::Io(err) => Display::fmt(err, f), ErrorImpl::Utf8(err) => Display::fmt(err, f), ErrorImpl::FromUtf8(err) => Display::fmt(err, f), ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"), ErrorImpl::MoreThanOneDocument => f.write_str( "deserializing from YAML containing more than one document is not supported", ), ErrorImpl::RecursionLimitExceeded => f.write_str("recursion limit exceeded"), ErrorImpl::Shared(err) => err.display(f), } } fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { ErrorImpl::Message(msg, pos) => f.debug_tuple("Message").field(msg).field(pos).finish(), ErrorImpl::Emit(emit) => f.debug_tuple("Emit").field(emit).finish(), ErrorImpl::Scan(scan) => f.debug_tuple("Scan").field(scan).finish(), ErrorImpl::Io(io) => f.debug_tuple("Io").field(io).finish(), ErrorImpl::Utf8(utf8) => f.debug_tuple("Utf8").field(utf8).finish(), ErrorImpl::FromUtf8(from_utf8) => f.debug_tuple("FromUtf8").field(from_utf8).finish(), ErrorImpl::EndOfStream => f.debug_tuple("EndOfStream").finish(), ErrorImpl::MoreThanOneDocument => f.debug_tuple("MoreThanOneDocument").finish(), ErrorImpl::RecursionLimitExceeded => f.debug_tuple("RecursionLimitExceeded").finish(), ErrorImpl::Shared(err) => err.debug(f), } } } serde_yaml-0.8.26/src/lib.rs000064400000000000000000000100151046102023000137450ustar 00000000000000//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml) //! //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs //! //!
//! //! This crate is a Rust library for using the [Serde] serialization framework //! with data in [YAML] file format. //! //! This library does not reimplement a YAML parser; it uses [yaml-rust] which //! is a pure Rust YAML 1.2 implementation. //! //! [Serde]: https://github.com/serde-rs/serde //! [YAML]: https://yaml.org/ //! [yaml-rust]: https://github.com/chyh1990/yaml-rust //! //! # Examples //! //! ``` //! use std::collections::BTreeMap; //! //! fn main() -> Result<(), serde_yaml::Error> { //! // You have some type. //! let mut map = BTreeMap::new(); //! map.insert("x".to_string(), 1.0); //! map.insert("y".to_string(), 2.0); //! //! // Serialize it to a YAML string. //! let s = serde_yaml::to_string(&map)?; //! assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); //! //! // Deserialize it back to a Rust type. //! let deserialized_map: BTreeMap = serde_yaml::from_str(&s)?; //! assert_eq!(map, deserialized_map); //! Ok(()) //! } //! ``` //! //! ## Using Serde derive //! //! It can also be used with Serde's serialization code generator `serde_derive` to //! handle structs and enums defined in your own program. //! //! ``` //! # use serde_derive::{Serialize, Deserialize}; //! use serde::{Serialize, Deserialize}; //! //! #[derive(Debug, PartialEq, Serialize, Deserialize)] //! struct Point { //! x: f64, //! y: f64, //! } //! //! fn main() -> Result<(), serde_yaml::Error> { //! let point = Point { x: 1.0, y: 2.0 }; //! //! let s = serde_yaml::to_string(&point)?; //! assert_eq!(s, "---\nx: 1.0\ny: 2.0\n"); //! //! let deserialized_point: Point = serde_yaml::from_str(&s)?; //! assert_eq!(point, deserialized_point); //! Ok(()) //! } //! ``` #![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.26")] #![deny(missing_docs)] // Suppressed clippy_pedantic lints #![allow( // buggy clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285 clippy::question_mark, // https://github.com/rust-lang/rust-clippy/issues/7859 // private Deserializer::next clippy::should_implement_trait, // things are often more readable this way clippy::cast_lossless, clippy::checked_conversions, clippy::if_not_else, clippy::manual_assert, clippy::match_like_matches_macro, clippy::match_same_arms, clippy::module_name_repetitions, clippy::needless_pass_by_value, clippy::option_if_let_else, clippy::redundant_else, clippy::single_match_else, // code is acceptable clippy::blocks_in_if_conditions, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::derive_partial_eq_without_eq, clippy::doc_markdown, clippy::items_after_statements, clippy::return_self_not_must_use, // noisy clippy::missing_errors_doc, clippy::must_use_candidate, )] pub use crate::de::{from_reader, from_slice, from_str, Deserializer}; pub use crate::error::{Error, Location, Result}; pub use crate::ser::{to_string, to_vec, to_writer, Serializer}; pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value}; #[doc(inline)] pub use crate::mapping::Mapping; /// Entry points for deserializing with pre-existing state. /// /// These functions are only exposed this way because we don't yet expose a /// Deserializer type. Data formats that have a public Deserializer should not /// copy these signatures. pub mod seed { pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed}; } mod de; mod error; pub mod mapping; mod number; mod path; mod ser; mod value; serde_yaml-0.8.26/src/mapping.rs000064400000000000000000000352641046102023000146470ustar 00000000000000//! A YAML mapping and its iterator types. use crate::Value; use indexmap::IndexMap; use serde::{Deserialize, Deserializer, Serialize}; use std::cmp::Ordering; use std::collections::hash_map::DefaultHasher; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::ops::{Index, IndexMut}; /// A YAML mapping in which the keys and values are both `serde_yaml::Value`. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Mapping { map: IndexMap, } impl Mapping { /// Creates an empty YAML map. #[inline] pub fn new() -> Self { Self::default() } /// Creates an empty YAML map with the given initial capacity. #[inline] pub fn with_capacity(capacity: usize) -> Self { Mapping { map: IndexMap::with_capacity(capacity), } } /// Reserves capacity for at least `additional` more elements to be inserted /// into the map. The map may reserve more space to avoid frequent /// allocations. /// /// # Panics /// /// Panics if the new allocation size overflows `usize`. #[inline] pub fn reserve(&mut self, additional: usize) { self.map.reserve(additional); } /// Shrinks the capacity of the map as much as possible. It will drop down /// as much as possible while maintaining the internal rules and possibly /// leaving some space in accordance with the resize policy. #[inline] pub fn shrink_to_fit(&mut self) { self.map.shrink_to_fit(); } /// Inserts a key-value pair into the map. If the key already existed, the /// old value is returned. #[inline] pub fn insert(&mut self, k: Value, v: Value) -> Option { self.map.insert(k, v) } /// Checks if the map contains the given key. #[inline] pub fn contains_key(&self, k: &Value) -> bool { self.map.contains_key(k) } /// Returns the value corresponding to the key in the map. #[inline] pub fn get(&self, k: &Value) -> Option<&Value> { self.map.get(k) } /// Returns the mutable reference corresponding to the key in the map. #[inline] pub fn get_mut(&mut self, k: &Value) -> Option<&mut Value> { self.map.get_mut(k) } /// Gets the given key’s corresponding entry in the map for insertion and/or /// in-place manipulation. #[inline] pub fn entry(&mut self, k: Value) -> Entry { match self.map.entry(k) { indexmap::map::Entry::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }), indexmap::map::Entry::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }), } } /// Removes and returns the value corresponding to the key from the map. #[inline] pub fn remove(&mut self, k: &Value) -> Option { self.map.remove(k) } /// Returns the maximum number of key-value pairs the map can hold without /// reallocating. #[inline] pub fn capacity(&self) -> usize { self.map.capacity() } /// Returns the number of key-value pairs in the map. #[inline] pub fn len(&self) -> usize { self.map.len() } /// Returns whether the map is currently empty. #[inline] pub fn is_empty(&self) -> bool { self.map.is_empty() } /// Clears the map of all key-value pairs. #[inline] pub fn clear(&mut self) { self.map.clear(); } /// Returns a double-ended iterator visiting all key-value pairs in order of /// insertion. Iterator element type is `(&'a Value, &'a Value)`. #[inline] pub fn iter(&self) -> Iter { Iter { iter: self.map.iter(), } } /// Returns a double-ended iterator visiting all key-value pairs in order of /// insertion. Iterator element type is `(&'a Value, &'a mut ValuE)`. #[inline] pub fn iter_mut(&mut self) -> IterMut { IterMut { iter: self.map.iter_mut(), } } } #[allow(clippy::derive_hash_xor_eq)] impl Hash for Mapping { fn hash(&self, state: &mut H) { // Hash the kv pairs in a way that is not sensitive to their order. let mut xor = 0; for (k, v) in self { let mut hasher = DefaultHasher::new(); k.hash(&mut hasher); v.hash(&mut hasher); xor ^= hasher.finish(); } xor.hash(state); } } impl PartialOrd for Mapping { fn partial_cmp(&self, other: &Self) -> Option { let mut self_entries = Vec::from_iter(self); let mut other_entries = Vec::from_iter(other); // Sort in an arbitrary order that is consistent with Value's PartialOrd // impl. fn total_cmp(a: &Value, b: &Value) -> Ordering { match (a, b) { (Value::Null, Value::Null) => Ordering::Equal, (Value::Null, _) => Ordering::Less, (_, Value::Null) => Ordering::Greater, (Value::Bool(a), Value::Bool(b)) => a.cmp(b), (Value::Bool(_), _) => Ordering::Less, (_, Value::Bool(_)) => Ordering::Greater, (Value::Number(a), Value::Number(b)) => a.total_cmp(b), (Value::Number(_), _) => Ordering::Less, (_, Value::Number(_)) => Ordering::Greater, (Value::String(a), Value::String(b)) => a.cmp(b), (Value::String(_), _) => Ordering::Less, (_, Value::String(_)) => Ordering::Greater, (Value::Sequence(a), Value::Sequence(b)) => iter_cmp_by(a, b, total_cmp), (Value::Sequence(_), _) => Ordering::Less, (_, Value::Sequence(_)) => Ordering::Greater, (Value::Mapping(a), Value::Mapping(b)) => { iter_cmp_by(a, b, |(ak, av), (bk, bv)| { total_cmp(ak, bk).then_with(|| total_cmp(av, bv)) }) } } } fn iter_cmp_by(this: I, other: I, mut cmp: F) -> Ordering where I: IntoIterator, F: FnMut(I::Item, I::Item) -> Ordering, { let mut this = this.into_iter(); let mut other = other.into_iter(); loop { let x = match this.next() { None => { if other.next().is_none() { return Ordering::Equal; } else { return Ordering::Less; } } Some(val) => val, }; let y = match other.next() { None => return Ordering::Greater, Some(val) => val, }; match cmp(x, y) { Ordering::Equal => {} non_eq => return non_eq, } } } // While sorting by map key, we get to assume that no two keys are // equal, otherwise they wouldn't both be in the map. This is not a safe // assumption outside of this situation. let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b); self_entries.sort_by(total_cmp); other_entries.sort_by(total_cmp); self_entries.partial_cmp(&other_entries) } } impl<'a> Index<&'a Value> for Mapping { type Output = Value; #[inline] fn index(&self, index: &'a Value) -> &Value { self.map.index(index) } } impl<'a> IndexMut<&'a Value> for Mapping { #[inline] fn index_mut(&mut self, index: &'a Value) -> &mut Value { self.map.index_mut(index) } } impl Extend<(Value, Value)> for Mapping { #[inline] fn extend>(&mut self, iter: I) { self.map.extend(iter); } } impl FromIterator<(Value, Value)> for Mapping { #[inline] fn from_iter>(iter: I) -> Self { Mapping { map: IndexMap::from_iter(iter), } } } macro_rules! delegate_iterator { (($name:ident $($generics:tt)*) => $item:ty) => { impl $($generics)* Iterator for $name $($generics)* { type Item = $item; #[inline] fn next(&mut self) -> Option { self.iter.next() } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl $($generics)* ExactSizeIterator for $name $($generics)* { #[inline] fn len(&self) -> usize { self.iter.len() } } } } /// Iterator over `&serde_yaml::Mapping`. pub struct Iter<'a> { iter: indexmap::map::Iter<'a, Value, Value>, } delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value)); impl<'a> IntoIterator for &'a Mapping { type Item = (&'a Value, &'a Value); type IntoIter = Iter<'a>; #[inline] fn into_iter(self) -> Self::IntoIter { Iter { iter: self.map.iter(), } } } /// Iterator over `&mut serde_yaml::Mapping`. pub struct IterMut<'a> { iter: indexmap::map::IterMut<'a, Value, Value>, } delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value)); impl<'a> IntoIterator for &'a mut Mapping { type Item = (&'a Value, &'a mut Value); type IntoIter = IterMut<'a>; #[inline] fn into_iter(self) -> Self::IntoIter { IterMut { iter: self.map.iter_mut(), } } } /// Iterator over `serde_yaml::Mapping` by value. pub struct IntoIter { iter: indexmap::map::IntoIter, } delegate_iterator!((IntoIter) => (Value, Value)); impl IntoIterator for Mapping { type Item = (Value, Value); type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter { iter: self.map.into_iter(), } } } /// Entry for an existing key-value pair or a vacant location to insert one. pub enum Entry<'a> { /// Existing slot with equivalent key. Occupied(OccupiedEntry<'a>), /// Vacant slot (no equivalent key in the map). Vacant(VacantEntry<'a>), } /// A view into an occupied entry in a [`Mapping`]. It is part of the [`Entry`] /// enum. pub struct OccupiedEntry<'a> { occupied: indexmap::map::OccupiedEntry<'a, Value, Value>, } /// A view into a vacant entry in a [`Mapping`]. It is part of the [`Entry`] /// enum. pub struct VacantEntry<'a> { vacant: indexmap::map::VacantEntry<'a, Value, Value>, } impl<'a> Entry<'a> { /// Returns a reference to this entry's key. pub fn key(&self) -> &Value { match self { Entry::Vacant(e) => e.key(), Entry::Occupied(e) => e.key(), } } /// Ensures a value is in the entry by inserting the default if empty, and /// returns a mutable reference to the value in the entry. pub fn or_insert(self, default: Value) -> &'a mut Value { match self { Entry::Vacant(entry) => entry.insert(default), Entry::Occupied(entry) => entry.into_mut(), } } /// Ensures a value is in the entry by inserting the result of the default /// function if empty, and returns a mutable reference to the value in the /// entry. pub fn or_insert_with(self, default: F) -> &'a mut Value where F: FnOnce() -> Value, { match self { Entry::Vacant(entry) => entry.insert(default()), Entry::Occupied(entry) => entry.into_mut(), } } /// Provides in-place mutable access to an occupied entry before any /// potential inserts into the map. pub fn and_modify(self, f: F) -> Self where F: FnOnce(&mut Value), { match self { Entry::Occupied(mut entry) => { f(entry.get_mut()); Entry::Occupied(entry) } Entry::Vacant(entry) => Entry::Vacant(entry), } } } impl<'a> OccupiedEntry<'a> { /// Gets a reference to the key in the entry. #[inline] pub fn key(&self) -> &Value { self.occupied.key() } /// Gets a reference to the value in the entry. #[inline] pub fn get(&self) -> &Value { self.occupied.get() } /// Gets a mutable reference to the value in the entry. #[inline] pub fn get_mut(&mut self) -> &mut Value { self.occupied.get_mut() } /// Converts the entry into a mutable reference to its value. #[inline] pub fn into_mut(self) -> &'a mut Value { self.occupied.into_mut() } /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns /// the entry's old value. #[inline] pub fn insert(&mut self, value: Value) -> Value { self.occupied.insert(value) } /// Takes the value of the entry out of the map, and returns it. #[inline] pub fn remove(self) -> Value { self.occupied.swap_remove() } } impl<'a> VacantEntry<'a> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. #[inline] pub fn key(&self) -> &Value { self.vacant.key() } /// Sets the value of the entry with the VacantEntry's key, and returns a /// mutable reference to it. #[inline] pub fn insert(self, value: Value) -> &'a mut Value { self.vacant.insert(value) } } impl Serialize for Mapping { #[inline] fn serialize(&self, serializer: S) -> Result { use serde::ser::SerializeMap; let mut map_serializer = serializer.serialize_map(Some(self.len()))?; for (k, v) in self { map_serializer.serialize_entry(k, v)?; } map_serializer.end() } } impl<'de> Deserialize<'de> for Mapping { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct Visitor; impl<'de> serde::de::Visitor<'de> for Visitor { type Value = Mapping; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a YAML mapping") } #[inline] fn visit_unit(self) -> Result where E: serde::de::Error, { Ok(Mapping::new()) } #[inline] fn visit_map(self, mut visitor: V) -> Result where V: serde::de::MapAccess<'de>, { let mut values = Mapping::new(); while let Some((k, v)) = visitor.next_entry()? { values.insert(k, v); } Ok(values) } } deserializer.deserialize_map(Visitor) } } serde_yaml-0.8.26/src/number.rs000064400000000000000000000357501046102023000145040ustar 00000000000000use crate::Error; use serde::de::{Unexpected, Visitor}; use serde::{forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer}; use std::cmp::Ordering; use std::fmt::{self, Debug, Display}; use std::hash::{Hash, Hasher}; use std::i64; /// Represents a YAML number, whether integer or floating point. #[derive(Clone, PartialEq, PartialOrd)] pub struct Number { n: N, } // "N" is a prefix of "NegInt"... this is a false positive. // https://github.com/Manishearth/rust-clippy/issues/1241 #[allow(clippy::enum_variant_names)] #[derive(Copy, Clone, Debug)] enum N { PosInt(u64), /// Always less than zero. NegInt(i64), /// May be infinite or NaN. Float(f64), } impl Number { /// Returns true if the `Number` is an integer between `i64::MIN` and /// `i64::MAX`. /// /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to /// return the integer value. /// /// ``` /// # use std::i64; /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let big = i64::MAX as u64 + 10; /// let v = yaml(r#" /// a: 64 /// b: 9223372036854775817 /// c: 256.0 /// "#); /// /// assert!(v["a"].is_i64()); /// /// // Greater than i64::MAX. /// assert!(!v["b"].is_i64()); /// /// // Numbers with a decimal point are not considered integers. /// assert!(!v["c"].is_i64()); /// ``` #[inline] #[allow(clippy::cast_sign_loss)] pub fn is_i64(&self) -> bool { match self.n { N::PosInt(v) => v <= i64::max_value() as u64, N::NegInt(_) => true, N::Float(_) => false, } } /// Returns true if the `Number` is an integer between zero and `u64::MAX`. /// /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to /// return the integer value. /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let v = yaml(r#" /// a: 64 /// b: -64 /// c: 256.0 /// "#); /// /// assert!(v["a"].is_u64()); /// /// // Negative integer. /// assert!(!v["b"].is_u64()); /// /// // Numbers with a decimal point are not considered integers. /// assert!(!v["c"].is_u64()); /// ``` #[inline] pub fn is_u64(&self) -> bool { match self.n { N::PosInt(_) => true, N::NegInt(_) | N::Float(_) => false, } } /// Returns true if the `Number` can be represented by f64. /// /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to /// return the floating point value. /// /// Currently this function returns true if and only if both `is_i64` and /// `is_u64` return false but this is not a guarantee in the future. /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let v = yaml(r#" /// --- /// a: 256.0 /// b: 64 /// c: -64 /// "#); /// /// assert!(v["a"].is_f64()); /// /// // Integers. /// assert!(!v["b"].is_f64()); /// assert!(!v["c"].is_f64()); /// ``` #[inline] pub fn is_f64(&self) -> bool { match self.n { N::Float(_) => true, N::PosInt(_) | N::NegInt(_) => false, } } /// If the `Number` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// /// ``` /// # use std::i64; /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let big = i64::MAX as u64 + 10; /// let v = yaml(r#" /// --- /// a: 64 /// b: 9223372036854775817 /// c: 256.0 /// "#); /// /// assert_eq!(v["a"].as_i64(), Some(64)); /// assert_eq!(v["b"].as_i64(), None); /// assert_eq!(v["c"].as_i64(), None); /// ``` #[inline] pub fn as_i64(&self) -> Option { match self.n { N::PosInt(n) => { if n <= i64::max_value() as u64 { Some(n as i64) } else { None } } N::NegInt(n) => Some(n), N::Float(_) => None, } } /// If the `Number` is an integer, represent it as u64 if possible. Returns /// None otherwise. /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let v = yaml(r#" /// --- /// a: 64 /// b: -64 /// c: 256.0 /// "#); /// /// assert_eq!(v["a"].as_u64(), Some(64)); /// assert_eq!(v["b"].as_u64(), None); /// assert_eq!(v["c"].as_u64(), None); /// ``` #[inline] pub fn as_u64(&self) -> Option { match self.n { N::PosInt(n) => Some(n), N::NegInt(_) | N::Float(_) => None, } } /// Represents the number as f64 if possible. Returns None otherwise. /// /// ``` /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// let v = yaml(r#" /// --- /// a: 256.0 /// b: 64 /// c: -64 /// "#); /// /// assert_eq!(v["a"].as_f64(), Some(256.0)); /// assert_eq!(v["b"].as_f64(), Some(64.0)); /// assert_eq!(v["c"].as_f64(), Some(-64.0)); /// ``` /// /// ``` /// # use std::f64; /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// assert_eq!(yaml(".inf").as_f64(), Some(f64::INFINITY)); /// assert_eq!(yaml("-.inf").as_f64(), Some(f64::NEG_INFINITY)); /// assert!(yaml(".nan").as_f64().unwrap().is_nan()); /// ``` #[inline] pub fn as_f64(&self) -> Option { match self.n { N::PosInt(n) => Some(n as f64), N::NegInt(n) => Some(n as f64), N::Float(n) => Some(n), } } /// Returns true if this value is NaN and false otherwise. /// /// ``` /// # use std::f64; /// # /// # use serde_yaml::Number; /// # /// assert!(!Number::from(256.0).is_nan()); /// /// assert!(Number::from(f64::NAN).is_nan()); /// /// assert!(!Number::from(f64::INFINITY).is_nan()); /// /// assert!(!Number::from(f64::NEG_INFINITY).is_nan()); /// /// assert!(!Number::from(1).is_nan()); /// ``` #[inline] pub fn is_nan(&self) -> bool { match self.n { N::PosInt(_) | N::NegInt(_) => false, N::Float(f) => f.is_nan(), } } /// Returns true if this value is positive infinity or negative infinity and /// false otherwise. /// /// ``` /// # use std::f64; /// # /// # use serde_yaml::Number; /// # /// assert!(!Number::from(256.0).is_infinite()); /// /// assert!(!Number::from(f64::NAN).is_infinite()); /// /// assert!(Number::from(f64::INFINITY).is_infinite()); /// /// assert!(Number::from(f64::NEG_INFINITY).is_infinite()); /// /// assert!(!Number::from(1).is_infinite()); /// ``` #[inline] pub fn is_infinite(&self) -> bool { match self.n { N::PosInt(_) | N::NegInt(_) => false, N::Float(f) => f.is_infinite(), } } /// Returns true if this number is neither infinite nor NaN. /// /// ``` /// # use std::f64; /// # /// # use serde_yaml::Number; /// # /// assert!(Number::from(256.0).is_finite()); /// /// assert!(!Number::from(f64::NAN).is_finite()); /// /// assert!(!Number::from(f64::INFINITY).is_finite()); /// /// assert!(!Number::from(f64::NEG_INFINITY).is_finite()); /// /// assert!(Number::from(1).is_finite()); /// ``` #[inline] pub fn is_finite(&self) -> bool { match self.n { N::PosInt(_) | N::NegInt(_) => true, N::Float(f) => f.is_finite(), } } } impl fmt::Display for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self.n { N::PosInt(i) => Display::fmt(&i, formatter), N::NegInt(i) => Display::fmt(&i, formatter), N::Float(f) if f.is_nan() => formatter.write_str(".nan"), N::Float(f) if f.is_infinite() => { if f.is_sign_negative() { formatter.write_str("-.inf") } else { formatter.write_str(".inf") } } N::Float(f) => Display::fmt(&f, formatter), } } } impl Debug for Number { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(&self.n, formatter) } } impl PartialEq for N { fn eq(&self, other: &N) -> bool { match (*self, *other) { (N::PosInt(a), N::PosInt(b)) => a == b, (N::NegInt(a), N::NegInt(b)) => a == b, (N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { // YAML only has one NaN; // the bit representation isn't preserved true } else { a == b } } _ => false, } } } impl PartialOrd for N { fn partial_cmp(&self, other: &Self) -> Option { match (*self, *other) { (N::Float(a), N::Float(b)) => { if a.is_nan() && b.is_nan() { // YAML only has one NaN Some(Ordering::Equal) } else { a.partial_cmp(&b) } } _ => Some(self.total_cmp(other)), } } } impl N { fn total_cmp(&self, other: &Self) -> Ordering { match (*self, *other) { (N::PosInt(a), N::PosInt(b)) => a.cmp(&b), (N::NegInt(a), N::NegInt(b)) => a.cmp(&b), // negint is always less than zero (N::NegInt(_), N::PosInt(_)) => Ordering::Less, (N::PosInt(_), N::NegInt(_)) => Ordering::Greater, (N::Float(a), N::Float(b)) => a.partial_cmp(&b).unwrap_or_else(|| { // arbitrarily sort the NaN last if !a.is_nan() { Ordering::Less } else if !b.is_nan() { Ordering::Greater } else { Ordering::Equal } }), // arbitrarily sort integers below floats // FIXME: maybe something more sensible? (_, N::Float(_)) => Ordering::Less, (N::Float(_), _) => Ordering::Greater, } } } impl Number { pub(crate) fn total_cmp(&self, other: &Self) -> Ordering { self.n.total_cmp(&other.n) } } impl Serialize for Number { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self.n { N::PosInt(i) => serializer.serialize_u64(i), N::NegInt(i) => serializer.serialize_i64(i), N::Float(f) => serializer.serialize_f64(f), } } } impl<'de> Deserialize<'de> for Number { #[inline] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct NumberVisitor; impl<'de> Visitor<'de> for NumberVisitor { type Value = Number; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a number") } #[inline] fn visit_i64(self, value: i64) -> Result { Ok(value.into()) } #[inline] fn visit_u64(self, value: u64) -> Result { Ok(value.into()) } #[inline] fn visit_f64(self, value: f64) -> Result { Ok(value.into()) } } deserializer.deserialize_any(NumberVisitor) } } impl<'de> Deserializer<'de> for Number { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self.n { N::PosInt(i) => visitor.visit_u64(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } } impl<'de, 'a> Deserializer<'de> for &'a Number { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self.n { N::PosInt(i) => visitor.visit_u64(i), N::NegInt(i) => visitor.visit_i64(i), N::Float(f) => visitor.visit_f64(f), } } forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any } } macro_rules! from_signed { ($($signed_ty:ident)*) => { $( impl From<$signed_ty> for Number { #[inline] #[allow(clippy::cast_sign_loss)] fn from(i: $signed_ty) -> Self { if i < 0 { Number { n: N::NegInt(i as i64) } } else { Number { n: N::PosInt(i as u64) } } } } )* }; } macro_rules! from_unsigned { ($($unsigned_ty:ident)*) => { $( impl From<$unsigned_ty> for Number { #[inline] fn from(u: $unsigned_ty) -> Self { Number { n: N::PosInt(u as u64) } } } )* }; } macro_rules! from_float { ($($float_ty:ident)*) => { $( impl From<$float_ty> for Number { #[inline] fn from(f: $float_ty) -> Self { Number { n: N::Float(f as f64) } } } )* } } from_signed!(i8 i16 i32 i64 isize); from_unsigned!(u8 u16 u32 u64 usize); from_float!(f32 f64); // This is fine, because we don't _really_ implement hash for floats // all other hash functions should work as expected #[allow(clippy::derive_hash_xor_eq)] impl Hash for Number { fn hash(&self, state: &mut H) { match self.n { N::Float(_) => { // you should feel bad for using f64 as a map key 3.hash(state); } N::PosInt(u) => u.hash(state), N::NegInt(i) => i.hash(state), } } } pub(crate) fn unexpected(number: &Number) -> Unexpected { match number.n { N::PosInt(u) => Unexpected::Unsigned(u), N::NegInt(i) => Unexpected::Signed(i), N::Float(f) => Unexpected::Float(f), } } serde_yaml-0.8.26/src/path.rs000064400000000000000000000022731046102023000141420ustar 00000000000000use std::fmt::{self, Display}; /// Path to the current value in the input, like `dependencies.serde.typo1`. #[derive(Copy, Clone)] pub enum Path<'a> { Root, Seq { parent: &'a Path<'a>, index: usize }, Map { parent: &'a Path<'a>, key: &'a str }, Alias { parent: &'a Path<'a> }, Unknown { parent: &'a Path<'a> }, } impl<'a> Display for Path<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { struct Parent<'a>(&'a Path<'a>); impl<'a> Display for Parent<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.0 { Path::Root => Ok(()), path => write!(formatter, "{}.", path), } } } match self { Path::Root => formatter.write_str("."), Path::Seq { parent, index } => write!(formatter, "{}[{}]", parent, index), Path::Map { parent, key } => write!(formatter, "{}{}", Parent(parent), key), Path::Alias { parent } => write!(formatter, "{}", parent), Path::Unknown { parent } => write!(formatter, "{}?", Parent(parent)), } } } serde_yaml-0.8.26/src/ser.rs000064400000000000000000000540151046102023000140000ustar 00000000000000//! YAML Serialization //! //! This module provides YAML serialization with the type `Serializer`. use crate::{error, Error, Result}; use serde::ser; use std::{fmt, io, num, str}; use yaml_rust::{yaml, Yaml, YamlEmitter}; /// A structure for serializing Rust values into YAML. /// /// # Example /// /// ``` /// use anyhow::Result; /// use serde::Serialize; /// use std::collections::BTreeMap; /// /// fn main() -> Result<()> { /// let mut buffer = Vec::new(); /// let mut ser = serde_yaml::Serializer::new(&mut buffer); /// /// let mut object = BTreeMap::new(); /// object.insert("k", 107); /// object.serialize(&mut ser)?; /// /// object.insert("J", 74); /// object.serialize(&mut ser)?; /// /// assert_eq!(buffer, b"---\nk: 107\n...\n---\nJ: 74\nk: 107\n"); /// Ok(()) /// } /// ``` pub struct Serializer { documents: usize, writer: W, } impl Serializer where W: io::Write, { /// Creates a new YAML serializer. pub fn new(writer: W) -> Self { Serializer { documents: 0, writer, } } /// Calls [`.flush()`](io::Write::flush) on the underlying `io::Write` /// object. pub fn flush(&mut self) -> io::Result<()> { self.writer.flush() } /// Unwrap the underlying `io::Write` object from the `Serializer`. pub fn into_inner(self) -> W { self.writer } fn write(&mut self, doc: Yaml) -> Result<()> { if self.documents > 0 { self.writer.write_all(b"...\n").map_err(error::io)?; } self.documents += 1; let mut writer_adapter = FmtToIoWriter { writer: &mut self.writer, }; YamlEmitter::new(&mut writer_adapter) .dump(&doc) .map_err(error::emitter)?; writer_adapter.writer.write_all(b"\n").map_err(error::io)?; Ok(()) } } impl<'a, W> ser::Serializer for &'a mut Serializer where W: io::Write, { type Ok = (); type Error = Error; type SerializeSeq = ThenWrite<'a, W, SerializeArray>; type SerializeTuple = ThenWrite<'a, W, SerializeArray>; type SerializeTupleStruct = ThenWrite<'a, W, SerializeArray>; type SerializeTupleVariant = ThenWrite<'a, W, SerializeTupleVariant>; type SerializeMap = ThenWrite<'a, W, SerializeMap>; type SerializeStruct = ThenWrite<'a, W, SerializeStruct>; type SerializeStructVariant = ThenWrite<'a, W, SerializeStructVariant>; fn serialize_bool(self, v: bool) -> Result<()> { let doc = SerializerToYaml.serialize_bool(v)?; self.write(doc) } fn serialize_i8(self, v: i8) -> Result<()> { let doc = SerializerToYaml.serialize_i8(v)?; self.write(doc) } fn serialize_i16(self, v: i16) -> Result<()> { let doc = SerializerToYaml.serialize_i16(v)?; self.write(doc) } fn serialize_i32(self, v: i32) -> Result<()> { let doc = SerializerToYaml.serialize_i32(v)?; self.write(doc) } fn serialize_i64(self, v: i64) -> Result<()> { let doc = SerializerToYaml.serialize_i64(v)?; self.write(doc) } fn serialize_i128(self, v: i128) -> Result<()> { let doc = SerializerToYaml.serialize_i128(v)?; self.write(doc) } fn serialize_u8(self, v: u8) -> Result<()> { let doc = SerializerToYaml.serialize_u8(v)?; self.write(doc) } fn serialize_u16(self, v: u16) -> Result<()> { let doc = SerializerToYaml.serialize_u16(v)?; self.write(doc) } fn serialize_u32(self, v: u32) -> Result<()> { let doc = SerializerToYaml.serialize_u32(v)?; self.write(doc) } fn serialize_u64(self, v: u64) -> Result<()> { let doc = SerializerToYaml.serialize_u64(v)?; self.write(doc) } fn serialize_u128(self, v: u128) -> Result<()> { let doc = SerializerToYaml.serialize_u128(v)?; self.write(doc) } fn serialize_f32(self, v: f32) -> Result<()> { let doc = SerializerToYaml.serialize_f32(v)?; self.write(doc) } fn serialize_f64(self, v: f64) -> Result<()> { let doc = SerializerToYaml.serialize_f64(v)?; self.write(doc) } fn serialize_char(self, value: char) -> Result<()> { let doc = SerializerToYaml.serialize_char(value)?; self.write(doc) } fn serialize_str(self, value: &str) -> Result<()> { let doc = SerializerToYaml.serialize_str(value)?; self.write(doc) } fn serialize_bytes(self, value: &[u8]) -> Result<()> { let doc = SerializerToYaml.serialize_bytes(value)?; self.write(doc) } fn serialize_unit(self) -> Result<()> { let doc = SerializerToYaml.serialize_unit()?; self.write(doc) } fn serialize_unit_struct(self, name: &'static str) -> Result<()> { let doc = SerializerToYaml.serialize_unit_struct(name)?; self.write(doc) } fn serialize_unit_variant( self, name: &'static str, variant_index: u32, variant: &'static str, ) -> Result<()> { let doc = SerializerToYaml.serialize_unit_variant(name, variant_index, variant)?; self.write(doc) } fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { let doc = SerializerToYaml.serialize_newtype_struct(name, value)?; self.write(doc) } fn serialize_newtype_variant( self, name: &'static str, variant_index: u32, variant: &'static str, value: &T, ) -> Result<()> where T: ?Sized + ser::Serialize, { let doc = SerializerToYaml.serialize_newtype_variant(name, variant_index, variant, value)?; self.write(doc) } fn serialize_none(self) -> Result<()> { let doc = SerializerToYaml.serialize_none()?; self.write(doc) } fn serialize_some(self, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { let doc = SerializerToYaml.serialize_some(value)?; self.write(doc) } fn serialize_seq(self, len: Option) -> Result { let delegate = SerializerToYaml.serialize_seq(len)?; Ok(ThenWrite::new(self, delegate)) } fn serialize_tuple(self, len: usize) -> Result { let delegate = SerializerToYaml.serialize_tuple(len)?; Ok(ThenWrite::new(self, delegate)) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { let delegate = SerializerToYaml.serialize_tuple_struct(name, len)?; Ok(ThenWrite::new(self, delegate)) } fn serialize_tuple_variant( self, enm: &'static str, idx: u32, variant: &'static str, len: usize, ) -> Result { let delegate = SerializerToYaml.serialize_tuple_variant(enm, idx, variant, len)?; Ok(ThenWrite::new(self, delegate)) } fn serialize_map(self, len: Option) -> Result { let delegate = SerializerToYaml.serialize_map(len)?; Ok(ThenWrite::new(self, delegate)) } fn serialize_struct(self, name: &'static str, len: usize) -> Result { let delegate = SerializerToYaml.serialize_struct(name, len)?; Ok(ThenWrite::new(self, delegate)) } fn serialize_struct_variant( self, enm: &'static str, idx: u32, variant: &'static str, len: usize, ) -> Result { let delegate = SerializerToYaml.serialize_struct_variant(enm, idx, variant, len)?; Ok(ThenWrite::new(self, delegate)) } } pub struct ThenWrite<'a, W, D> { serializer: &'a mut Serializer, delegate: D, } impl<'a, W, D> ThenWrite<'a, W, D> { fn new(serializer: &'a mut Serializer, delegate: D) -> Self { ThenWrite { serializer, delegate, } } } impl<'a, W> ser::SerializeSeq for ThenWrite<'a, W, SerializeArray> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.delegate.serialize_element(elem) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } impl<'a, W> ser::SerializeTuple for ThenWrite<'a, W, SerializeArray> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.delegate.serialize_element(elem) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } impl<'a, W> ser::SerializeTupleStruct for ThenWrite<'a, W, SerializeArray> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field(&mut self, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.delegate.serialize_field(value) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } impl<'a, W> ser::SerializeTupleVariant for ThenWrite<'a, W, SerializeTupleVariant> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field(&mut self, v: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.delegate.serialize_field(v) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } impl<'a, W> ser::SerializeMap for ThenWrite<'a, W, SerializeMap> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.delegate.serialize_key(key) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.delegate.serialize_value(value) } fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> where K: ?Sized + ser::Serialize, V: ?Sized + ser::Serialize, { self.delegate.serialize_entry(key, value) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } impl<'a, W> ser::SerializeStruct for ThenWrite<'a, W, SerializeStruct> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.delegate.serialize_field(key, value) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } impl<'a, W> ser::SerializeStructVariant for ThenWrite<'a, W, SerializeStructVariant> where W: io::Write, { type Ok = (); type Error = Error; fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.delegate.serialize_field(field, v) } fn end(self) -> Result<()> { let doc = self.delegate.end()?; self.serializer.write(doc) } } pub struct SerializerToYaml; impl ser::Serializer for SerializerToYaml { type Ok = Yaml; type Error = Error; type SerializeSeq = SerializeArray; type SerializeTuple = SerializeArray; type SerializeTupleStruct = SerializeArray; type SerializeTupleVariant = SerializeTupleVariant; type SerializeMap = SerializeMap; type SerializeStruct = SerializeStruct; type SerializeStructVariant = SerializeStructVariant; fn serialize_bool(self, v: bool) -> Result { Ok(Yaml::Boolean(v)) } fn serialize_i8(self, v: i8) -> Result { self.serialize_i64(v as i64) } fn serialize_i16(self, v: i16) -> Result { self.serialize_i64(v as i64) } fn serialize_i32(self, v: i32) -> Result { self.serialize_i64(v as i64) } fn serialize_i64(self, v: i64) -> Result { Ok(Yaml::Integer(v)) } #[allow(clippy::cast_possible_truncation)] fn serialize_i128(self, v: i128) -> Result { if v <= i64::max_value() as i128 && v >= i64::min_value() as i128 { self.serialize_i64(v as i64) } else { Ok(Yaml::Real(v.to_string())) } } fn serialize_u8(self, v: u8) -> Result { self.serialize_i64(v as i64) } fn serialize_u16(self, v: u16) -> Result { self.serialize_i64(v as i64) } fn serialize_u32(self, v: u32) -> Result { self.serialize_i64(v as i64) } fn serialize_u64(self, v: u64) -> Result { if v <= i64::max_value() as u64 { self.serialize_i64(v as i64) } else { Ok(Yaml::Real(v.to_string())) } } #[allow(clippy::cast_possible_truncation)] fn serialize_u128(self, v: u128) -> Result { if v <= i64::max_value() as u128 { self.serialize_i64(v as i64) } else { Ok(Yaml::Real(v.to_string())) } } fn serialize_f32(self, v: f32) -> Result { Ok(Yaml::Real(match v.classify() { num::FpCategory::Infinite if v.is_sign_positive() => ".inf".into(), num::FpCategory::Infinite => "-.inf".into(), num::FpCategory::Nan => ".nan".into(), _ => ryu::Buffer::new().format_finite(v).into(), })) } fn serialize_f64(self, v: f64) -> Result { Ok(Yaml::Real(match v.classify() { num::FpCategory::Infinite if v.is_sign_positive() => ".inf".into(), num::FpCategory::Infinite => "-.inf".into(), num::FpCategory::Nan => ".nan".into(), _ => ryu::Buffer::new().format_finite(v).into(), })) } fn serialize_char(self, value: char) -> Result { Ok(Yaml::String(value.to_string())) } fn serialize_str(self, value: &str) -> Result { Ok(Yaml::String(value.to_owned())) } fn serialize_bytes(self, value: &[u8]) -> Result { let vec = value.iter().map(|&b| Yaml::Integer(b as i64)).collect(); Ok(Yaml::Array(vec)) } fn serialize_unit(self) -> Result { Ok(Yaml::Null) } fn serialize_unit_struct(self, _name: &'static str) -> Result { self.serialize_unit() } fn serialize_unit_variant( self, _name: &str, _variant_index: u32, variant: &str, ) -> Result { Ok(Yaml::String(variant.to_owned())) } fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result where T: ?Sized + ser::Serialize, { value.serialize(self) } fn serialize_newtype_variant( self, _name: &str, _variant_index: u32, variant: &str, value: &T, ) -> Result where T: ?Sized + ser::Serialize, { Ok(singleton_hash(to_yaml(variant)?, to_yaml(value)?)) } fn serialize_none(self) -> Result { self.serialize_unit() } fn serialize_some(self, value: &V) -> Result where V: ?Sized + ser::Serialize, { value.serialize(self) } fn serialize_seq(self, len: Option) -> Result { let array = match len { None => yaml::Array::new(), Some(len) => yaml::Array::with_capacity(len), }; Ok(SerializeArray { array }) } fn serialize_tuple(self, len: usize) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_variant( self, _enum: &'static str, _idx: u32, variant: &'static str, len: usize, ) -> Result { Ok(SerializeTupleVariant { name: variant, array: yaml::Array::with_capacity(len), }) } fn serialize_map(self, _len: Option) -> Result { Ok(SerializeMap { hash: yaml::Hash::new(), next_key: None, }) } fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { Ok(SerializeStruct { hash: yaml::Hash::new(), }) } fn serialize_struct_variant( self, _enum: &'static str, _idx: u32, variant: &'static str, _len: usize, ) -> Result { Ok(SerializeStructVariant { name: variant, hash: yaml::Hash::new(), }) } } #[doc(hidden)] pub struct SerializeArray { array: yaml::Array, } #[doc(hidden)] pub struct SerializeTupleVariant { name: &'static str, array: yaml::Array, } #[doc(hidden)] pub struct SerializeMap { hash: yaml::Hash, next_key: Option, } #[doc(hidden)] pub struct SerializeStruct { hash: yaml::Hash, } #[doc(hidden)] pub struct SerializeStructVariant { name: &'static str, hash: yaml::Hash, } impl ser::SerializeSeq for SerializeArray { type Ok = yaml::Yaml; type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.array.push(to_yaml(elem)?); Ok(()) } fn end(self) -> Result { Ok(Yaml::Array(self.array)) } } impl ser::SerializeTuple for SerializeArray { type Ok = yaml::Yaml; type Error = Error; fn serialize_element(&mut self, elem: &T) -> Result<()> where T: ?Sized + ser::Serialize, { ser::SerializeSeq::serialize_element(self, elem) } fn end(self) -> Result { ser::SerializeSeq::end(self) } } impl ser::SerializeTupleStruct for SerializeArray { type Ok = yaml::Yaml; type Error = Error; fn serialize_field(&mut self, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { ser::SerializeSeq::serialize_element(self, value) } fn end(self) -> Result { ser::SerializeSeq::end(self) } } impl ser::SerializeTupleVariant for SerializeTupleVariant { type Ok = yaml::Yaml; type Error = Error; fn serialize_field(&mut self, v: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.array.push(to_yaml(v)?); Ok(()) } fn end(self) -> Result { Ok(singleton_hash(to_yaml(self.name)?, Yaml::Array(self.array))) } } impl ser::SerializeMap for SerializeMap { type Ok = yaml::Yaml; type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + ser::Serialize, { self.next_key = Some(to_yaml(key)?); Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { match self.next_key.take() { Some(key) => self.hash.insert(key, to_yaml(value)?), None => panic!("serialize_value called before serialize_key"), }; Ok(()) } fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> where K: ?Sized + ser::Serialize, V: ?Sized + ser::Serialize, { self.hash.insert(to_yaml(key)?, to_yaml(value)?); Ok(()) } fn end(self) -> Result { Ok(Yaml::Hash(self.hash)) } } impl ser::SerializeStruct for SerializeStruct { type Ok = yaml::Yaml; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.hash.insert(to_yaml(key)?, to_yaml(value)?); Ok(()) } fn end(self) -> Result { Ok(Yaml::Hash(self.hash)) } } impl ser::SerializeStructVariant for SerializeStructVariant { type Ok = yaml::Yaml; type Error = Error; fn serialize_field(&mut self, field: &'static str, v: &V) -> Result<()> where V: ?Sized + ser::Serialize, { self.hash.insert(to_yaml(field)?, to_yaml(v)?); Ok(()) } fn end(self) -> Result { Ok(singleton_hash(to_yaml(self.name)?, Yaml::Hash(self.hash))) } } /// Serialize the given data structure as YAML into the IO stream. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// return an error. pub fn to_writer(writer: W, value: &T) -> Result<()> where W: io::Write, T: ?Sized + ser::Serialize, { value.serialize(&mut Serializer::new(writer)) } /// Serialize the given data structure as a YAML byte vector. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// return an error. pub fn to_vec(value: &T) -> Result> where T: ?Sized + ser::Serialize, { let mut vec = Vec::with_capacity(128); to_writer(&mut vec, value)?; Ok(vec) } /// Serialize the given data structure as a String of YAML. /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to /// return an error. pub fn to_string(value: &T) -> Result where T: ?Sized + ser::Serialize, { String::from_utf8(to_vec(value)?).map_err(error::string_utf8) } /// The yaml-rust library uses `fmt::Write` intead of `io::Write` so this is a /// simple adapter. struct FmtToIoWriter { writer: W, } impl fmt::Write for FmtToIoWriter where W: io::Write, { fn write_str(&mut self, s: &str) -> fmt::Result { if self.writer.write_all(s.as_bytes()).is_err() { return Err(fmt::Error); } Ok(()) } } fn to_yaml(elem: T) -> Result where T: ser::Serialize, { elem.serialize(SerializerToYaml) } fn singleton_hash(k: Yaml, v: Yaml) -> Yaml { let mut hash = yaml::Hash::new(); hash.insert(k, v); Yaml::Hash(hash) } serde_yaml-0.8.26/src/value/de.rs000064400000000000000000000437551046102023000147240ustar 00000000000000use crate::{number, Error, Mapping, Sequence, Value}; use serde::de::{ self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as SError, Expected, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, }; use serde::forward_to_deserialize_any; use std::fmt; use std::vec; impl<'de> Deserialize<'de> for Value { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct ValueVisitor; impl<'de> Visitor<'de> for ValueVisitor { type Value = Value; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("any YAML value") } fn visit_bool(self, b: bool) -> Result where E: SError, { Ok(Value::Bool(b)) } fn visit_i64(self, i: i64) -> Result where E: SError, { Ok(Value::Number(i.into())) } fn visit_u64(self, u: u64) -> Result where E: SError, { Ok(Value::Number(u.into())) } fn visit_f64(self, f: f64) -> Result where E: SError, { Ok(Value::Number(f.into())) } fn visit_str(self, s: &str) -> Result where E: SError, { Ok(Value::String(s.to_owned())) } fn visit_string(self, s: String) -> Result where E: SError, { Ok(Value::String(s)) } fn visit_unit(self) -> Result where E: SError, { Ok(Value::Null) } fn visit_none(self) -> Result where E: SError, { Ok(Value::Null) } fn visit_some(self, deserializer: D) -> Result where D: Deserializer<'de>, { Deserialize::deserialize(deserializer) } fn visit_seq(self, mut visitor: V) -> Result where V: SeqAccess<'de>, { let mut vec = Vec::new(); while let Some(element) = visitor.next_element()? { vec.push(element); } Ok(Value::Sequence(vec)) } fn visit_map(self, mut visitor: V) -> Result where V: MapAccess<'de>, { let mut values = Mapping::new(); while let Some((key, value)) = visitor.next_entry()? { values.insert(key, value); } Ok(Value::Mapping(values)) } } deserializer.deserialize_any(ValueVisitor) } } impl Value { fn deserialize_number<'de, V>(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Number(n) => n.deserialize_any(visitor), _ => Err(self.invalid_type(&visitor)), } } } fn visit_sequence<'de, V>(sequence: Sequence, visitor: V) -> Result where V: Visitor<'de>, { let len = sequence.len(); let mut deserializer = SeqDeserializer::new(sequence); let seq = visitor.visit_seq(&mut deserializer)?; let remaining = deserializer.iter.len(); if remaining == 0 { Ok(seq) } else { Err(Error::invalid_length(len, &"fewer elements in sequence")) } } fn visit_mapping<'de, V>(mapping: Mapping, visitor: V) -> Result where V: Visitor<'de>, { let len = mapping.len(); let mut deserializer = MapDeserializer::new(mapping); let map = visitor.visit_map(&mut deserializer)?; let remaining = deserializer.iter.len(); if remaining == 0 { Ok(map) } else { Err(Error::invalid_length(len, &"fewer elements in map")) } } impl<'de> Deserializer<'de> for Value { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_unit(), Value::Bool(v) => visitor.visit_bool(v), Value::Number(n) => n.deserialize_any(visitor), Value::String(v) => visitor.visit_string(v), Value::Sequence(v) => visit_sequence(v, visitor), Value::Mapping(v) => visit_mapping(v, visitor), } } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Bool(v) => visitor.visit_bool(v), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_u128(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_number(visitor) } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::String(v) => visitor.visit_string(v), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_byte_buf(visitor) } fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::String(v) => visitor.visit_string(v), Value::Sequence(v) => visit_sequence(v, visitor), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_none(), _ => visitor.visit_some(self), } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Null => visitor.visit_unit(), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Sequence(v) => visit_sequence(v, visitor), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_tuple(self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_tuple_struct( self, _name: &'static str, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { match self { Value::Mapping(v) => visit_mapping(v, visitor), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { match self { Value::Sequence(v) => visit_sequence(v, visitor), Value::Mapping(v) => visit_mapping(v, visitor), _ => Err(self.invalid_type(&visitor)), } } fn deserialize_enum( self, _name: &str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let (variant, value) = match self { Value::Mapping(value) => { let mut iter = value.into_iter(); let (variant, value) = match iter.next() { Some(v) => v, None => { return Err(Error::invalid_value( Unexpected::Map, &"map with a single key", )); } }; // enums are encoded in json as maps with a single key:value pair if iter.next().is_some() { return Err(Error::invalid_value( Unexpected::Map, &"map with a single key", )); } (variant, Some(value)) } Value::String(variant) => (Value::String(variant), None), other => { return Err(Error::invalid_type(other.unexpected(), &"string or map")); } }; visitor.visit_enum(EnumDeserializer { variant, value }) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_string(visitor) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } } struct EnumDeserializer { variant: Value, value: Option, } impl<'de> EnumAccess<'de> for EnumDeserializer { type Error = Error; type Variant = VariantDeserializer; fn variant_seed(self, seed: V) -> Result<(V::Value, VariantDeserializer), Error> where V: DeserializeSeed<'de>, { let visitor = VariantDeserializer { value: self.value }; seed.deserialize(self.variant).map(|v| (v, visitor)) } } struct VariantDeserializer { value: Option, } impl<'de> VariantAccess<'de> for VariantDeserializer { type Error = Error; fn unit_variant(self) -> Result<(), Error> { match self.value { Some(value) => Deserialize::deserialize(value), None => Ok(()), } } fn newtype_variant_seed(self, seed: T) -> Result where T: DeserializeSeed<'de>, { match self.value { Some(value) => seed.deserialize(value), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"newtype variant", )), } } fn tuple_variant(self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Some(Value::Sequence(v)) => { Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) } Some(other) => Err(Error::invalid_type(other.unexpected(), &"tuple variant")), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"tuple variant", )), } } fn struct_variant( self, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { match self.value { Some(Value::Mapping(v)) => { Deserializer::deserialize_any(MapDeserializer::new(v), visitor) } Some(other) => Err(Error::invalid_type(other.unexpected(), &"struct variant")), None => Err(Error::invalid_type( Unexpected::UnitVariant, &"struct variant", )), } } } struct SeqDeserializer { iter: vec::IntoIter, } impl SeqDeserializer { fn new(vec: Vec) -> Self { SeqDeserializer { iter: vec.into_iter(), } } } impl<'de> Deserializer<'de> for SeqDeserializer { type Error = Error; #[inline] fn deserialize_any(mut self, visitor: V) -> Result where V: Visitor<'de>, { let len = self.iter.len(); if len == 0 { visitor.visit_unit() } else { let ret = visitor.visit_seq(&mut self)?; let remaining = self.iter.len(); if remaining == 0 { Ok(ret) } else { Err(Error::invalid_length(len, &"fewer elements in sequence")) } } } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier } } impl<'de> SeqAccess<'de> for SeqDeserializer { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result, Error> where T: DeserializeSeed<'de>, { match self.iter.next() { Some(value) => seed.deserialize(value).map(Some), None => Ok(None), } } fn size_hint(&self) -> Option { match self.iter.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, } } } struct MapDeserializer { iter: ::IntoIter, value: Option, } impl MapDeserializer { fn new(map: Mapping) -> Self { MapDeserializer { iter: map.into_iter(), value: None, } } } impl<'de> MapAccess<'de> for MapDeserializer { type Error = Error; fn next_key_seed(&mut self, seed: T) -> Result, Error> where T: DeserializeSeed<'de>, { match self.iter.next() { Some((key, value)) => { self.value = Some(value); seed.deserialize(key).map(Some) } None => Ok(None), } } fn next_value_seed(&mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { match self.value.take() { Some(value) => seed.deserialize(value), None => panic!("visit_value called before visit_key"), } } fn size_hint(&self) -> Option { match self.iter.size_hint() { (lower, Some(upper)) if lower == upper => Some(upper), _ => None, } } } impl<'de> Deserializer<'de> for MapDeserializer { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_map(self) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { drop(self); visitor.visit_unit() } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier } } impl Value { #[cold] fn invalid_type(&self, exp: &dyn Expected) -> E where E: de::Error, { de::Error::invalid_type(self.unexpected(), exp) } #[cold] fn unexpected(&self) -> Unexpected { match self { Value::Null => Unexpected::Unit, Value::Bool(b) => Unexpected::Bool(*b), Value::Number(n) => number::unexpected(n), Value::String(s) => Unexpected::Str(s), Value::Sequence(_) => Unexpected::Seq, Value::Mapping(_) => Unexpected::Map, } } } serde_yaml-0.8.26/src/value/from.rs000064400000000000000000000075131046102023000152670ustar 00000000000000use crate::{Mapping, Value}; // Implement a bunch of conversion to make it easier to create YAML values // on the fly. macro_rules! from_number { ($($ty:ident)*) => { $( impl From<$ty> for Value { fn from(n: $ty) -> Self { Value::Number(n.into()) } } )* }; } from_number! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize f32 f64 } impl From for Value { /// Convert boolean to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// /// let b = false; /// let x: Value = b.into(); /// ``` fn from(f: bool) -> Self { Value::Bool(f) } } impl From for Value { /// Convert `String` to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// /// let s: String = "lorem".to_string(); /// let x: Value = s.into(); /// ``` fn from(f: String) -> Self { Value::String(f) } } impl<'a> From<&'a str> for Value { /// Convert string slice to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// /// let s: &str = "lorem"; /// let x: Value = s.into(); /// ``` fn from(f: &str) -> Self { Value::String(f.to_string()) } } use std::borrow::Cow; impl<'a> From> for Value { /// Convert copy-on-write string to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// use std::borrow::Cow; /// /// let s: Cow = Cow::Borrowed("lorem"); /// let x: Value = s.into(); /// ``` /// /// ``` /// use serde_yaml::Value; /// use std::borrow::Cow; /// /// let s: Cow = Cow::Owned("lorem".to_string()); /// let x: Value = s.into(); /// ``` fn from(f: Cow<'a, str>) -> Self { Value::String(f.to_string()) } } impl From for Value { /// Convert map (with string keys) to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::{Mapping, Value}; /// /// let mut m = Mapping::new(); /// m.insert("Lorem".into(), "ipsum".into()); /// let x: Value = m.into(); /// ``` fn from(f: Mapping) -> Self { Value::Mapping(f) } } impl> From> for Value { /// Convert a `Vec` to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// /// let v = vec!["lorem", "ipsum", "dolor"]; /// let x: Value = v.into(); /// ``` fn from(f: Vec) -> Self { Value::Sequence(f.into_iter().map(Into::into).collect()) } } impl<'a, T: Clone + Into> From<&'a [T]> for Value { /// Convert a slice to `Value` /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; /// let x: Value = v.into(); /// ``` fn from(f: &'a [T]) -> Self { Value::Sequence(f.iter().cloned().map(Into::into).collect()) } } use std::iter::FromIterator; impl> FromIterator for Value { /// Convert an iteratable type to a YAML sequence /// /// # Examples /// /// ``` /// use serde_yaml::Value; /// /// let v = std::iter::repeat(42).take(5); /// let x: Value = v.collect(); /// ``` /// /// ``` /// use serde_yaml::Value; /// /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; /// let x: Value = v.into_iter().collect(); /// ``` /// /// ``` /// use std::iter::FromIterator; /// use serde_yaml::Value; /// /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); /// ``` fn from_iter>(iter: I) -> Self { let vec = iter.into_iter().map(T::into).collect(); Value::Sequence(vec) } } serde_yaml-0.8.26/src/value/index.rs000064400000000000000000000224661046102023000154370ustar 00000000000000use crate::{Mapping, Value}; use std::fmt; use std::ops; /// A type that can be used to index into a `serde_yaml::Value`. See the `get` /// and `get_mut` methods of `Value`. /// /// This trait is sealed and cannot be implemented for types outside of /// `serde_yaml`. pub trait Index: private::Sealed { /// Return None if the key is not already in the sequence or object. #[doc(hidden)] fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; /// Return None if the key is not already in the sequence or object. #[doc(hidden)] fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>; /// Panic if sequence index out of bounds. If key is not already in the object, /// insert it with a value of null. Panic if Value is a type that cannot be /// indexed into, except if Value is null then it can be treated as an empty /// object. #[doc(hidden)] fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; } impl Index for usize { fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { match v { Value::Sequence(vec) => vec.get(*self), Value::Mapping(vec) => vec.get(&Value::Number((*self).into())), _ => None, } } fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { match v { Value::Sequence(vec) => vec.get_mut(*self), Value::Mapping(vec) => vec.get_mut(&Value::Number((*self).into())), _ => None, } } fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { match v { Value::Sequence(vec) => { let len = vec.len(); vec.get_mut(*self).unwrap_or_else(|| { panic!( "cannot access index {} of YAML sequence of length {}", self, len ) }) } Value::Mapping(map) => { let n = Value::Number((*self).into()); // TODO: use entry() once LinkedHashMap supports entry() // https://github.com/contain-rs/linked-hash-map/issues/5 if !map.contains_key(&n) { map.insert(n.clone(), Value::Null); } map.get_mut(&n).unwrap() } _ => panic!("cannot access index {} of YAML {}", self, Type(v)), } } } impl Index for Value { fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { match v { Value::Mapping(map) => map.get(self), _ => None, } } fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { match v { Value::Mapping(map) => map.get_mut(self), _ => None, } } fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { if let Value::Null = *v { let mut map = Mapping::new(); map.insert(self.clone(), Value::Null); *v = Value::Mapping(map); } match v { Value::Mapping(map) => { // TODO: use entry() once LinkedHashMap supports entry() // https://github.com/contain-rs/linked-hash-map/issues/5 if !map.contains_key(self) { map.insert(self.clone(), Value::Null); } map.get_mut(self).unwrap() } _ => panic!("cannot access key {:?} in YAML {}", self, Type(v)), } } } impl Index for str { fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { Value::String(self.into()).index_into(v) } fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { Value::String(self.into()).index_into_mut(v) } fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { Value::String(self.into()).index_or_insert(v) } } impl Index for String { fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { Value::String(self.clone()).index_into(v) } fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { Value::String(self.clone()).index_into_mut(v) } fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { Value::String(self.clone()).index_or_insert(v) } } impl<'a, T> Index for &'a T where T: ?Sized + Index, { fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { (**self).index_into(v) } fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { (**self).index_into_mut(v) } fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { (**self).index_or_insert(v) } } // Prevent users from implementing the Index trait. mod private { pub trait Sealed {} impl Sealed for usize {} impl Sealed for str {} impl Sealed for String {} impl Sealed for super::Value {} impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} } /// Used in panic messages. struct Type<'a>(&'a Value); impl<'a> fmt::Display for Type<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self.0 { Value::Null => formatter.write_str("null"), Value::Bool(_) => formatter.write_str("boolean"), Value::Number(_) => formatter.write_str("number"), Value::String(_) => formatter.write_str("string"), Value::Sequence(_) => formatter.write_str("sequence"), Value::Mapping(_) => formatter.write_str("mapping"), } } } // The usual semantics of Index is to panic on invalid indexing. // // That said, the usual semantics are for things like `Vec` and `BTreeMap` which // have different use cases than Value. If you are working with a Vec, you know // that you are working with a Vec and you can get the len of the Vec and make // sure your indices are within bounds. The Value use cases are more // loosey-goosey. You got some YAML from an endpoint and you want to pull values // out of it. Outside of this Index impl, you already have the option of using // `value.as_sequence()` and working with the Vec directly, or matching on // `Value::Sequence` and getting the Vec directly. The Index impl means you can // skip that and index directly into the thing using a concise syntax. You don't // have to check the type, you don't have to check the len, it is all about what // you expect the Value to look like. // // Basically the use cases that would be well served by panicking here are // better served by using one of the other approaches: `get` and `get_mut`, // `as_sequence`, or match. The value of this impl is that it adds a way of // working with Value that is not well served by the existing approaches: // concise and careless and sometimes that is exactly what you want. impl ops::Index for Value where I: Index, { type Output = Value; /// Index into a `serde_yaml::Value` using the syntax `value[0]` or /// `value["k"]`. /// /// Returns `Value::Null` if the type of `self` does not match the type of /// the index, for example if the index is a string and `self` is a sequence /// or a number. Also returns `Value::Null` if the given key does not exist /// in the map or the given index is not within the bounds of the sequence. /// /// For retrieving deeply nested values, you should have a look at the /// `Value::pointer` method. /// /// # Examples /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let data = yaml(r#"{ x: { y: [z, zz] } }"#); /// /// assert_eq!(data["x"]["y"], yaml(r#"["z", "zz"]"#)); /// assert_eq!(data["x"]["y"][0], yaml(r#""z""#)); /// /// assert_eq!(data["a"], yaml(r#"null"#)); // returns null for undefined values /// assert_eq!(data["a"]["b"], yaml(r#"null"#)); // does not panic /// ``` fn index(&self, index: I) -> &Value { static NULL: Value = Value::Null; index.index_into(self).unwrap_or(&NULL) } } impl ops::IndexMut for Value where I: Index, { /// Write into a `serde_yaml::Value` using the syntax `value[0] = ...` or /// `value["k"] = ...`. /// /// If the index is a number, the value must be a sequence of length bigger /// than the index. Indexing into a value that is not a sequence or a /// sequence that is too small will panic. /// /// If the index is a string, the value must be an object or null which is /// treated like an empty object. If the key is not already present in the /// object, it will be inserted with a value of null. Indexing into a value /// that is neither an object nor null will panic. /// /// # Examples /// /// ``` /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let mut data = yaml(r#"{x: 0}"#); /// /// // replace an existing key /// data["x"] = yaml(r#"1"#); /// /// // insert a new key /// data["y"] = yaml(r#"[false, false, false]"#); /// /// // replace a value in a sequence /// data["y"][0] = yaml(r#"true"#); /// /// // inserted a deeply nested key /// data["a"]["b"]["c"]["d"] = yaml(r#"true"#); /// /// println!("{:?}", data); /// ``` fn index_mut(&mut self, index: I) -> &mut Value { index.index_or_insert(self) } } serde_yaml-0.8.26/src/value/mod.rs000064400000000000000000000463221046102023000151040ustar 00000000000000mod de; mod from; mod index; mod partial_eq; mod ser; use crate::ser::SerializerToYaml; use crate::{Error, Mapping}; use serde::de::{Deserialize, DeserializeOwned, IntoDeserializer}; use serde::Serialize; use std::f64; use std::hash::{Hash, Hasher}; use std::str::FromStr; use yaml_rust::Yaml; pub use self::index::Index; pub use crate::number::Number; /// Represents any valid YAML value. #[derive(Clone, PartialOrd, Debug)] pub enum Value { /// Represents a YAML null value. Null, /// Represents a YAML boolean. Bool(bool), /// Represents a YAML numerical value, whether integer or floating point. Number(Number), /// Represents a YAML string. String(String), /// Represents a YAML sequence in which the elements are /// `serde_yaml::Value`. Sequence(Sequence), /// Represents a YAML mapping in which the keys and values are both /// `serde_yaml::Value`. Mapping(Mapping), } /// The default value is `Value::Null`. /// /// This is useful for handling omitted `Value` fields when deserializing. /// /// # Examples /// /// ``` /// # use serde_derive::Deserialize; /// use serde::Deserialize; /// use serde_yaml::Value; /// /// #[derive(Deserialize)] /// struct Settings { /// level: i32, /// #[serde(default)] /// extras: Value, /// } /// /// # fn try_main() -> Result<(), serde_yaml::Error> { /// let data = r#" { "level": 42 } "#; /// let s: Settings = serde_yaml::from_str(data)?; /// /// assert_eq!(s.level, 42); /// assert_eq!(s.extras, Value::Null); /// # /// # Ok(()) /// # } /// # /// # try_main().unwrap() /// ``` impl Default for Value { fn default() -> Value { Value::Null } } /// A YAML sequence in which the elements are `serde_yaml::Value`. pub type Sequence = Vec; /// Convert a `T` into `serde_yaml::Value` which is an enum that can represent /// any valid YAML data. /// /// This conversion can fail if `T`'s implementation of `Serialize` decides to /// return an error. /// /// ``` /// # use serde_yaml::Value; /// let val = serde_yaml::to_value("s").unwrap(); /// assert_eq!(val, Value::String("s".to_owned())); /// ``` pub fn to_value(value: T) -> Result where T: Serialize, { value.serialize(SerializerToYaml).map(yaml_to_value) } /// Interpret a `serde_yaml::Value` as an instance of type `T`. /// /// This conversion can fail if the structure of the Value does not match the /// structure expected by `T`, for example if `T` is a struct type but the Value /// contains something other than a YAML map. It can also fail if the structure /// is correct but `T`'s implementation of `Deserialize` decides that something /// is wrong with the data, for example required struct fields are missing from /// the YAML map or some number is too big to fit in the expected primitive /// type. /// /// ``` /// # use serde_yaml::Value; /// let val = Value::String("foo".to_owned()); /// let s: String = serde_yaml::from_value(val).unwrap(); /// assert_eq!("foo", s); /// ``` pub fn from_value(value: Value) -> Result where T: DeserializeOwned, { Deserialize::deserialize(value) } impl Value { /// Index into a YAML sequence or map. A string index can be used to access /// a value in a map, and a usize index can be used to access an element of /// an sequence. /// /// Returns `None` if the type of `self` does not match the type of the /// index, for example if the index is a string and `self` is a sequence or /// a number. Also returns `None` if the given key does not exist in the map /// or the given index is not within the bounds of the sequence. /// /// ``` /// # use serde_yaml::Value; /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let object: Value = yaml(r#"{ A: 65, B: 66, C: 67 }"#); /// let x = object.get("A").unwrap(); /// assert_eq!(x, 65); /// /// let sequence: Value = yaml(r#"[ "A", "B", "C" ]"#); /// let x = sequence.get(2).unwrap(); /// assert_eq!(x, &Value::String("C".into())); /// /// assert_eq!(sequence.get("A"), None); /// ``` /// /// Square brackets can also be used to index into a value in a more concise /// way. This returns `Value::Null` in cases where `get` would have returned /// `None`. /// /// ``` /// # use serde_yaml::Value; /// # /// # fn yaml(i: &str) -> serde_yaml::Value { serde_yaml::from_str(i).unwrap() } /// # /// let object = yaml(r#" /// --- /// A: [a, á, à] /// B: [b, b́] /// C: [c, ć, ć̣, ḉ] /// 42: true /// "#); /// assert_eq!(object["B"][0], Value::String("b".into())); /// /// assert_eq!(object[Value::String("D".into())], Value::Null); /// assert_eq!(object["D"], Value::Null); /// assert_eq!(object[0]["x"]["y"]["z"], Value::Null); /// /// assert_eq!(object[42], Value::Bool(true)); /// ``` pub fn get(&self, index: I) -> Option<&Value> { index.index_into(self) } /// Index into a YAML sequence or map. A string index can be used to access /// a value in a map, and a usize index can be used to access an element of /// an sequence. /// /// Returns `None` if the type of `self` does not match the type of the /// index, for example if the index is a string and `self` is a sequence or /// a number. Also returns `None` if the given key does not exist in the map /// or the given index is not within the bounds of the sequence. pub fn get_mut(&mut self, index: I) -> Option<&mut Value> { index.index_into_mut(self) } /// Returns true if the `Value` is a Null. Returns false otherwise. /// /// For any Value on which `is_null` returns true, `as_null` is guaranteed /// to return `Some(())`. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("null").unwrap(); /// assert!(v.is_null()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert!(!v.is_null()); /// ``` pub fn is_null(&self) -> bool { if let Value::Null = *self { true } else { false } } /// If the `Value` is a Null, returns (). Returns None otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("null").unwrap(); /// assert_eq!(v.as_null(), Some(())); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_null(), None); /// ``` pub fn as_null(&self) -> Option<()> { match self { Value::Null => Some(()), _ => None, } } /// Returns true if the `Value` is a Boolean. Returns false otherwise. /// /// For any Value on which `is_boolean` returns true, `as_bool` is /// guaranteed to return the boolean value. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("true").unwrap(); /// assert!(v.is_bool()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("42").unwrap(); /// assert!(!v.is_bool()); /// ``` pub fn is_bool(&self) -> bool { self.as_bool().is_some() } /// If the `Value` is a Boolean, returns the associated bool. Returns None /// otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("true").unwrap(); /// assert_eq!(v.as_bool(), Some(true)); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("42").unwrap(); /// assert_eq!(v.as_bool(), None); /// ``` pub fn as_bool(&self) -> Option { match self { Value::Bool(b) => Some(*b), _ => None, } } /// Returns true if the `Value` is a Number. Returns false otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("5").unwrap(); /// assert!(v.is_number()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("true").unwrap(); /// assert!(!v.is_number()); /// ``` pub fn is_number(&self) -> bool { match self { Value::Number(_) => true, _ => false, } } /// Returns true if the `Value` is an integer between `i64::MIN` and /// `i64::MAX`. /// /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to /// return the integer value. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("1337").unwrap(); /// assert!(v.is_i64()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("null").unwrap(); /// assert!(!v.is_i64()); /// ``` pub fn is_i64(&self) -> bool { self.as_i64().is_some() } /// If the `Value` is an integer, represent it as i64 if possible. Returns /// None otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("1337").unwrap(); /// assert_eq!(v.as_i64(), Some(1337)); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_i64(), None); /// ``` pub fn as_i64(&self) -> Option { match self { Value::Number(n) => n.as_i64(), _ => None, } } /// Returns true if the `Value` is an integer between `u64::MIN` and /// `u64::MAX`. /// /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to /// return the integer value. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("1337").unwrap(); /// assert!(v.is_u64()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("null").unwrap(); /// assert!(!v.is_u64()); /// ``` pub fn is_u64(&self) -> bool { self.as_u64().is_some() } /// If the `Value` is an integer, represent it as u64 if possible. Returns /// None otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("1337").unwrap(); /// assert_eq!(v.as_u64(), Some(1337)); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_u64(), None); /// ``` pub fn as_u64(&self) -> Option { match self { Value::Number(n) => n.as_u64(), _ => None, } } /// Returns true if the `Value` is a number that can be represented by f64. /// /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to /// return the floating point value. /// /// Currently this function returns true if and only if both `is_i64` and /// `is_u64` return false but this is not a guarantee in the future. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("256.01").unwrap(); /// assert!(v.is_f64()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("true").unwrap(); /// assert!(!v.is_f64()); /// ``` pub fn is_f64(&self) -> bool { match self { Value::Number(n) => n.is_f64(), _ => false, } } /// If the `Value` is a number, represent it as f64 if possible. Returns /// None otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("13.37").unwrap(); /// assert_eq!(v.as_f64(), Some(13.37)); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_f64(), None); /// ``` pub fn as_f64(&self) -> Option { match self { Value::Number(i) => i.as_f64(), _ => None, } } /// Returns true if the `Value` is a String. Returns false otherwise. /// /// For any Value on which `is_string` returns true, `as_str` is guaranteed /// to return the string slice. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap(); /// assert!(v.is_string()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("42").unwrap(); /// assert!(!v.is_string()); /// ``` pub fn is_string(&self) -> bool { self.as_str().is_some() } /// If the `Value` is a String, returns the associated str. Returns None /// otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("'lorem ipsum'").unwrap(); /// assert_eq!(v.as_str(), Some("lorem ipsum")); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_str(), None); /// ``` pub fn as_str(&self) -> Option<&str> { match self { Value::String(s) => Some(s), _ => None, } } /// Returns true if the `Value` is a sequence. Returns false otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("[1, 2, 3]").unwrap(); /// assert!(v.is_sequence()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("true").unwrap(); /// assert!(!v.is_sequence()); /// ``` pub fn is_sequence(&self) -> bool { self.as_sequence().is_some() } /// If the `Value` is a sequence, return a reference to it if possible. /// Returns None otherwise. /// /// ``` /// # use serde_yaml::{Value, Number}; /// let v: Value = serde_yaml::from_str("[1, 2]").unwrap(); /// assert_eq!(v.as_sequence(), Some(&vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))])); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_sequence(), None); /// ``` pub fn as_sequence(&self) -> Option<&Sequence> { match self { Value::Sequence(seq) => Some(seq), _ => None, } } /// If the `Value` is a sequence, return a mutable reference to it if /// possible. Returns None otherwise. /// /// ``` /// # use serde_yaml::{Value, Number}; /// let mut v: Value = serde_yaml::from_str("[1]").unwrap(); /// let s = v.as_sequence_mut().unwrap(); /// s.push(Value::Number(Number::from(2))); /// assert_eq!(s, &vec![Value::Number(Number::from(1)), Value::Number(Number::from(2))]); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let mut v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_sequence_mut(), None); /// ``` pub fn as_sequence_mut(&mut self) -> Option<&mut Sequence> { match self { Value::Sequence(seq) => Some(seq), _ => None, } } /// Returns true if the `Value` is a mapping. Returns false otherwise. /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("a: 42").unwrap(); /// assert!(v.is_mapping()); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("true").unwrap(); /// assert!(!v.is_mapping()); /// ``` pub fn is_mapping(&self) -> bool { self.as_mapping().is_some() } /// If the `Value` is a mapping, return a reference to it if possible. /// Returns None otherwise. /// /// ``` /// # use serde_yaml::{Value, Mapping, Number}; /// let v: Value = serde_yaml::from_str("a: 42").unwrap(); /// /// let mut expected = Mapping::new(); /// expected.insert(Value::String("a".into()),Value::Number(Number::from(42))); /// /// assert_eq!(v.as_mapping(), Some(&expected)); /// ``` /// /// ``` /// # use serde_yaml::Value; /// let v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_mapping(), None); /// ``` pub fn as_mapping(&self) -> Option<&Mapping> { match self { Value::Mapping(map) => Some(map), _ => None, } } /// If the `Value` is a mapping, return a reference to it if possible. /// Returns None otherwise. /// /// ``` /// # use serde_yaml::{Value, Mapping, Number}; /// let mut v: Value = serde_yaml::from_str("a: 42").unwrap(); /// let m = v.as_mapping_mut().unwrap(); /// m.insert(Value::String("b".into()), Value::Number(Number::from(21))); /// /// let mut expected = Mapping::new(); /// expected.insert(Value::String("a".into()), Value::Number(Number::from(42))); /// expected.insert(Value::String("b".into()), Value::Number(Number::from(21))); /// /// assert_eq!(m, &expected); /// ``` /// /// ``` /// # use serde_yaml::{Value, Mapping}; /// let mut v: Value = serde_yaml::from_str("false").unwrap(); /// assert_eq!(v.as_mapping_mut(), None); /// ``` pub fn as_mapping_mut(&mut self) -> Option<&mut Mapping> { match self { Value::Mapping(map) => Some(map), _ => None, } } } fn yaml_to_value(yaml: Yaml) -> Value { match yaml { Yaml::Real(f) => { if f == ".inf" { Value::Number(f64::INFINITY.into()) } else if f == "-.inf" { Value::Number(f64::NEG_INFINITY.into()) } else if f == ".nan" { Value::Number(f64::NAN.into()) } else if let Ok(n) = u64::from_str(&f) { Value::Number(n.into()) } else if let Ok(n) = i64::from_str(&f) { Value::Number(n.into()) } else if let Ok(n) = f64::from_str(&f) { Value::Number(n.into()) } else { Value::String(f) } } Yaml::Integer(i) => Value::Number(i.into()), Yaml::String(s) => Value::String(s), Yaml::Boolean(b) => Value::Bool(b), Yaml::Array(sequence) => Value::Sequence(sequence.into_iter().map(yaml_to_value).collect()), Yaml::Hash(hash) => Value::Mapping( hash.into_iter() .map(|(k, v)| (yaml_to_value(k), yaml_to_value(v))) .collect(), ), Yaml::Alias(_) => panic!("alias unsupported"), Yaml::Null => Value::Null, Yaml::BadValue => panic!("bad value"), } } impl Eq for Value {} impl Hash for Value { fn hash(&self, state: &mut H) { match self { Value::Null => 0.hash(state), Value::Bool(b) => (1, b).hash(state), Value::Number(i) => (2, i).hash(state), Value::String(s) => (3, s).hash(state), Value::Sequence(seq) => (4, seq).hash(state), Value::Mapping(map) => (5, map).hash(state), } } } impl<'de> IntoDeserializer<'de, Error> for Value { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } serde_yaml-0.8.26/src/value/partial_eq.rs000064400000000000000000000075371046102023000164530ustar 00000000000000use crate::Value; impl PartialEq for Value { fn eq(&self, other: &Value) -> bool { match (self, other) { (Value::Null, Value::Null) => true, (Value::Bool(a), Value::Bool(b)) => a == b, (Value::Number(a), Value::Number(b)) => a == b, (Value::String(a), Value::String(b)) => a == b, (Value::Sequence(a), Value::Sequence(b)) => a == b, (Value::Mapping(a), Value::Mapping(b)) => a == b, _ => false, } } } impl PartialEq for Value { /// Compare `str` with YAML value /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!(Value::String("lorem".into()) == *"lorem"); /// ``` fn eq(&self, other: &str) -> bool { self.as_str().map_or(false, |s| s == other) } } impl<'a> PartialEq<&'a str> for Value { /// Compare `&str` with YAML value /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!(Value::String("lorem".into()) == "lorem"); /// ``` fn eq(&self, other: &&str) -> bool { self.as_str().map_or(false, |s| s == *other) } } impl PartialEq for str { /// Compare YAML value with `str` /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!(*"lorem" == Value::String("lorem".into())); /// ``` fn eq(&self, other: &Value) -> bool { other.as_str().map_or(false, |s| s == self) } } impl<'a> PartialEq for &'a str { /// Compare `&str` with YAML value /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!("lorem" == Value::String("lorem".into())); /// ``` fn eq(&self, other: &Value) -> bool { other.as_str().map_or(false, |s| s == *self) } } impl PartialEq for Value { /// Compare YAML value with String /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!(Value::String("lorem".into()) == "lorem".to_string()); /// ``` fn eq(&self, other: &String) -> bool { self.as_str().map_or(false, |s| s == other) } } impl PartialEq for String { /// Compare `String` with YAML value /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!("lorem".to_string() == Value::String("lorem".into())); /// ``` fn eq(&self, other: &Value) -> bool { other.as_str().map_or(false, |s| s == self) } } impl PartialEq for Value { /// Compare YAML value with bool /// /// # Examples /// /// ``` /// # use serde_yaml::Value; /// assert!(Value::Bool(true) == true); /// ``` fn eq(&self, other: &bool) -> bool { self.as_bool().map_or(false, |b| b == *other) } } macro_rules! partialeq_numeric { ($([$($ty:ty)*], $conversion:ident, $base:ty)*) => { $($( impl PartialEq<$ty> for Value { fn eq(&self, other: &$ty) -> bool { self.$conversion().map_or(false, |i| i == (*other as $base)) } } impl PartialEq for $ty { fn eq(&self, other: &Value) -> bool { other.$conversion().map_or(false, |i| i == (*self as $base)) } } impl<'a> PartialEq<$ty> for &'a Value { fn eq(&self, other: &$ty) -> bool { self.$conversion().map_or(false, |i| i == (*other as $base)) } } impl<'a> PartialEq<$ty> for &'a mut Value { fn eq(&self, other: &$ty) -> bool { self.$conversion().map_or(false, |i| i == (*other as $base)) } } )*)* } } partialeq_numeric! { [i8 i16 i32 i64 isize], as_i64, i64 [u8 u16 u32 u64 usize], as_u64, u64 [f32 f64], as_f64, f64 } serde_yaml-0.8.26/src/value/ser.rs000064400000000000000000000014661046102023000151160ustar 00000000000000use crate::Value; use serde::Serialize; impl Serialize for Value { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { match self { Value::Null => serializer.serialize_unit(), Value::Bool(b) => serializer.serialize_bool(*b), Value::Number(n) => n.serialize(serializer), Value::String(s) => serializer.serialize_str(s), Value::Sequence(seq) => seq.serialize(serializer), Value::Mapping(hash) => { use serde::ser::SerializeMap; let mut map = serializer.serialize_map(Some(hash.len()))?; for (k, v) in hash { map.serialize_entry(k, v)?; } map.end() } } } } serde_yaml-0.8.26/tests/test_de.rs000064400000000000000000000223071046102023000152100ustar 00000000000000#![allow( clippy::cast_lossless, clippy::cast_possible_wrap, clippy::derive_partial_eq_without_eq )] use indoc::indoc; use serde_derive::Deserialize; use serde_yaml::Value; use std::collections::BTreeMap; use std::fmt::Debug; fn test_de(yaml: &str, expected: &T) where T: serde::de::DeserializeOwned + PartialEq + Debug, { let deserialized: T = serde_yaml::from_str(yaml).unwrap(); assert_eq!(*expected, deserialized); serde_yaml::from_str::(yaml).unwrap(); serde_yaml::from_str::(yaml).unwrap(); } fn test_de_seed(yaml: &str, seed: S, expected: &T) where T: PartialEq + Debug, S: for<'de> serde::de::DeserializeSeed<'de, Value = T>, { let deserialized: T = serde_yaml::seed::from_str_seed(yaml, seed).unwrap(); assert_eq!(*expected, deserialized); serde_yaml::from_str::(yaml).unwrap(); serde_yaml::from_str::(yaml).unwrap(); } #[test] fn test_alias() { let yaml = indoc! {" --- first: &alias 1 second: *alias third: 3 "}; let mut expected = BTreeMap::new(); { expected.insert(String::from("first"), 1); expected.insert(String::from("second"), 1); expected.insert(String::from("third"), 3); } test_de(yaml, &expected); } #[test] fn test_option() { #[derive(Deserialize, PartialEq, Debug)] struct Data { a: Option, b: Option, c: Option, } let yaml = indoc! {" --- b: c: true "}; let expected = Data { a: None, b: None, c: Some(true), }; test_de(yaml, &expected); } #[test] fn test_option_alias() { #[derive(Deserialize, PartialEq, Debug)] struct Data { a: Option, b: Option, c: Option, d: Option, e: Option, f: Option, } let yaml = indoc! {" --- none_f: &none_f ~ none_s: &none_s ~ none_b: &none_b ~ some_f: &some_f 1.0 some_s: &some_s x some_b: &some_b true a: *none_f b: *none_s c: *none_b d: *some_f e: *some_s f: *some_b "}; let expected = Data { a: None, b: None, c: None, d: Some(1.0), e: Some("x".to_owned()), f: Some(true), }; test_de(yaml, &expected); } #[test] fn test_enum_alias() { #[derive(Deserialize, PartialEq, Debug)] enum E { A, B(u8, u8), } #[derive(Deserialize, PartialEq, Debug)] struct Data { a: E, b: E, } let yaml = indoc! {" --- aref: &aref A bref: &bref B: - 1 - 2 a: *aref b: *bref "}; let expected = Data { a: E::A, b: E::B(1, 2), }; test_de(yaml, &expected); } #[test] fn test_enum_tag() { #[derive(Deserialize, PartialEq, Debug)] enum E { A(String), B(String), } #[derive(Deserialize, PartialEq, Debug)] struct Data { a: E, b: E, } let yaml = indoc! {" --- a: !A foo b: !B bar "}; let expected = Data { a: E::A("foo".into()), b: E::B("bar".into()), }; test_de(yaml, &expected); } #[test] fn test_number_as_string() { #[derive(Deserialize, PartialEq, Debug)] struct Num { value: String, } let yaml = indoc! {" --- # Cannot be represented as u128 value: 340282366920938463463374607431768211457 "}; let expected = Num { value: "340282366920938463463374607431768211457".to_owned(), }; test_de(yaml, &expected); } #[test] fn test_i128_big() { let expected: i128 = ::std::i64::MIN as i128 - 1; let yaml = indoc! {" --- -9223372036854775809 "}; assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); } #[test] fn test_u128_big() { let expected: u128 = ::std::u64::MAX as u128 + 1; let yaml = indoc! {" --- 18446744073709551616 "}; assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); } #[test] fn test_number_alias_as_string() { #[derive(Deserialize, PartialEq, Debug)] struct Num { version: String, value: String, } let yaml = indoc! {" --- version: &a 1.10 value: *a "}; let expected = Num { version: "1.10".to_owned(), value: "1.10".to_owned(), }; test_de(yaml, &expected); } #[test] fn test_de_mapping() { #[derive(Debug, Deserialize, PartialEq)] struct Data { pub substructure: serde_yaml::Mapping, } let yaml = indoc! {" --- substructure: a: 'foo' b: 'bar' "}; let mut expected = Data { substructure: serde_yaml::Mapping::new(), }; expected.substructure.insert( serde_yaml::Value::String("a".to_owned()), serde_yaml::Value::String("foo".to_owned()), ); expected.substructure.insert( serde_yaml::Value::String("b".to_owned()), serde_yaml::Value::String("bar".to_owned()), ); test_de(yaml, &expected); } #[test] fn test_bomb() { #[derive(Debug, Deserialize, PartialEq)] struct Data { expected: String, } // This would deserialize an astronomical number of elements if we were // vulnerable. let yaml = indoc! {" --- a: &a ~ b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i] k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j] l: &l [*k,*k,*k,*k,*k,*k,*k,*k,*k] m: &m [*l,*l,*l,*l,*l,*l,*l,*l,*l] n: &n [*m,*m,*m,*m,*m,*m,*m,*m,*m] o: &o [*n,*n,*n,*n,*n,*n,*n,*n,*n] p: &p [*o,*o,*o,*o,*o,*o,*o,*o,*o] q: &q [*p,*p,*p,*p,*p,*p,*p,*p,*p] r: &r [*q,*q,*q,*q,*q,*q,*q,*q,*q] s: &s [*r,*r,*r,*r,*r,*r,*r,*r,*r] t: &t [*s,*s,*s,*s,*s,*s,*s,*s,*s] u: &u [*t,*t,*t,*t,*t,*t,*t,*t,*t] v: &v [*u,*u,*u,*u,*u,*u,*u,*u,*u] w: &w [*v,*v,*v,*v,*v,*v,*v,*v,*v] x: &x [*w,*w,*w,*w,*w,*w,*w,*w,*w] y: &y [*x,*x,*x,*x,*x,*x,*x,*x,*x] z: &z [*y,*y,*y,*y,*y,*y,*y,*y,*y] expected: string "}; let expected = Data { expected: "string".to_owned(), }; assert_eq!(expected, serde_yaml::from_str::(yaml).unwrap()); } #[test] fn test_numbers() { let cases = [ ("0xF0", "240"), ("+0xF0", "240"), ("-0xF0", "-240"), ("0o70", "56"), ("+0o70", "56"), ("-0o70", "-56"), ("0b10", "2"), ("+0b10", "2"), ("-0b10", "-2"), ("127", "127"), ("+127", "127"), ("-127", "-127"), (".inf", ".inf"), (".Inf", ".inf"), (".INF", ".inf"), ("-.inf", "-.inf"), ("-.Inf", "-.inf"), ("-.INF", "-.inf"), (".nan", ".nan"), (".NaN", ".nan"), (".NAN", ".nan"), ("0.1", "0.1"), ]; for &(yaml, expected) in &cases { let value = serde_yaml::from_str::(yaml).unwrap(); match value { Value::Number(number) => assert_eq!(number.to_string(), expected), _ => panic!("expected number. input={:?}, result={:?}", yaml, value), } } // NOT numbers. let cases = ["0127", "+0127", "-0127"]; for yaml in &cases { let value = serde_yaml::from_str::(yaml).unwrap(); match value { Value::String(string) => assert_eq!(string, *yaml), _ => panic!("expected string. input={:?}, result={:?}", yaml, value), } } } #[test] fn test_stateful() { struct Seed(i64); impl<'de> serde::de::DeserializeSeed<'de> for Seed { type Value = i64; fn deserialize(self, deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { struct Visitor(i64); impl<'de> serde::de::Visitor<'de> for Visitor { type Value = i64; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "an integer") } fn visit_i64(self, v: i64) -> Result { Ok(v * self.0) } fn visit_u64(self, v: u64) -> Result { Ok(v as i64 * self.0) } } deserializer.deserialize_any(Visitor(self.0)) } } let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)]; for &(yaml, seed, expected) in &cases { test_de_seed(yaml, Seed(seed), &expected); } } serde_yaml-0.8.26/tests/test_error.rs000064400000000000000000000143361046102023000157540ustar 00000000000000use indoc::indoc; use serde_derive::Deserialize; use std::fmt::Debug; fn test_error(yaml: &str, expected: &str) where T: serde::de::DeserializeOwned + Debug, { let result = serde_yaml::from_str::(yaml); assert_eq!(expected, format!("{}", result.unwrap_err())); } #[test] fn test_incorrect_type() { let yaml = indoc! {" --- str "}; let expected = "invalid type: string \"str\", expected i16 at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_incorrect_nested_type() { #[derive(Deserialize, Debug)] struct A { #[allow(dead_code)] b: Vec, } #[derive(Deserialize, Debug)] enum B { C(C), } #[derive(Deserialize, Debug)] struct C { #[allow(dead_code)] d: bool, } let yaml = indoc! {" --- b: - C: d: fase "}; let expected = "b[0].C.d: invalid type: string \"fase\", expected a boolean at line 4 column 10"; test_error::(yaml, expected); } #[test] fn test_empty() { let expected = "EOF while parsing a value"; test_error::("", expected); } #[test] fn test_missing_field() { #[derive(Deserialize, Debug)] struct Basic { #[allow(dead_code)] v: bool, #[allow(dead_code)] w: bool, } let yaml = indoc! {" --- v: true "}; let expected = "missing field `w` at line 2 column 2"; test_error::(yaml, expected); } #[test] fn test_unknown_anchor() { let yaml = indoc! {" --- *some "}; let expected = "while parsing node, found unknown anchor at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_ignored_unknown_anchor() { #[derive(Deserialize, Debug)] struct Wrapper { #[allow(dead_code)] c: (), } let yaml = indoc! {" --- b: [*a] c: ~ "}; let expected = "while parsing node, found unknown anchor at line 2 column 5"; test_error::(yaml, expected); } #[test] fn test_two_documents() { let yaml = indoc! {" --- 0 --- 1 "}; let expected = "deserializing from YAML containing more than one document is not supported"; test_error::(yaml, expected); } #[test] fn test_variant_map_wrong_size() { #[derive(Deserialize, Debug)] enum E { V(usize), } let yaml = indoc! {r#" --- "V": 16 "other": 32 "#}; let expected = "invalid length 2, expected map containing 1 entry"; test_error::(yaml, expected); } #[test] fn test_variant_not_a_map() { #[derive(Deserialize, Debug)] enum E { V(usize), } let yaml = indoc! {r#" --- - "V" "#}; let expected = "invalid type: sequence, expected string or singleton map at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_variant_not_string() { #[derive(Deserialize, Debug)] enum E { V(bool), } let yaml = indoc! {r#" --- {}: true "#}; let expected = "invalid type: map, expected variant of enum `E` at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_bad_bool() { let yaml = indoc! {" --- !!bool str "}; let expected = "invalid value: string \"str\", expected a boolean at line 2 column 8"; test_error::(yaml, expected); } #[test] fn test_bad_int() { let yaml = indoc! {" --- !!int str "}; let expected = "invalid value: string \"str\", expected an integer at line 2 column 7"; test_error::(yaml, expected); } #[test] fn test_bad_float() { let yaml = indoc! {" --- !!float str "}; let expected = "invalid value: string \"str\", expected a float at line 2 column 9"; test_error::(yaml, expected); } #[test] fn test_bad_null() { let yaml = indoc! {" --- !!null str "}; let expected = "invalid value: string \"str\", expected null at line 2 column 8"; test_error::<()>(yaml, expected); } #[test] fn test_short_tuple() { let yaml = indoc! {" --- [0, 0] "}; let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1"; test_error::<(u8, u8, u8)>(yaml, expected); } #[test] fn test_long_tuple() { let yaml = indoc! {" --- [0, 0, 0] "}; let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1"; test_error::<(u8, u8)>(yaml, expected); } #[test] fn test_no_location() { let invalid_utf8: Result = serde_yaml::from_slice(b"\x80\xae"); let utf8_location = invalid_utf8.unwrap_err().location(); assert!(utf8_location.is_none()); } #[test] fn test_invalid_scalar_type() { #[derive(Deserialize, Debug)] struct S { #[allow(dead_code)] x: [(); 1], } let yaml = "x:\n"; let expected = "x: invalid type: unit value, expected an array of length 1 at line 2 column 1"; test_error::(yaml, expected); } #[test] fn test_infinite_recursion_objects() { #[derive(Deserialize, Debug)] struct S { #[allow(dead_code)] x: Option>, } let yaml = "&a {x: *a}"; let expected = "recursion limit exceeded"; test_error::(yaml, expected); } #[test] fn test_infinite_recursion_arrays() { #[derive(Deserialize, Debug)] struct S { #[allow(dead_code)] x: Option>, } let yaml = "&a [*a]"; let expected = "recursion limit exceeded"; test_error::(yaml, expected); } #[test] fn test_finite_recursion_objects() { #[derive(Deserialize, Debug)] struct S { #[allow(dead_code)] x: Option>, } let yaml = "{x:".repeat(1_000) + &"}".repeat(1_000); let expected = "recursion limit exceeded at line 1 column 766"; test_error::(&yaml, expected); } #[test] fn test_finite_recursion_arrays() { #[derive(Deserialize, Debug)] struct S { #[allow(dead_code)] x: Option>, } let yaml = "[".repeat(1_000) + &"]".repeat(1_000); let expected = "recursion limit exceeded at line 1 column 256"; test_error::(&yaml, expected); } serde_yaml-0.8.26/tests/test_serde.rs000064400000000000000000000201411046102023000157140ustar 00000000000000#![allow( clippy::decimal_literal_representation, clippy::derive_partial_eq_without_eq, clippy::unreadable_literal, clippy::shadow_unrelated )] use indoc::indoc; use serde_derive::{Deserialize, Serialize}; use serde_yaml::Value; use std::collections::BTreeMap; use std::f64; use std::fmt::Debug; fn test_serde(thing: &T, yaml: &str) where T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug, { let serialized = serde_yaml::to_string(&thing).unwrap(); assert_eq!(yaml, serialized); let value = serde_yaml::to_value(&thing).unwrap(); let serialized = serde_yaml::to_string(&value).unwrap(); assert_eq!(yaml, serialized); let deserialized: T = serde_yaml::from_str(yaml).unwrap(); assert_eq!(*thing, deserialized); let value: Value = serde_yaml::from_str(yaml).unwrap(); let deserialized: T = serde_yaml::from_value(value).unwrap(); assert_eq!(*thing, deserialized); serde_yaml::from_str::(yaml).unwrap(); } #[test] fn test_default() { assert_eq!(Value::default(), Value::Null); } #[test] fn test_int() { let thing = 256; let yaml = indoc! {" --- 256 "}; test_serde(&thing, yaml); } #[test] fn test_int_max_u64() { let thing = ::std::u64::MAX; let yaml = indoc! {" --- 18446744073709551615 "}; test_serde(&thing, yaml); } #[test] fn test_int_min_i64() { let thing = ::std::i64::MIN; let yaml = indoc! {" --- -9223372036854775808 "}; test_serde(&thing, yaml); } #[test] fn test_int_max_i64() { let thing = ::std::i64::MAX; let yaml = indoc! {" --- 9223372036854775807 "}; test_serde(&thing, yaml); } #[test] fn test_i128_small() { let thing: i128 = -256; let yaml = indoc! {" --- -256 "}; test_serde(&thing, yaml); } #[test] fn test_u128_small() { let thing: u128 = 256; let yaml = indoc! {" --- 256 "}; test_serde(&thing, yaml); } #[test] fn test_float() { let thing = 25.6; let yaml = indoc! {" --- 25.6 "}; test_serde(&thing, yaml); let thing = 25.; let yaml = indoc! {" --- 25.0 "}; test_serde(&thing, yaml); let thing = f64::INFINITY; let yaml = indoc! {" --- .inf "}; test_serde(&thing, yaml); let thing = f64::NEG_INFINITY; let yaml = indoc! {" --- -.inf "}; test_serde(&thing, yaml); let float: f64 = serde_yaml::from_str(indoc! {" --- .nan "}) .unwrap(); assert!(float.is_nan()); } #[test] fn test_float32() { let thing: f32 = 25.6; let yaml = indoc! {" --- 25.6 "}; test_serde(&thing, yaml); let thing = f32::INFINITY; let yaml = indoc! {" --- .inf "}; test_serde(&thing, yaml); let thing = f32::NEG_INFINITY; let yaml = indoc! {" --- -.inf "}; test_serde(&thing, yaml); let single_float: f32 = serde_yaml::from_str(indoc! {" --- .nan "}) .unwrap(); assert!(single_float.is_nan()); } #[test] fn test_vec() { let thing = vec![1, 2, 3]; let yaml = indoc! {" --- - 1 - 2 - 3 "}; test_serde(&thing, yaml); } #[test] fn test_map() { let mut thing = BTreeMap::new(); thing.insert(String::from("x"), 1); thing.insert(String::from("y"), 2); let yaml = indoc! {" --- x: 1 y: 2 "}; test_serde(&thing, yaml); } #[test] fn test_basic_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Basic { x: isize, y: String, z: bool, } let thing = Basic { x: -4, y: String::from("hi\tquoted"), z: true, }; let yaml = indoc! {r#" --- x: -4 y: "hi\tquoted" z: true "#}; test_serde(&thing, yaml); } #[test] fn test_nested_vec() { let thing = vec![vec![1, 2, 3], vec![4, 5, 6]]; let yaml = indoc! {" --- - - 1 - 2 - 3 - - 4 - 5 - 6 "}; test_serde(&thing, yaml); } #[test] fn test_nested_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Outer { inner: Inner, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Inner { v: u16, } let thing = Outer { inner: Inner { v: 512 }, }; let yaml = indoc! {" --- inner: v: 512 "}; test_serde(&thing, yaml); } #[test] fn test_option() { let thing = vec![Some(1), None, Some(3)]; let yaml = indoc! {" --- - 1 - ~ - 3 "}; test_serde(&thing, yaml); } #[test] fn test_unit() { let thing = vec![(), ()]; let yaml = indoc! {" --- - ~ - ~ "}; test_serde(&thing, yaml); } #[test] fn test_unit_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Foo; let thing = Foo; let yaml = indoc! {" --- ~ "}; test_serde(&thing, yaml); } #[test] fn test_unit_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { First, Second, } let thing = Variant::First; let yaml = indoc! {" --- First "}; test_serde(&thing, yaml); } #[test] fn test_newtype_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct OriginalType { v: u16, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NewType(OriginalType); let thing = NewType(OriginalType { v: 1 }); let yaml = indoc! {" --- v: 1 "}; test_serde(&thing, yaml); } #[test] fn test_newtype_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { Size(usize), } let thing = Variant::Size(127); let yaml = indoc! {" --- Size: 127 "}; test_serde(&thing, yaml); } #[test] fn test_tuple_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { Rgb(u8, u8, u8), } let thing = Variant::Rgb(32, 64, 96); let yaml = indoc! {" --- Rgb: - 32 - 64 - 96 "}; test_serde(&thing, yaml); } #[test] fn test_struct_variant() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum Variant { Color { r: u8, g: u8, b: u8 }, } let thing = Variant::Color { r: 32, g: 64, b: 96, }; let yaml = indoc! {" --- Color: r: 32 g: 64 b: 96 "}; test_serde(&thing, yaml); } #[test] fn test_value() { use serde_yaml::{Mapping, Number}; #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct GenericInstructions { #[serde(rename = "type")] pub typ: String, pub config: Value, } let thing = GenericInstructions { typ: "primary".to_string(), config: Value::Sequence(vec![ Value::Null, Value::Bool(true), Value::Number(Number::from(65535)), Value::Number(Number::from(0.54321)), Value::String("s".into()), Value::Mapping(Mapping::new()), ]), }; let yaml = indoc! {" --- type: primary config: - ~ - true - 65535 - 0.54321 - s - {} "}; test_serde(&thing, yaml); } #[test] fn test_mapping() { use serde_yaml::Mapping; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Data { pub substructure: Mapping, } let mut thing = Data { substructure: Mapping::new(), }; thing.substructure.insert( Value::String("a".to_owned()), Value::String("foo".to_owned()), ); thing.substructure.insert( Value::String("b".to_owned()), Value::String("bar".to_owned()), ); let yaml = indoc! {" --- substructure: a: foo b: bar "}; test_serde(&thing, yaml); } serde_yaml-0.8.26/tests/test_value.rs000064400000000000000000000031501046102023000157270ustar 00000000000000#![allow(clippy::derive_partial_eq_without_eq, clippy::eq_op)] use serde::de::IntoDeserializer; use serde::Deserialize; use serde_derive::Deserialize; use serde_yaml::{Number, Value}; use std::f64; #[test] fn test_nan() { let pos_nan = serde_yaml::from_str::(".nan").unwrap(); assert!(pos_nan.is_f64()); assert_eq!(pos_nan, pos_nan); let neg_fake_nan = serde_yaml::from_str::("-.nan").unwrap(); assert!(neg_fake_nan.is_string()); let significand_mask = 0xF_FFFF_FFFF_FFFF; let bits = (f64::NAN.to_bits() ^ significand_mask) | 1; let different_pos_nan = Value::Number(Number::from(f64::from_bits(bits))); assert_eq!(pos_nan, different_pos_nan); } #[test] fn test_digits() { let num_string = serde_yaml::from_str::("01").unwrap(); assert!(num_string.is_string()); } #[test] fn test_into_deserializer() { #[derive(Debug, Deserialize, PartialEq)] struct Test { first: String, second: u32, } let value = serde_yaml::from_str::("xyz").unwrap(); let s = String::deserialize(value.into_deserializer()).unwrap(); assert_eq!(s, "xyz"); let value = serde_yaml::from_str::("- first\n- second\n- third").unwrap(); let arr = Vec::::deserialize(value.into_deserializer()).unwrap(); assert_eq!(arr, &["first", "second", "third"]); let value = serde_yaml::from_str::("first: abc\nsecond: 99").unwrap(); let test = Test::deserialize(value.into_deserializer()).unwrap(); assert_eq!( test, Test { first: "abc".to_string(), second: 99 } ); }