summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_yaml
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/serde_yaml
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--third_party/rust/serde_yaml/.cargo-checksum.json1
-rw-r--r--third_party/rust/serde_yaml/Cargo.toml53
-rw-r--r--third_party/rust/serde_yaml/LICENSE-APACHE201
-rw-r--r--third_party/rust/serde_yaml/LICENSE-MIT23
-rw-r--r--third_party/rust/serde_yaml/README.md104
-rw-r--r--third_party/rust/serde_yaml/src/de.rs1525
-rw-r--r--third_party/rust/serde_yaml/src/error.rs244
-rw-r--r--third_party/rust/serde_yaml/src/lib.rs125
-rw-r--r--third_party/rust/serde_yaml/src/mapping.rs512
-rw-r--r--third_party/rust/serde_yaml/src/number.rs550
-rw-r--r--third_party/rust/serde_yaml/src/path.rs34
-rw-r--r--third_party/rust/serde_yaml/src/ser.rs887
-rw-r--r--third_party/rust/serde_yaml/src/value/de.rs707
-rw-r--r--third_party/rust/serde_yaml/src/value/from.rs180
-rw-r--r--third_party/rust/serde_yaml/src/value/index.rs260
-rw-r--r--third_party/rust/serde_yaml/src/value/mod.rs648
-rw-r--r--third_party/rust/serde_yaml/src/value/partial_eq.rs149
-rw-r--r--third_party/rust/serde_yaml/src/value/ser.rs25
-rw-r--r--third_party/rust/serde_yaml/tests/test_de.rs396
-rw-r--r--third_party/rust/serde_yaml/tests/test_error.rs287
-rw-r--r--third_party/rust/serde_yaml/tests/test_serde.rs434
-rw-r--r--third_party/rust/serde_yaml/tests/test_value.rs55
22 files changed, 7400 insertions, 0 deletions
diff --git a/third_party/rust/serde_yaml/.cargo-checksum.json b/third_party/rust/serde_yaml/.cargo-checksum.json
new file mode 100644
index 0000000000..eb1d4afddc
--- /dev/null
+++ b/third_party/rust/serde_yaml/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"1e01ffba9fa6c48ceda8bd7b3b936b5909c7adbfb05b6a5f8deb3f679d7da37e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8b6df65d390bc4f9d5e05d0a4ccc860d6e5dc2668d82cd304e6c95b472a21f35","src/de.rs":"414b82334d78cf57b7cdc2fc1ed000594791b2f675648f5286678370f460a74d","src/error.rs":"96a49b8ea102d010760b3ade9b475d0c88d4014c17625302ddc145a9fea2988c","src/lib.rs":"a3276a7da395021e34547fe2f4336a5658f07d4d606a865b707a592f7b084e10","src/mapping.rs":"6607911090c89a41ade38f1717b9c0bd6c3c253cc4711890b77b2bda18d6bac7","src/number.rs":"4edf78ad75bf66bae31c1ee4d785ba2b7a2c14c082802d54c9feb93067bcf063","src/path.rs":"44d339ce1814effd10ba131ae0393df215f09dbfb35ab4d678f49d4081f58dd4","src/ser.rs":"e32c77b3e8087ca1b68a8f093e9f1e27b93ad1aac70a9bb22054b4179973cae1","src/value/de.rs":"84b213b23a8d4bf6bd9aacd18fc1091254382c4edc479f9a9abc87c416b370f0","src/value/from.rs":"cd66c76c4ab03bed32f8c4b22ffbd96274a837d587624a62d0584c7090633862","src/value/index.rs":"16f0e4fecd4a4cd149af89a7426864f58735f7dacc90f33d92c647b044c8f112","src/value/mod.rs":"171a98133de3445ccd4cfa3991b5c3f96baa1c05542fc1927e6eccf3e4ddbe09","src/value/partial_eq.rs":"0b28c8d2f10a58581dbe2a69d25742fa0f8bf3da797f3046e38e300d1f9691bf","src/value/ser.rs":"7ddb9bfadfbfe16a79c872888ea25f8fb7df14b862fea47dd603d576e162db86","tests/test_de.rs":"c7d8d71e8b0aa966ad4003657c1024405abeca0d49aec9f66f749db81bb1f061","tests/test_error.rs":"4ef5c9001f140e1aee1e9d6238c668d26b5b264e237773741d5f65bfff036e75","tests/test_serde.rs":"56aa2623b1aca1ba00d028edc60d6f74cde6eba83529d5bcd3340c4b0487db04","tests/test_value.rs":"f360eeaa7d281d52df18a452a6f67c6095bcf50b92f1a87c5a9e3c27b7a69f33"},"package":"578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"} \ No newline at end of file
diff --git a/third_party/rust/serde_yaml/Cargo.toml b/third_party/rust/serde_yaml/Cargo.toml
new file mode 100644
index 0000000000..3fd065aa35
--- /dev/null
+++ b/third_party/rust/serde_yaml/Cargo.toml
@@ -0,0 +1,53 @@
+# 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 <dtolnay@gmail.com>"]
+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"
diff --git a/third_party/rust/serde_yaml/LICENSE-APACHE b/third_party/rust/serde_yaml/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/serde_yaml/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ 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.
diff --git a/third_party/rust/serde_yaml/LICENSE-MIT b/third_party/rust/serde_yaml/LICENSE-MIT
new file mode 100644
index 0000000000..31aa79387f
--- /dev/null
+++ b/third_party/rust/serde_yaml/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission 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.
diff --git a/third_party/rust/serde_yaml/README.md b/third_party/rust/serde_yaml/README.md
new file mode 100644
index 0000000000..4500865cb0
--- /dev/null
+++ b/third_party/rust/serde_yaml/README.md
@@ -0,0 +1,104 @@
+Serde YAML
+==========
+
+[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/serde--yaml-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/serde-yaml)
+[<img alt="crates.io" src="https://img.shields.io/crates/v/serde_yaml.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/serde_yaml)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-serde__yaml-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/serde_yaml)
+[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/serde-yaml/CI/master?style=for-the-badge" height="20">](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<String, f64> = 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(())
+}
+```
+
+<br>
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+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.
+</sub>
diff --git a/third_party/rust/serde_yaml/src/de.rs b/third_party/rust/serde_yaml/src/de.rs
new file mode 100644
index 0000000000..8ccf271093
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/de.rs
@@ -0,0 +1,1525 @@
+use 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<dyn io::Read + 'a>),
+ Multidoc(Arc<Multidoc>),
+ Fail(Arc<ErrorImpl>),
+}
+
+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<R>(rdr: R) -> Self
+ where
+ R: io::Read + 'a,
+ {
+ let input = Input::Read(Box::new(rdr));
+ Deserializer { input }
+ }
+
+ fn de<T>(self, f: impl FnOnce(&mut DeserializerFromEvents) -> Result<T>) -> Result<T> {
+ 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<Loader> {
+ 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<Self> {
+ 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<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_any(visitor))
+ }
+
+ fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_bool(visitor))
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_i8(visitor))
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_i16(visitor))
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_i32(visitor))
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_i64(visitor))
+ }
+
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_i128(visitor))
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_u8(visitor))
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_u16(visitor))
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_u32(visitor))
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_u64(visitor))
+ }
+
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_u128(visitor))
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_f32(visitor))
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_f64(visitor))
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_char(visitor))
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_str(visitor))
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_string(visitor))
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_bytes(visitor))
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_byte_buf(visitor))
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_option(visitor))
+ }
+
+ fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_unit(visitor))
+ }
+
+ fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_unit_struct(name, visitor))
+ }
+
+ fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_newtype_struct(name, visitor))
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_seq(visitor))
+ }
+
+ fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_tuple(len, visitor))
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ name: &'static str,
+ len: usize,
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_tuple_struct(name, len, visitor))
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_map(visitor))
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_struct(name, fields, visitor))
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ name: &'static str,
+ variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_enum(name, variants, visitor))
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.de(|state| state.deserialize_identifier(visitor))
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
+ 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<usize, usize>,
+}
+
+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<TokenType>),
+ SequenceStart,
+ SequenceEnd,
+ MappingStart,
+ MappingEnd,
+}
+
+struct DeserializerFromEvents<'a> {
+ events: &'a [(Event, Marker)],
+ /// Map from alias id to index in events.
+ aliases: &'a BTreeMap<usize, usize>,
+ 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<DeserializerFromEvents<'a>> {
+ 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<V::Value>
+ 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<V::Value>
+ 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::<Ignore>(&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::<Ignore, Ignore>(&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<F: FnOnce(&mut Self) -> Result<T>, T>(&mut self, f: F) -> Result<T> {
+ 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<TokenType>,
+ visitor: V,
+) -> Result<V::Value>
+where
+ V: Visitor<'de>,
+{
+ if let Some(TokenType::Tag(handle, suffix)) = tag {
+ if handle == "!!" {
+ match suffix.as_ref() {
+ "bool" => match v.parse::<bool>() {
+ Ok(v) => visitor.visit_bool(v),
+ Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a boolean")),
+ },
+ "int" => match v.parse::<i64>() {
+ Ok(v) => visitor.visit_i64(v),
+ Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"an integer")),
+ },
+ "float" => match v.parse::<f64>() {
+ 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<T>(&mut self, seed: T) -> Result<Option<T::Value>>
+ 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<K>(&mut self, seed: K) -> Result<Option<K::Value>>
+ 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<V>(&mut self, seed: V) -> Result<V::Value>
+ 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<V>(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::<Error>::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<T>(mut self, seed: T) -> Result<T::Value>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ seed.deserialize(&mut self)
+ }
+
+ fn tuple_variant<V>(mut self, _len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ de::Deserializer::deserialize_seq(&mut self, visitor)
+ }
+
+ fn struct_variant<V>(mut self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
+ 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<V>(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<T>(self, _seed: T) -> Result<T::Value>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ Err(de::Error::invalid_type(
+ Unexpected::UnitVariant,
+ &"newtype variant",
+ ))
+ }
+
+ fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ Err(de::Error::invalid_type(
+ Unexpected::UnitVariant,
+ &"tuple variant",
+ ))
+ }
+
+ fn struct_variant<V>(self, _fields: &'static [&'static str], _visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ Err(de::Error::invalid_type(
+ Unexpected::UnitVariant,
+ &"struct variant",
+ ))
+ }
+}
+
+fn visit_untagged_str<'de, V>(visitor: V, v: &str) -> Result<V::Value>
+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::<f64>() {
+ 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<V::Value>
+ 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<V>(self, visitor: V) -> Result<V::Value>
+ 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<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_str(visitor)
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+ 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<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_str(visitor)
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_any(visitor)
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_bytes(visitor)
+ }
+
+ /// Parses `null` as None and any other values as `Some(...)`.
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
+ 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<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_scalar(visitor)
+ }
+
+ fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_unit(visitor)
+ }
+
+ /// Parses a newtype struct as the underlying value.
+ fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_newtype_struct(self)
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
+ 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<V>(self, _len: usize, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ _name: &'static str,
+ _len: usize,
+ visitor: V,
+ ) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
+ 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<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ 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<V>(
+ self,
+ name: &'static str,
+ variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value>
+ 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<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_str(visitor)
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
+ 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<T>(s: &str) -> Result<T>
+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<T, S>(s: &str, seed: S) -> Result<T>
+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<R, T>(rdr: R) -> Result<T>
+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<R, T, S>(rdr: R, seed: S) -> Result<T>
+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<T>(v: &[u8]) -> Result<T>
+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<T, S>(v: &[u8], seed: S) -> Result<T>
+where
+ S: for<'de> DeserializeSeed<'de, Value = T>,
+{
+ seed.deserialize(Deserializer::from_slice(v))
+}
diff --git a/third_party/rust/serde_yaml/src/error.rs b/third_party/rust/serde_yaml/src/error.rs
new file mode 100644
index 0000000000..dc8321435f
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/error.rs
@@ -0,0 +1,244 @@
+use 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<ErrorImpl>);
+
+/// Alias for a `Result` with the error type `serde_yaml::Error`.
+pub type Result<T> = result::Result<T, Error>;
+
+#[derive(Debug)]
+pub enum ErrorImpl {
+ Message(String, Option<Pos>),
+
+ Emit(emitter::EmitError),
+ Scan(scanner::ScanError),
+ Io(io::Error),
+ Utf8(str::Utf8Error),
+ FromUtf8(string::FromUtf8Error),
+
+ EndOfStream,
+ MoreThanOneDocument,
+ RecursionLimitExceeded,
+
+ Shared(Arc<ErrorImpl>),
+}
+
+#[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<Value, Error> = 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<Location> {
+ 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<ErrorImpl>) -> 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<ErrorImpl> {
+ 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<T: Display>(msg: T) -> Self {
+ Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
+ }
+}
+
+impl de::Error for Error {
+ fn custom<T: Display>(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),
+ }
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/lib.rs b/third_party/rust/serde_yaml/src/lib.rs
new file mode 100644
index 0000000000..f3fc6a9d3c
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/lib.rs
@@ -0,0 +1,125 @@
+//! [![github]](https://github.com/dtolnay/serde-yaml)&ensp;[![crates-io]](https://crates.io/crates/serde-yaml)&ensp;[![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
+//!
+//! <br>
+//!
+//! 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<String, f64> = 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;
diff --git a/third_party/rust/serde_yaml/src/mapping.rs b/third_party/rust/serde_yaml/src/mapping.rs
new file mode 100644
index 0000000000..89f6e413a0
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/mapping.rs
@@ -0,0 +1,512 @@
+//! 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<Value, Value>,
+}
+
+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<Value> {
+ 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<Value> {
+ 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<H: Hasher>(&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<Ordering> {
+ 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<I, F>(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<I: IntoIterator<Item = (Value, Value)>>(&mut self, iter: I) {
+ self.map.extend(iter);
+ }
+}
+
+impl FromIterator<(Value, Value)> for Mapping {
+ #[inline]
+ fn from_iter<I: IntoIterator<Item = (Value, Value)>>(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::Item> {
+ self.iter.next()
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<Value, Value>,
+}
+
+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<F>(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<F>(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<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+ 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<D>(deserializer: D) -> Result<Self, D::Error>
+ 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<E>(self) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ Ok(Mapping::new())
+ }
+
+ #[inline]
+ fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
+ 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)
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/number.rs b/third_party/rust/serde_yaml/src/number.rs
new file mode 100644
index 0000000000..b3643ba8b1
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/number.rs
@@ -0,0 +1,550 @@
+use 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<i64> {
+ 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<u64> {
+ 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<f64> {
+ 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<Ordering> {
+ 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<D>(deserializer: D) -> Result<Number, D::Error>
+ 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<E>(self, value: i64) -> Result<Number, E> {
+ Ok(value.into())
+ }
+
+ #[inline]
+ fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
+ Ok(value.into())
+ }
+
+ #[inline]
+ fn visit_f64<E>(self, value: f64) -> Result<Number, E> {
+ Ok(value.into())
+ }
+ }
+
+ deserializer.deserialize_any(NumberVisitor)
+ }
+}
+
+impl<'de> Deserializer<'de> for Number {
+ type Error = Error;
+
+ #[inline]
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ 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<V>(self, visitor: V) -> Result<V::Value, Error>
+ 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<H: Hasher>(&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),
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/path.rs b/third_party/rust/serde_yaml/src/path.rs
new file mode 100644
index 0000000000..095add017b
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/path.rs
@@ -0,0 +1,34 @@
+use 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)),
+ }
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/ser.rs b/third_party/rust/serde_yaml/src/ser.rs
new file mode 100644
index 0000000000..6ce5995dff
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/ser.rs
@@ -0,0 +1,887 @@
+//! 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<W> {
+ documents: usize,
+ writer: W,
+}
+
+impl<W> Serializer<W>
+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<W>
+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<T>(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<T>(
+ 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<V>(self, value: &V) -> Result<()>
+ where
+ V: ?Sized + ser::Serialize,
+ {
+ let doc = SerializerToYaml.serialize_some(value)?;
+ self.write(doc)
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
+ let delegate = SerializerToYaml.serialize_seq(len)?;
+ Ok(ThenWrite::new(self, delegate))
+ }
+
+ fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
+ let delegate = SerializerToYaml.serialize_tuple(len)?;
+ Ok(ThenWrite::new(self, delegate))
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleStruct> {
+ 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<Self::SerializeTupleVariant> {
+ let delegate = SerializerToYaml.serialize_tuple_variant(enm, idx, variant, len)?;
+ Ok(ThenWrite::new(self, delegate))
+ }
+
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
+ let delegate = SerializerToYaml.serialize_map(len)?;
+ Ok(ThenWrite::new(self, delegate))
+ }
+
+ fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
+ 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<Self::SerializeStructVariant> {
+ 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<W>,
+ delegate: D,
+}
+
+impl<'a, W, D> ThenWrite<'a, W, D> {
+ fn new(serializer: &'a mut Serializer<W>, 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<T>(&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<T>(&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<V>(&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<V>(&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<T>(&mut self, key: &T) -> Result<()>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ self.delegate.serialize_key(key)
+ }
+
+ fn serialize_value<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ self.delegate.serialize_value(value)
+ }
+
+ fn serialize_entry<K, V>(&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<V>(&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<V>(&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<Yaml> {
+ Ok(Yaml::Boolean(v))
+ }
+
+ fn serialize_i8(self, v: i8) -> Result<Yaml> {
+ self.serialize_i64(v as i64)
+ }
+
+ fn serialize_i16(self, v: i16) -> Result<Yaml> {
+ self.serialize_i64(v as i64)
+ }
+
+ fn serialize_i32(self, v: i32) -> Result<Yaml> {
+ self.serialize_i64(v as i64)
+ }
+
+ fn serialize_i64(self, v: i64) -> Result<Yaml> {
+ Ok(Yaml::Integer(v))
+ }
+
+ #[allow(clippy::cast_possible_truncation)]
+ fn serialize_i128(self, v: i128) -> Result<Yaml> {
+ 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<Yaml> {
+ self.serialize_i64(v as i64)
+ }
+
+ fn serialize_u16(self, v: u16) -> Result<Yaml> {
+ self.serialize_i64(v as i64)
+ }
+
+ fn serialize_u32(self, v: u32) -> Result<Yaml> {
+ self.serialize_i64(v as i64)
+ }
+
+ fn serialize_u64(self, v: u64) -> Result<Yaml> {
+ 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<Yaml> {
+ 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<Yaml> {
+ 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<Yaml> {
+ 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<Yaml> {
+ Ok(Yaml::String(value.to_string()))
+ }
+
+ fn serialize_str(self, value: &str) -> Result<Yaml> {
+ Ok(Yaml::String(value.to_owned()))
+ }
+
+ fn serialize_bytes(self, value: &[u8]) -> Result<Yaml> {
+ let vec = value.iter().map(|&b| Yaml::Integer(b as i64)).collect();
+ Ok(Yaml::Array(vec))
+ }
+
+ fn serialize_unit(self) -> Result<Yaml> {
+ Ok(Yaml::Null)
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Yaml> {
+ self.serialize_unit()
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &str,
+ _variant_index: u32,
+ variant: &str,
+ ) -> Result<Yaml> {
+ Ok(Yaml::String(variant.to_owned()))
+ }
+
+ fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Yaml>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ value.serialize(self)
+ }
+
+ fn serialize_newtype_variant<T>(
+ self,
+ _name: &str,
+ _variant_index: u32,
+ variant: &str,
+ value: &T,
+ ) -> Result<Yaml>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ Ok(singleton_hash(to_yaml(variant)?, to_yaml(value)?))
+ }
+
+ fn serialize_none(self) -> Result<Yaml> {
+ self.serialize_unit()
+ }
+
+ fn serialize_some<V>(self, value: &V) -> Result<Yaml>
+ where
+ V: ?Sized + ser::Serialize,
+ {
+ value.serialize(self)
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<SerializeArray> {
+ 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<SerializeArray> {
+ self.serialize_seq(Some(len))
+ }
+
+ fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result<SerializeArray> {
+ self.serialize_seq(Some(len))
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _enum: &'static str,
+ _idx: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<SerializeTupleVariant> {
+ Ok(SerializeTupleVariant {
+ name: variant,
+ array: yaml::Array::with_capacity(len),
+ })
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> Result<SerializeMap> {
+ Ok(SerializeMap {
+ hash: yaml::Hash::new(),
+ next_key: None,
+ })
+ }
+
+ fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<SerializeStruct> {
+ Ok(SerializeStruct {
+ hash: yaml::Hash::new(),
+ })
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _enum: &'static str,
+ _idx: u32,
+ variant: &'static str,
+ _len: usize,
+ ) -> Result<SerializeStructVariant> {
+ 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<yaml::Yaml>,
+}
+
+#[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<T>(&mut self, elem: &T) -> Result<()>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ self.array.push(to_yaml(elem)?);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Yaml> {
+ Ok(Yaml::Array(self.array))
+ }
+}
+
+impl ser::SerializeTuple for SerializeArray {
+ type Ok = yaml::Yaml;
+ type Error = Error;
+
+ fn serialize_element<T>(&mut self, elem: &T) -> Result<()>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ ser::SerializeSeq::serialize_element(self, elem)
+ }
+
+ fn end(self) -> Result<Yaml> {
+ ser::SerializeSeq::end(self)
+ }
+}
+
+impl ser::SerializeTupleStruct for SerializeArray {
+ type Ok = yaml::Yaml;
+ type Error = Error;
+
+ fn serialize_field<V>(&mut self, value: &V) -> Result<()>
+ where
+ V: ?Sized + ser::Serialize,
+ {
+ ser::SerializeSeq::serialize_element(self, value)
+ }
+
+ fn end(self) -> Result<Yaml> {
+ ser::SerializeSeq::end(self)
+ }
+}
+
+impl ser::SerializeTupleVariant for SerializeTupleVariant {
+ type Ok = yaml::Yaml;
+ type Error = Error;
+
+ fn serialize_field<V>(&mut self, v: &V) -> Result<()>
+ where
+ V: ?Sized + ser::Serialize,
+ {
+ self.array.push(to_yaml(v)?);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Yaml> {
+ 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<T>(&mut self, key: &T) -> Result<()>
+ where
+ T: ?Sized + ser::Serialize,
+ {
+ self.next_key = Some(to_yaml(key)?);
+ Ok(())
+ }
+
+ fn serialize_value<T>(&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<K, V>(&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<Yaml> {
+ Ok(Yaml::Hash(self.hash))
+ }
+}
+
+impl ser::SerializeStruct for SerializeStruct {
+ type Ok = yaml::Yaml;
+ type Error = Error;
+
+ fn serialize_field<V>(&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<Yaml> {
+ Ok(Yaml::Hash(self.hash))
+ }
+}
+
+impl ser::SerializeStructVariant for SerializeStructVariant {
+ type Ok = yaml::Yaml;
+ type Error = Error;
+
+ fn serialize_field<V>(&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<Yaml> {
+ 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<W, T>(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<T>(value: &T) -> Result<Vec<u8>>
+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<T>(value: &T) -> Result<String>
+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<W> {
+ writer: W,
+}
+
+impl<W> fmt::Write for FmtToIoWriter<W>
+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<T>(elem: T) -> Result<Yaml>
+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)
+}
diff --git a/third_party/rust/serde_yaml/src/value/de.rs b/third_party/rust/serde_yaml/src/value/de.rs
new file mode 100644
index 0000000000..61e0469693
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/value/de.rs
@@ -0,0 +1,707 @@
+use 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<D>(deserializer: D) -> Result<Self, D::Error>
+ 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<E>(self, b: bool) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::Bool(b))
+ }
+
+ fn visit_i64<E>(self, i: i64) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::Number(i.into()))
+ }
+
+ fn visit_u64<E>(self, u: u64) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::Number(u.into()))
+ }
+
+ fn visit_f64<E>(self, f: f64) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::Number(f.into()))
+ }
+
+ fn visit_str<E>(self, s: &str) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::String(s.to_owned()))
+ }
+
+ fn visit_string<E>(self, s: String) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::String(s))
+ }
+
+ fn visit_unit<E>(self) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::Null)
+ }
+
+ fn visit_none<E>(self) -> Result<Value, E>
+ where
+ E: SError,
+ {
+ Ok(Value::Null)
+ }
+
+ fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Deserialize::deserialize(deserializer)
+ }
+
+ fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
+ 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<V>(self, mut visitor: V) -> Result<Value, V::Error>
+ 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<V::Value, Error>
+ 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<V::Value, Error>
+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<V::Value, Error>
+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<V>(self, visitor: V) -> Result<V::Value, Error>
+ 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<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Bool(v) => visitor.visit_bool(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_number(visitor)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_string(visitor)
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_string(visitor)
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::String(v) => visitor.visit_string(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_byte_buf(visitor)
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Error>
+ 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<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Null => visitor.visit_none(),
+ _ => visitor.visit_some(self),
+ }
+ }
+
+ fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Null => visitor.visit_unit(),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_unit(visitor)
+ }
+
+ fn deserialize_newtype_struct<V>(
+ self,
+ _name: &'static str,
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_newtype_struct(self)
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Sequence(v) => visit_sequence(v, visitor),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ _name: &'static str,
+ _len: usize,
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self {
+ Value::Mapping(v) => visit_mapping(v, visitor),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ _name: &'static str,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ 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<V>(
+ self,
+ _name: &str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ 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<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_string(visitor)
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ drop(self);
+ visitor.visit_unit()
+ }
+}
+
+struct EnumDeserializer {
+ variant: Value,
+ value: Option<Value>,
+}
+
+impl<'de> EnumAccess<'de> for EnumDeserializer {
+ type Error = Error;
+ type Variant = VariantDeserializer;
+
+ fn variant_seed<V>(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<Value>,
+}
+
+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<T>(self, seed: T) -> Result<T::Value, Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.value {
+ Some(value) => seed.deserialize(value),
+ None => Err(Error::invalid_type(
+ Unexpected::UnitVariant,
+ &"newtype variant",
+ )),
+ }
+ }
+
+ fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
+ 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<V>(
+ self,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ 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<Value>,
+}
+
+impl SeqDeserializer {
+ fn new(vec: Vec<Value>) -> Self {
+ SeqDeserializer {
+ iter: vec.into_iter(),
+ }
+ }
+}
+
+impl<'de> Deserializer<'de> for SeqDeserializer {
+ type Error = Error;
+
+ #[inline]
+ fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Error>
+ 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<V>(self, visitor: V) -> Result<V::Value, Error>
+ 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<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.iter.next() {
+ Some(value) => seed.deserialize(value).map(Some),
+ None => Ok(None),
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ match self.iter.size_hint() {
+ (lower, Some(upper)) if lower == upper => Some(upper),
+ _ => None,
+ }
+ }
+}
+
+struct MapDeserializer {
+ iter: <Mapping as IntoIterator>::IntoIter,
+ value: Option<Value>,
+}
+
+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<T>(&mut self, seed: T) -> Result<Option<T::Value>, 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<T>(&mut self, seed: T) -> Result<T::Value, Error>
+ 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<usize> {
+ 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<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_map(self)
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ 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<E>(&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,
+ }
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/value/from.rs b/third_party/rust/serde_yaml/src/value/from.rs
new file mode 100644
index 0000000000..c02855d3b1
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/value/from.rs
@@ -0,0 +1,180 @@
+use 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<bool> 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<String> 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<Cow<'a, str>> for Value {
+ /// Convert copy-on-write string to `Value`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use serde_yaml::Value;
+ /// use std::borrow::Cow;
+ ///
+ /// let s: Cow<str> = Cow::Borrowed("lorem");
+ /// let x: Value = s.into();
+ /// ```
+ ///
+ /// ```
+ /// use serde_yaml::Value;
+ /// use std::borrow::Cow;
+ ///
+ /// let s: Cow<str> = Cow::Owned("lorem".to_string());
+ /// let x: Value = s.into();
+ /// ```
+ fn from(f: Cow<'a, str>) -> Self {
+ Value::String(f.to_string())
+ }
+}
+
+impl From<Mapping> 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<T: Into<Value>> From<Vec<T>> 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<T>) -> Self {
+ Value::Sequence(f.into_iter().map(Into::into).collect())
+ }
+}
+
+impl<'a, T: Clone + Into<Value>> 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<T: Into<Value>> FromIterator<T> 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<I: IntoIterator<Item = T>>(iter: I) -> Self {
+ let vec = iter.into_iter().map(T::into).collect();
+
+ Value::Sequence(vec)
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/value/index.rs b/third_party/rust/serde_yaml/src/value/index.rs
new file mode 100644
index 0000000000..b5f5e90160
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/value/index.rs
@@ -0,0 +1,260 @@
+use 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<I> ops::Index<I> 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<I> ops::IndexMut<I> 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)
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/value/mod.rs b/third_party/rust/serde_yaml/src/value/mod.rs
new file mode 100644
index 0000000000..a71091bffb
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/value/mod.rs
@@ -0,0 +1,648 @@
+mod 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<Value>;
+
+/// 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<T>(value: T) -> Result<Value, Error>
+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<T>(value: Value) -> Result<T, Error>
+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<I: Index>(&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<I: Index>(&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<bool> {
+ 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<i64> {
+ 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<u64> {
+ 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<f64> {
+ 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<H: Hasher>(&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
+ }
+}
diff --git a/third_party/rust/serde_yaml/src/value/partial_eq.rs b/third_party/rust/serde_yaml/src/value/partial_eq.rs
new file mode 100644
index 0000000000..ff9b1f8f8a
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/value/partial_eq.rs
@@ -0,0 +1,149 @@
+use 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<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<'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<Value> 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<Value> 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<String> 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<Value> 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<bool> 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<Value> 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
+}
diff --git a/third_party/rust/serde_yaml/src/value/ser.rs b/third_party/rust/serde_yaml/src/value/ser.rs
new file mode 100644
index 0000000000..f2c4bb438c
--- /dev/null
+++ b/third_party/rust/serde_yaml/src/value/ser.rs
@@ -0,0 +1,25 @@
+use crate::Value;
+use serde::Serialize;
+
+impl Serialize for Value {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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()
+ }
+ }
+ }
+}
diff --git a/third_party/rust/serde_yaml/tests/test_de.rs b/third_party/rust/serde_yaml/tests/test_de.rs
new file mode 100644
index 0000000000..e3a8c0da12
--- /dev/null
+++ b/third_party/rust/serde_yaml/tests/test_de.rs
@@ -0,0 +1,396 @@
+#![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<T>(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::<serde_yaml::Value>(yaml).unwrap();
+ serde_yaml::from_str::<serde::de::IgnoredAny>(yaml).unwrap();
+}
+
+fn test_de_seed<T, S>(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::<serde_yaml::Value>(yaml).unwrap();
+ serde_yaml::from_str::<serde::de::IgnoredAny>(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<f64>,
+ b: Option<String>,
+ c: Option<bool>,
+ }
+ 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<f64>,
+ b: Option<String>,
+ c: Option<bool>,
+ d: Option<f64>,
+ e: Option<String>,
+ f: Option<bool>,
+ }
+ 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::<i128>(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::<u128>(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::<Data>(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::<Value>(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::<Value>(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<D>(self, deserializer: D) -> Result<i64, D::Error>
+ 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<E: serde::de::Error>(self, v: i64) -> Result<i64, E> {
+ Ok(v * self.0)
+ }
+
+ fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<i64, E> {
+ 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);
+ }
+}
diff --git a/third_party/rust/serde_yaml/tests/test_error.rs b/third_party/rust/serde_yaml/tests/test_error.rs
new file mode 100644
index 0000000000..bd830c0fc0
--- /dev/null
+++ b/third_party/rust/serde_yaml/tests/test_error.rs
@@ -0,0 +1,287 @@
+use indoc::indoc;
+use serde_derive::Deserialize;
+use std::fmt::Debug;
+
+fn test_error<T>(yaml: &str, expected: &str)
+where
+ T: serde::de::DeserializeOwned + Debug,
+{
+ let result = serde_yaml::from_str::<T>(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::<i16>(yaml, expected);
+}
+
+#[test]
+fn test_incorrect_nested_type() {
+ #[derive(Deserialize, Debug)]
+ struct A {
+ #[allow(dead_code)]
+ b: Vec<B>,
+ }
+ #[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::<A>(yaml, expected);
+}
+
+#[test]
+fn test_empty() {
+ let expected = "EOF while parsing a value";
+ test_error::<String>("", 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::<Basic>(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::<String>(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::<Wrapper>(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::<usize>(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::<E>(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::<E>(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::<E>(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::<bool>(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::<i64>(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::<f64>(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::Value, serde_yaml::Error> =
+ 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::<S>(yaml, expected);
+}
+
+#[test]
+fn test_infinite_recursion_objects() {
+ #[derive(Deserialize, Debug)]
+ struct S {
+ #[allow(dead_code)]
+ x: Option<Box<S>>,
+ }
+
+ let yaml = "&a {x: *a}";
+ let expected = "recursion limit exceeded";
+ test_error::<S>(yaml, expected);
+}
+
+#[test]
+fn test_infinite_recursion_arrays() {
+ #[derive(Deserialize, Debug)]
+ struct S {
+ #[allow(dead_code)]
+ x: Option<Box<S>>,
+ }
+
+ let yaml = "&a [*a]";
+ let expected = "recursion limit exceeded";
+ test_error::<S>(yaml, expected);
+}
+
+#[test]
+fn test_finite_recursion_objects() {
+ #[derive(Deserialize, Debug)]
+ struct S {
+ #[allow(dead_code)]
+ x: Option<Box<S>>,
+ }
+
+ let yaml = "{x:".repeat(1_000) + &"}".repeat(1_000);
+ let expected = "recursion limit exceeded at line 1 column 766";
+ test_error::<i32>(&yaml, expected);
+}
+
+#[test]
+fn test_finite_recursion_arrays() {
+ #[derive(Deserialize, Debug)]
+ struct S {
+ #[allow(dead_code)]
+ x: Option<Box<S>>,
+ }
+
+ let yaml = "[".repeat(1_000) + &"]".repeat(1_000);
+ let expected = "recursion limit exceeded at line 1 column 256";
+ test_error::<S>(&yaml, expected);
+}
diff --git a/third_party/rust/serde_yaml/tests/test_serde.rs b/third_party/rust/serde_yaml/tests/test_serde.rs
new file mode 100644
index 0000000000..8b3f34b3fc
--- /dev/null
+++ b/third_party/rust/serde_yaml/tests/test_serde.rs
@@ -0,0 +1,434 @@
+#![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<T>(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::<serde::de::IgnoredAny>(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);
+}
diff --git a/third_party/rust/serde_yaml/tests/test_value.rs b/third_party/rust/serde_yaml/tests/test_value.rs
new file mode 100644
index 0000000000..c001b9d73d
--- /dev/null
+++ b/third_party/rust/serde_yaml/tests/test_value.rs
@@ -0,0 +1,55 @@
+#![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::<Value>(".nan").unwrap();
+ assert!(pos_nan.is_f64());
+ assert_eq!(pos_nan, pos_nan);
+
+ let neg_fake_nan = serde_yaml::from_str::<Value>("-.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::<Value>("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::<Value>("xyz").unwrap();
+ let s = String::deserialize(value.into_deserializer()).unwrap();
+ assert_eq!(s, "xyz");
+
+ let value = serde_yaml::from_str::<Value>("- first\n- second\n- third").unwrap();
+ let arr = Vec::<String>::deserialize(value.into_deserializer()).unwrap();
+ assert_eq!(arr, &["first", "second", "third"]);
+
+ let value = serde_yaml::from_str::<Value>("first: abc\nsecond: 99").unwrap();
+ let test = Test::deserialize(value.into_deserializer()).unwrap();
+ assert_eq!(
+ test,
+ Test {
+ first: "abc".to_string(),
+ second: 99
+ }
+ );
+}