value-bag-1.9.0/.cargo_vcs_info.json0000644000000001360000000000100127060ustar { "git": { "sha1": "aed5701cbb0532c5246c19a0fce82e028513ce1c" }, "path_in_vcs": "" }value-bag-1.9.0/.gitignore000064400000000000000000000004771046102023000134760ustar 00000000000000# Generated by Cargo # will have compiled files and executables target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk value-bag-1.9.0/Cargo.toml0000644000000033670000000000100107150ustar # 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" name = "value-bag" version = "1.9.0" authors = ["Ashley Mannix "] exclude = [".github/*"] description = "Anonymous structured values" documentation = "https://docs.rs/value-bag" readme = "README.md" keywords = [ "serialization", "no_std", ] categories = [ "encoding", "no-std", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/sval-rs/value-bag" [package.metadata.docs.rs] features = [ "std", "error", "sval", "serde", "test", "owned", "seq", ] [dependencies.value-bag-serde1] version = "1.9.0" optional = true [dependencies.value-bag-sval2] version = "1.9.0" optional = true [dev-dependencies] [features] alloc = [ "value-bag-sval2?/alloc", "value-bag-serde1?/alloc", ] error = ["std"] inline-i128 = [] owned = [ "alloc", "value-bag-serde1?/owned", ] seq = [] serde = ["serde1"] serde1 = [ "alloc", "value-bag-serde1", "value-bag-sval2?/serde1", ] std = [ "alloc", "value-bag-sval2?/std", "value-bag-serde1?/std", ] sval = ["sval2"] sval2 = ["value-bag-sval2"] test = ["std"] [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen] version = "0.2" [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test] version = "0.3" value-bag-1.9.0/Cargo.toml.orig000064400000000000000000000035621046102023000143730ustar 00000000000000[package] name = "value-bag" version = "1.9.0" authors = ["Ashley Mannix "] edition = "2021" license = "Apache-2.0 OR MIT" documentation = "https://docs.rs/value-bag" description = "Anonymous structured values" repository = "https://github.com/sval-rs/value-bag" readme = "README.md" keywords = ["serialization", "no_std"] categories = ["encoding", "no-std"] exclude = [ ".github/*", ] [package.metadata.docs.rs] features = ["std", "error", "sval", "serde", "test", "owned", "seq"] [workspace] members = [ "meta/serde1", "meta/sval2", ] [features] # Store 128bit numbers inline instead of as references # This may increase the size of `ValueBag` on some platforms inline-i128 = [] # Use the standard library std = [ "alloc", "value-bag-sval2?/std", "value-bag-serde1?/std", ] # Assume an allocator alloc = [ "value-bag-sval2?/alloc", "value-bag-serde1?/alloc", ] # Support owned values owned = [ "alloc", "value-bag-serde1?/owned", ] # Utilities for working with sequences seq = [] # Add support for `sval` sval = ["sval2"] sval2 = [ "value-bag-sval2", ] # Add support for `serde` serde = ["serde1"] serde1 = [ "alloc", "value-bag-serde1", "value-bag-sval2?/serde1", ] # Add support for `std::error` error = [ "std", ] # Add support for testing the contents of a value bag test = ["std"] [dependencies.value-bag-sval2] version = "1.9.0" path = "meta/sval2" optional = true [dependencies.value-bag-serde1] version = "1.9.0" path = "meta/serde1" optional = true [dev-dependencies.value-bag-sval2] path = "meta/sval2" features = ["test", "json"] [dev-dependencies.value-bag-serde1] path = "meta/serde1" features = ["test", "json"] [target.'cfg(target_arch = "wasm32")'.dev-dependencies.wasm-bindgen] version = "0.2" [target.'cfg(target_arch = "wasm32")'.dev-dependencies.wasm-bindgen-test] version = "0.3" value-bag-1.9.0/LICENSE-APACHE000064400000000000000000000251371046102023000134320ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. value-bag-1.9.0/LICENSE-MIT000064400000000000000000000020501046102023000131270ustar 00000000000000MIT License Copyright (c) 2020 sval-rs 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. value-bag-1.9.0/README.md000064400000000000000000000074111046102023000127600ustar 00000000000000# `value-bag` [![Rust](https://github.com/sval-rs/value-bag/workflows/Rust/badge.svg)](https://github.com/sval-rs/value-bag/actions) [![Latest version](https://img.shields.io/crates/v/value-bag.svg)](https://crates.io/crates/value-bag) [![Documentation Latest](https://docs.rs/value-bag/badge.svg)](https://docs.rs/value-bag) ## What is a value bag? A `ValueBag` is an anonymous structured value that supports casting, downcasting, formatting, and serializing. The producer of a `ValueBag` and its eventual consumer don't need to agree on a serialization contract. Any translation is handled internally by `ValueBag`. Say we capture an `i32` using its `Display` implementation as a `ValueBag`: ```rust let bag = ValueBag::capture_display(42); ``` That value can then be cast to a concrete integer type, like `u64`: ```rust let num = bag.as_u64().unwrap(); assert_eq!(42, num); ``` It could also be serialized as a number using `serde`: ```rust let num = serde_json::to_value(&bag).unwrap(); assert!(num.is_number()); ``` It works for more complex types too. Say we derive `sval::Value` on a type and capture it as a `ValueBag`: ```rust #[derive(Value)] struct Work { id: u64, description: String, } let work = Work { id: 123, description: String::from("do the work"), } let bag = ValueBag::capture_sval2(&work); ``` We could still serialize that value using `serde` without losing structure: ```rust let obj = serde_json::to_value(&bag).unwrap(); assert!(obj.is_object()); ``` It could also be formatted using `Display`: ```rust assert_eq!("Work { id: 123, description: \"do the work\" }", bag.to_string()); ``` The tradeoff in all this is that `ValueBag` needs to depend on the serialization frameworks (`sval`, `serde`, and `std::fmt`) that it supports, instead of just providing an API of its own for others to plug into. Doing this lets `ValueBag` guarantee everything will always line up, and keep its own public API narrow. ## Getting started Add the `value-bag` crate to your `Cargo.toml`: ```rust [dependencies.value-bag] version = "1.9.0" ``` You'll probably also want to add a feature for either `sval` (if you're in a no-std environment) or `serde` (if you need to integrate with other code that uses `serde`): ```rust [dependencies.value-bag] version = "1.9.0" features = ["sval2"] ``` ```rust [dependencies.value-bag] version = "1.9.0" features = ["serde1"] ``` Then you're ready to capture anonymous values! ```rust #[derive(Serialize)] struct MyValue { title: String, description: String, version: u32, } // Capture a value that implements `serde::Serialize` let bag = ValueBag::capture_serde1(&my_value); // Print the contents of the value bag println!("{:?}", bag); ``` ## Cargo features The `value-bag` crate is no-std by default, and offers the following Cargo features: - `std`: Enable support for the standard library. This allows more types to be captured in a `ValueBag`. - `error`: Enable support for capturing `std::error::Error`s. Implies `std`. - `sval`: Enable support for using the [`sval`](https://github.com/sval-rs/sval) serialization framework for inspecting `ValueBag`s by implementing `sval::value::Value`. Implies `sval2`. - `sval2`: Enable support for the stable `2.x.x` version of `sval`. - `serde`: Enable support for using the [`serde`](https://github.com/serde-rs/serde) serialization framework for inspecting `ValueBag`s by implementing `serde::Serialize`. Implies `std` and `serde1`. - `serde1`: Enable support for the stable `1.x.x` version of `serde`. - `owned`: Add support for buffering `ValueBag`s into an owned `Send + Sync` variant. - `seq`: Add support for working with sequences without needing to go through a full serialization framework. - `test`: Add test helpers for inspecting the shape of the value inside a `ValueBag`. value-bag-1.9.0/benches/by_ref.rs000064400000000000000000000002551046102023000147230ustar 00000000000000#![feature(test)] extern crate test; use value_bag::ValueBag; #[bench] fn u8_by_ref(b: &mut test::Bencher) { let v = ValueBag::from(1u8); b.iter(|| v.by_ref()) } value-bag-1.9.0/benches/capture.rs000064400000000000000000000045441046102023000151250ustar 00000000000000#![feature(test)] extern crate test; use value_bag::ValueBag; #[bench] fn u8_capture_from(b: &mut test::Bencher) { b.iter(|| ValueBag::from(1u8)) } #[bench] fn u8_capture_debug(b: &mut test::Bencher) { b.iter(|| ValueBag::capture_debug(&1u8)) } #[bench] fn str_capture_debug(b: &mut test::Bencher) { // Currently at the top of the linear list of types in `cast::primitive` b.iter(|| ValueBag::capture_debug(&"a string")) } #[bench] fn bool_capture_debug(b: &mut test::Bencher) { // Currently at the bottom of the linear list of types in `cast::primitive` b.iter(|| ValueBag::capture_debug(&true)) } #[bench] fn custom_capture_debug(b: &mut test::Bencher) { #[derive(Debug)] struct A; b.iter(|| ValueBag::capture_debug(&A)) } #[bench] fn fill_debug(b: &mut test::Bencher) { b.iter(|| { ValueBag::from_fill(&|slot: value_bag::fill::Slot| { #[derive(Debug)] struct A; slot.fill_debug(&A) }) }) } #[bench] fn u8_capture_from_to_u64(b: &mut test::Bencher) { let v = ValueBag::from(1u8); b.iter(|| v.to_u64()) } #[bench] fn u8_capture_debug_to_u64(b: &mut test::Bencher) { let v = ValueBag::capture_debug(&1u8); b.iter(|| v.to_u64()) } #[bench] fn u8_fill_to_u64(b: &mut test::Bencher) { let v = ValueBag::from_fill(&|slot: value_bag::fill::Slot| slot.fill_any(1u8)); b.iter(|| v.to_u64()) } #[bench] #[cfg(feature = "sval1")] fn u8_from_sval_to_u64(b: &mut test::Bencher) { let v = ValueBag::from_sval1(&1u8); b.iter(|| v.to_u64()) } #[bench] #[cfg(feature = "sval1")] fn u8_fill_sval_to_u64(b: &mut test::Bencher) { let v = ValueBag::from_fill(&|slot: value_bag::fill::Slot| slot.fill_sval1(&1u8)); b.iter(|| v.to_u64()) } #[bench] fn u8_capture_debug_to_borrowed_str(b: &mut test::Bencher) { let v = ValueBag::capture_debug(&1u8); b.iter(|| v.to_borrowed_str()) } #[bench] fn str_capture_debug_to_borrowed_str(b: &mut test::Bencher) { let v = ValueBag::capture_debug(&"a string"); b.iter(|| v.to_borrowed_str()) } #[bench] fn str_capture_debug_to_u64(b: &mut test::Bencher) { let v = ValueBag::capture_debug(&"a string"); b.iter(|| v.to_u64()) } #[bench] fn custom_capture_debug_to_str(b: &mut test::Bencher) { #[derive(Debug)] struct A; let v = ValueBag::capture_debug(&A); b.iter(|| v.to_borrowed_str()) } value-bag-1.9.0/benches/owned.rs000064400000000000000000000041511046102023000145700ustar 00000000000000#![cfg(feature = "owned")] #![feature(test)] extern crate test; use value_bag::ValueBag; #[bench] fn u8_to_owned(b: &mut test::Bencher) { let bag = ValueBag::from(1u8); b.iter(|| bag.to_owned()); } #[bench] fn str_to_owned(b: &mut test::Bencher) { let bag = ValueBag::from("a string"); b.iter(|| bag.to_owned()); } #[bench] fn display_to_owned(b: &mut test::Bencher) { let bag = ValueBag::from_display(&42); b.iter(|| bag.to_owned()); } #[cfg(feature = "serde1")] #[bench] fn serde1_to_owned(b: &mut test::Bencher) { use value_bag_serde1::lib::ser::{Serialize, SerializeStruct, Serializer}; pub struct MyData<'a> { a: i32, b: &'a str, } impl<'a> Serialize for MyData<'a> { fn serialize(&self, serializer: S) -> Result { let mut serializer = serializer.serialize_struct("MyData", 2)?; serializer.serialize_field("a", &self.a)?; serializer.serialize_field("b", &self.b)?; serializer.end() } } let bag = ValueBag::from_serde1(&MyData { a: 42, b: "a string", }); b.iter(|| bag.to_owned()); } #[cfg(feature = "sval2")] #[bench] fn sval2_to_owned(b: &mut test::Bencher) { use value_bag_sval2::lib::{Label, Result, Stream, Value}; pub struct MyData<'a> { a: i32, b: &'a str, } impl<'a> Value for MyData<'a> { fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result { stream.record_begin(None, Some(&Label::new("MyData")), None, Some(2))?; stream.record_value_begin(None, &Label::new("a"))?; stream.value(&self.a)?; stream.record_value_end(None, &Label::new("a"))?; stream.record_value_begin(None, &Label::new("b"))?; stream.value(&self.b)?; stream.record_value_end(None, &Label::new("b"))?; stream.record_end(None, Some(&Label::new("MyData")), None) } } let bag = ValueBag::from_sval2(&MyData { a: 42, b: "a string", }); b.iter(|| bag.to_owned()); } value-bag-1.9.0/benches/seq.rs000064400000000000000000000007401046102023000142440ustar 00000000000000#![cfg(feature = "seq")] #![feature(test)] extern crate test; use value_bag::ValueBag; #[cfg(feature = "serde1")] #[bench] fn serde1_to_seq_5(b: &mut test::Bencher) { let v = ValueBag::from_serde1(&[1.0, 2.0, 3.0, 4.0, 5.0]); b.iter(|| v.to_f64_seq::>>()) } #[cfg(feature = "sval2")] #[bench] fn sval2_to_seq_5(b: &mut test::Bencher) { let v = ValueBag::from_sval2(&[1.0, 2.0, 3.0, 4.0, 5.0]); b.iter(|| v.to_f64_seq::>>()) } value-bag-1.9.0/src/error.rs000064400000000000000000000034171046102023000137710ustar 00000000000000use crate::std::fmt; /// An error encountered while working with structured data. #[derive(Debug)] pub struct Error { inner: Inner, } #[derive(Debug)] enum Inner { #[cfg(feature = "std")] Boxed(std_support::BoxedError), Msg(&'static str), Fmt, } impl Error { /// Create an error from a message. pub fn msg(msg: &'static str) -> Self { Error { inner: Inner::Msg(msg), } } #[cfg(feature = "serde1")] pub(crate) fn try_boxed(msg: &'static str, e: impl fmt::Display) -> Self { #[cfg(feature = "std")] { Error::boxed(format!("{msg}: {e}")) } #[cfg(not(feature = "std"))] { let _ = e; Error::msg(msg) } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Inner::*; match self.inner { #[cfg(feature = "std")] Boxed(ref err) => err.fmt(f), Msg(ref msg) => msg.fmt(f), Fmt => fmt::Error.fmt(f), } } } impl From for Error { fn from(_: fmt::Error) -> Self { Error { inner: Inner::Fmt } } } #[cfg(feature = "std")] mod std_support { use super::*; use crate::std::{boxed::Box, error, io}; pub(crate) type BoxedError = Box; impl Error { /// Create an error from a standard error type. pub fn boxed(err: E) -> Self where E: Into, { Error { inner: Inner::Boxed(err.into()), } } } impl error::Error for Error {} impl From for Error { fn from(err: io::Error) -> Self { Error::boxed(err) } } } value-bag-1.9.0/src/fill.rs000064400000000000000000000106521046102023000135650ustar 00000000000000//! Deferred value initialization. //! //! The [`Fill`] trait is a way to bridge APIs that may not be directly //! compatible with other constructor methods. //! //! The `Fill` trait is automatically implemented for closures, so can usually //! be used in libraries that can't implement the trait themselves. //! //! ``` //! use value_bag::{ValueBag, fill::Slot}; //! //! let value = ValueBag::from_fill(&|slot: Slot| { //! #[derive(Debug)] //! struct MyShortLivedValue; //! //! slot.fill_debug(&MyShortLivedValue) //! }); //! //! assert_eq!("MyShortLivedValue", format!("{:?}", value)); //! ``` //! //! The trait can also be implemented manually: //! //! ``` //! # use std::fmt::Debug; //! use value_bag::{ValueBag, Error, fill::{Slot, Fill}}; //! //! struct FillDebug; //! //! impl Fill for FillDebug { //! fn fill(&self, slot: Slot) -> Result<(), Error> { //! slot.fill_debug(&42i64 as &dyn Debug) //! } //! } //! //! let value = ValueBag::from_fill(&FillDebug); //! //! assert_eq!(None, value.to_i64()); //! ``` use crate::std::fmt; use super::internal::{Internal, InternalVisitor}; use super::{Error, ValueBag}; impl<'v> ValueBag<'v> { /// Get a value from a fillable slot. pub const fn from_fill(value: &'v T) -> Self where T: Fill, { ValueBag { inner: Internal::Fill(value), } } } /// A type that requires extra work to convert into a [`ValueBag`](../struct.ValueBag.html). /// /// This trait is an advanced initialization API. /// It's intended for erased values coming from other logging frameworks that may need /// to perform extra work to determine the concrete type to use. pub trait Fill { /// Fill a value. fn fill(&self, slot: Slot) -> Result<(), Error>; } impl Fill for F where F: Fn(Slot) -> Result<(), Error>, { fn fill(&self, slot: Slot) -> Result<(), Error> { (self)(slot) } } /// A value slot to fill using the [`Fill`](trait.Fill.html) trait. pub struct Slot<'s, 'f> { visitor: &'s mut dyn InternalVisitor<'f>, } impl<'s, 'f> fmt::Debug for Slot<'s, 'f> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Slot").finish() } } impl<'s, 'f> Slot<'s, 'f> { pub(crate) fn new(visitor: &'s mut dyn InternalVisitor<'f>) -> Self { Slot { visitor } } pub(crate) fn fill(self, f: F) -> Result<(), Error> where F: FnOnce(&mut dyn InternalVisitor<'f>) -> Result<(), Error>, { f(self.visitor) } /// Fill the slot with a value. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_any(self, value: T) -> Result<(), Error> where T: Into>, { self.fill(|visitor| value.into().inner.internal_visit(visitor)) } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::std::string::ToString; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_value_borrowed() { struct TestFill; impl Fill for TestFill { fn fill(&self, slot: Slot) -> Result<(), Error> { let dbg = &1 as &dyn fmt::Debug; slot.fill_debug(dbg) } } assert_eq!("1", ValueBag::from_fill(&TestFill).to_string()); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_cast() { struct TestFill; impl Fill for TestFill { fn fill(&self, slot: Slot) -> Result<(), Error> { slot.fill_any("a string") } } assert_eq!( "a string", ValueBag::from_fill(&TestFill) .to_borrowed_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_fn_cast() { assert_eq!( 42u64, ValueBag::from_fill(&|slot: Slot| slot.fill_any(42u64)) .to_u64() .unwrap() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_fn_borrowed() { #[derive(Debug)] struct MyValue; let value = MyValue; assert_eq!( format!("{:?}", value), format!( "{:?}", ValueBag::from_fill(&|slot: Slot| slot.fill_debug(&value)) ) ); } } value-bag-1.9.0/src/impls.rs000064400000000000000000000167451046102023000137740ustar 00000000000000//! Converting standard types into `ValueBag`s. use super::{Error, ValueBag}; macro_rules! convert_primitive { ($($t:ty: $from:ident, $to:ident,)*) => { $( impl<'v> From<$t> for ValueBag<'v> { #[inline] fn from(v: $t) -> Self { ValueBag::$from(v) } } impl<'a, 'v> From<&'a $t> for ValueBag<'v> { #[inline] fn from(v: &'a $t) -> Self { ValueBag::$from(*v) } } impl<'v> From> for ValueBag<'v> { #[inline] fn from(v: Option<$t>) -> Self { ValueBag::from_option(v) } } impl<'v> TryFrom> for $t { type Error = Error; #[inline] fn try_from(v: ValueBag<'v>) -> Result { v.$to() .ok_or_else(|| Error::msg("conversion failed"))? .try_into() .map_err(|_| Error::msg("conversion failed")) } } )* }; } impl<'v> From<()> for ValueBag<'v> { #[inline] fn from(_: ()) -> Self { ValueBag::empty() } } impl<'a, 'v> From<&'a ()> for ValueBag<'v> { #[inline] fn from(_: &'a ()) -> Self { ValueBag::empty() } } convert_primitive!( u8: from_u8, to_u64, u16: from_u16, to_u64, u32: from_u32, to_u64, u64: from_u64, to_u64, usize: from_usize, to_u64, i8: from_i8, to_i64, i16: from_i16, to_i64, i32: from_i32, to_i64, i64: from_i64, to_i64, isize: from_isize, to_i64, f64: from_f64, to_f64, bool: from_bool, to_bool, char: from_char, to_char, ); impl<'v> From for ValueBag<'v> { #[inline] fn from(v: f32) -> Self { ValueBag::from_f32(v) } } impl<'v> From> for ValueBag<'v> { #[inline] fn from(v: Option) -> Self { ValueBag::from_option(v) } } impl<'a, 'v> From<&'a f32> for ValueBag<'v> { #[inline] fn from(v: &'a f32) -> Self { ValueBag::from_f32(*v) } } #[cfg(feature = "inline-i128")] impl<'a, 'v> From<&'a u128> for ValueBag<'v> { #[inline] fn from(v: &'a u128) -> Self { ValueBag::from_u128(*v) } } #[cfg(not(feature = "inline-i128"))] impl<'v> From<&'v u128> for ValueBag<'v> { #[inline] fn from(v: &'v u128) -> Self { ValueBag::from_u128_ref(v) } } #[cfg(feature = "inline-i128")] impl<'v> From for ValueBag<'v> { #[inline] fn from(v: u128) -> Self { ValueBag::from_u128(v) } } impl<'v> TryFrom> for u128 { type Error = Error; #[inline] fn try_from(v: ValueBag<'v>) -> Result { v.to_u128().ok_or_else(|| Error::msg("conversion failed")) } } #[cfg(feature = "inline-i128")] impl<'a, 'v> From<&'a i128> for ValueBag<'v> { #[inline] fn from(v: &'a i128) -> Self { ValueBag::from_i128(*v) } } #[cfg(not(feature = "inline-i128"))] impl<'v> From<&'v i128> for ValueBag<'v> { #[inline] fn from(v: &'v i128) -> Self { ValueBag::from_i128_ref(v) } } #[cfg(feature = "inline-i128")] impl<'v> From for ValueBag<'v> { #[inline] fn from(v: i128) -> Self { ValueBag::from_i128(v) } } impl<'v> TryFrom> for i128 { type Error = Error; #[inline] fn try_from(v: ValueBag<'v>) -> Result { v.to_i128().ok_or_else(|| Error::msg("conversion failed")) } } impl<'v> From<&'v str> for ValueBag<'v> { #[inline] fn from(v: &'v str) -> Self { ValueBag::from_str(v) } } impl<'v> From> for ValueBag<'v> { #[inline] fn from(v: Option<&'v str>) -> Self { ValueBag::from_option(v) } } impl<'v> TryFrom> for &'v str { type Error = Error; #[inline] fn try_from(v: ValueBag<'v>) -> Result { v.to_borrowed_str() .ok_or_else(|| Error::msg("conversion failed")) } } impl<'v, 'u> From<&'v &'u str> for ValueBag<'v> where 'u: 'v, { #[inline] fn from(v: &'v &'u str) -> Self { ValueBag::from_str(v) } } #[cfg(feature = "alloc")] mod alloc_support { use super::*; use crate::std::{borrow::Cow, string::String}; impl<'v> From<&'v String> for ValueBag<'v> { #[inline] fn from(v: &'v String) -> Self { ValueBag::from_str(v) } } impl<'v> TryFrom> for Cow<'v, str> { type Error = Error; #[inline] fn try_from(v: ValueBag<'v>) -> Result { v.to_str().ok_or_else(|| Error::msg("conversion failed")) } } impl<'v> TryFrom> for String { type Error = Error; #[inline] fn try_from(v: ValueBag<'v>) -> Result { Ok(v.to_str() .ok_or_else(|| Error::msg("conversion failed"))? .into_owned()) } } } #[cfg(feature = "owned")] mod owned_support { use super::*; use crate::OwnedValueBag; impl<'v> From<&'v OwnedValueBag> for ValueBag<'v> { #[inline] fn from(v: &'v OwnedValueBag) -> ValueBag<'v> { v.by_ref() } } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use crate::{ std::{borrow::ToOwned, string::ToString}, test::{IntoValueBag, TestToken}, }; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_into_display() { assert_eq!(42u64.into_value_bag().by_ref().to_string(), "42"); assert_eq!(42i64.into_value_bag().by_ref().to_string(), "42"); assert_eq!(42.01f64.into_value_bag().by_ref().to_string(), "42.01"); assert_eq!(true.into_value_bag().by_ref().to_string(), "true"); assert_eq!('a'.into_value_bag().by_ref().to_string(), "a"); assert_eq!( "a loong string".into_value_bag().by_ref().to_string(), "a loong string" ); assert_eq!(().into_value_bag().by_ref().to_string(), "None"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_into_structured() { assert_eq!( 42u64.into_value_bag().by_ref().to_test_token(), TestToken::U64(42) ); assert_eq!( 42i64.into_value_bag().by_ref().to_test_token(), TestToken::I64(42) ); assert_eq!( 42.01f64.into_value_bag().by_ref().to_test_token(), TestToken::F64(42.01) ); assert_eq!( true.into_value_bag().by_ref().to_test_token(), TestToken::Bool(true) ); assert_eq!( 'a'.into_value_bag().by_ref().to_test_token(), TestToken::Char('a') ); assert_eq!( "a loong string".into_value_bag().by_ref().to_test_token(), TestToken::Str("a loong string".to_owned()) ); assert_eq!( ().into_value_bag().by_ref().to_test_token(), TestToken::None ); #[cfg(feature = "inline-i128")] { assert_eq!( 42u128.into_value_bag().by_ref().to_test_token(), TestToken::U128(42) ); assert_eq!( 42i128.into_value_bag().by_ref().to_test_token(), TestToken::I128(42) ); } } } value-bag-1.9.0/src/internal/cast/mod.rs000064400000000000000000000533501046102023000161660ustar 00000000000000//! Coerce a `Value` into some concrete types. //! //! These operations are cheap when the captured value is a simple primitive, //! but may end up executing arbitrary caller code if the value is complex. //! They will also attempt to downcast erased types into a primitive where possible. use crate::std::fmt; #[cfg(feature = "alloc")] use crate::std::{borrow::ToOwned, string::String}; use super::{Internal, InternalVisitor}; use crate::{Error, ValueBag}; mod primitive; impl ValueBag<'static> { /// Try capture an owned raw value. /// /// This method will return `Some` if the value is a simple primitive /// that can be captured without losing its structure. In other cases /// this method will return `None`. #[cfg(feature = "owned")] pub fn try_capture_owned(value: &'_ T) -> Option where T: ?Sized + 'static, { primitive::from_owned_any(value) } } impl<'v> ValueBag<'v> { /// Try capture a raw value. /// /// This method will return `Some` if the value is a simple primitive /// that can be captured without losing its structure. In other cases /// this method will return `None`. pub fn try_capture(value: &'v T) -> Option where T: ?Sized + 'static, { primitive::from_any(value) } /// Try get a `u64` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. pub fn to_u64(&self) -> Option { self.inner.cast().into_u64() } /// Try get a `i64` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. pub fn to_i64(&self) -> Option { self.inner.cast().into_i64() } /// Try get a `u128` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. pub fn to_u128(&self) -> Option { self.inner.cast().into_u128() } /// Try get a `i128` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. pub fn to_i128(&self) -> Option { self.inner.cast().into_i128() } /// Try get a `f64` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. /// /// This method is based on standard `TryInto` conversions, and will /// only return `Some` if there's a guaranteed lossless conversion between /// the source and destination types. For a more lenient alternative, see /// [`ValueBag::as_f64`]. pub fn to_f64(&self) -> Option { self.inner.cast().into_f64() } /// Get a `f64` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. /// /// This method is like [`ValueBag::to_f64`] except will always return /// a `f64`, regardless of the actual type of underlying value. For /// numeric types, it will use a regular `as` conversion, which may be lossy. /// For non-numeric types it will return `NaN`. pub fn as_f64(&self) -> f64 { self.inner.cast().as_f64() } /// Try get a `bool` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. pub fn to_bool(&self) -> Option { self.inner.cast().into_bool() } /// Try get a `char` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. pub fn to_char(&self) -> Option { self.inner.cast().into_char() } /// Try get a `str` from this value. /// /// This method is cheap for primitive types. It won't allocate an owned /// `String` if the value is a complex type. pub fn to_borrowed_str(&self) -> Option<&'v str> { self.inner.cast().into_borrowed_str() } /// Check whether this value is empty. pub fn is_empty(&self) -> bool { matches!(self.inner, Internal::None) } /// Check whether this value can be downcast to `T`. pub fn is(&self) -> bool { self.downcast_ref::().is_some() } /// Try downcast this value to `T`. pub fn downcast_ref(&self) -> Option<&T> { match self.inner { Internal::Debug(value) => value.as_any().downcast_ref(), Internal::Display(value) => value.as_any().downcast_ref(), #[cfg(feature = "error")] Internal::Error(value) => value.as_any().downcast_ref(), #[cfg(feature = "sval2")] Internal::Sval2(value) => value.as_any().downcast_ref(), #[cfg(feature = "serde1")] Internal::Serde1(value) => value.as_any().downcast_ref(), #[cfg(feature = "owned")] Internal::SharedDebug(ref value) => value.as_any().downcast_ref(), #[cfg(feature = "owned")] Internal::SharedDisplay(ref value) => value.as_any().downcast_ref(), #[cfg(all(feature = "error", feature = "owned"))] Internal::SharedError(ref value) => value.as_any().downcast_ref(), #[cfg(all(feature = "serde1", feature = "owned"))] Internal::SharedSerde1(ref value) => value.as_any().downcast_ref(), #[cfg(all(feature = "sval2", feature = "owned"))] Internal::SharedSval2(ref value) => value.as_any().downcast_ref(), #[cfg(all(feature = "seq", feature = "owned"))] Internal::SharedSeq(ref value) => value.as_any().downcast_ref(), #[cfg(feature = "owned")] Internal::SharedRefDebug(value) => value.as_any().downcast_ref(), #[cfg(feature = "owned")] Internal::SharedRefDisplay(value) => value.as_any().downcast_ref(), #[cfg(all(feature = "error", feature = "owned"))] Internal::SharedRefError(value) => value.as_any().downcast_ref(), #[cfg(all(feature = "serde1", feature = "owned"))] Internal::SharedRefSerde1(value) => value.as_any().downcast_ref(), #[cfg(all(feature = "sval2", feature = "owned"))] Internal::SharedRefSval2(value) => value.as_any().downcast_ref(), #[cfg(all(feature = "seq", feature = "owned"))] Internal::SharedRefSeq(value) => value.as_any().downcast_ref(), _ => None, } } } impl<'v> Internal<'v> { /// Cast the inner value to another type. #[inline] fn cast(&self) -> Cast<'v> { struct CastVisitor<'v>(Cast<'v>); impl<'v> InternalVisitor<'v> for CastVisitor<'v> { #[inline] fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } #[inline] fn debug(&mut self, _: &dyn fmt::Debug) -> Result<(), Error> { Ok(()) } #[inline] fn display(&mut self, _: &dyn fmt::Display) -> Result<(), Error> { Ok(()) } #[inline] fn u64(&mut self, v: u64) -> Result<(), Error> { self.0 = Cast::Unsigned(v); Ok(()) } #[inline] fn i64(&mut self, v: i64) -> Result<(), Error> { self.0 = Cast::Signed(v); Ok(()) } #[inline] fn u128(&mut self, v: &u128) -> Result<(), Error> { self.0 = Cast::BigUnsigned(*v); Ok(()) } #[inline] fn i128(&mut self, v: &i128) -> Result<(), Error> { self.0 = Cast::BigSigned(*v); Ok(()) } #[inline] fn f64(&mut self, v: f64) -> Result<(), Error> { self.0 = Cast::Float(v); Ok(()) } #[inline] fn bool(&mut self, v: bool) -> Result<(), Error> { self.0 = Cast::Bool(v); Ok(()) } #[inline] fn char(&mut self, v: char) -> Result<(), Error> { self.0 = Cast::Char(v); Ok(()) } #[cfg(feature = "alloc")] #[inline] fn str(&mut self, s: &str) -> Result<(), Error> { self.0 = Cast::String(s.to_owned()); Ok(()) } #[cfg(not(feature = "alloc"))] #[inline] fn str(&mut self, _: &str) -> Result<(), Error> { Ok(()) } #[inline] fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { self.0 = Cast::Str(v); Ok(()) } #[inline] fn none(&mut self) -> Result<(), Error> { self.0 = Cast::None; Ok(()) } #[cfg(feature = "error")] #[inline] fn error(&mut self, _: &dyn super::error::Error) -> Result<(), Error> { Ok(()) } #[cfg(feature = "sval2")] #[inline] fn sval2(&mut self, v: &dyn super::sval::v2::Value) -> Result<(), Error> { if super::sval::v2::internal_visit(v, self) { Ok(()) } else { Err(Error::msg("invalid cast")) } } #[cfg(feature = "sval2")] fn borrowed_sval2(&mut self, v: &'v dyn super::sval::v2::Value) -> Result<(), Error> { if super::sval::v2::borrowed_internal_visit(v, self) { Ok(()) } else { Err(Error::msg("invalid cast")) } } #[cfg(feature = "serde1")] #[inline] fn serde1(&mut self, v: &dyn super::serde::v1::Serialize) -> Result<(), Error> { if super::serde::v1::internal_visit(v, self) { Ok(()) } else { Err(Error::msg("invalid cast")) } } #[cfg(feature = "seq")] fn seq(&mut self, _: &dyn super::seq::Seq) -> Result<(), Error> { self.0 = Cast::None; Ok(()) } fn poisoned(&mut self, _: &'static str) -> Result<(), Error> { self.0 = Cast::None; Ok(()) } } match &self { Internal::Signed(value) => Cast::Signed(*value), Internal::Unsigned(value) => Cast::Unsigned(*value), #[cfg(feature = "inline-i128")] Internal::BigSigned(value) => Cast::BigSigned(*value), #[cfg(not(feature = "inline-i128"))] Internal::BigSigned(value) => Cast::BigSigned(**value), #[cfg(feature = "inline-i128")] Internal::BigUnsigned(value) => Cast::BigUnsigned(*value), #[cfg(not(feature = "inline-i128"))] Internal::BigUnsigned(value) => Cast::BigUnsigned(**value), Internal::Float(value) => Cast::Float(*value), Internal::Bool(value) => Cast::Bool(*value), Internal::Char(value) => Cast::Char(*value), Internal::Str(value) => Cast::Str(value), Internal::None => Cast::None, other => { // If the erased value isn't a primitive then we visit it let mut cast = CastVisitor(Cast::None); let _ = other.internal_visit(&mut cast); cast.0 } } } } pub(in crate::internal) enum Cast<'v> { Signed(i64), Unsigned(u64), BigSigned(i128), BigUnsigned(u128), Float(f64), Bool(bool), Char(char), Str(&'v str), None, #[cfg(feature = "alloc")] String(String), } impl<'v> Cast<'v> { #[inline] fn into_borrowed_str(self) -> Option<&'v str> { if let Cast::Str(value) = self { Some(value) } else { None } } #[inline] fn into_u64(self) -> Option { match self { Cast::Unsigned(value) => Some(value), Cast::BigUnsigned(value) => value.try_into().ok(), Cast::Signed(value) => value.try_into().ok(), Cast::BigSigned(value) => value.try_into().ok(), _ => None, } } #[inline] fn into_i64(self) -> Option { match self { Cast::Signed(value) => Some(value), Cast::BigSigned(value) => value.try_into().ok(), Cast::Unsigned(value) => value.try_into().ok(), Cast::BigUnsigned(value) => value.try_into().ok(), _ => None, } } #[inline] fn into_u128(self) -> Option { match self { Cast::BigUnsigned(value) => Some(value), Cast::Unsigned(value) => Some(value.into()), Cast::Signed(value) => value.try_into().ok(), Cast::BigSigned(value) => value.try_into().ok(), _ => None, } } #[inline] fn into_i128(self) -> Option { match self { Cast::BigSigned(value) => Some(value), Cast::Signed(value) => Some(value.into()), Cast::Unsigned(value) => value.try_into().ok(), Cast::BigUnsigned(value) => value.try_into().ok(), _ => None, } } #[inline] fn into_f64(self) -> Option { match self { Cast::Float(value) => Some(value), Cast::Unsigned(value) => u32::try_from(value) .ok() .and_then(|value| value.try_into().ok()), Cast::Signed(value) => i32::try_from(value) .ok() .and_then(|value| value.try_into().ok()), Cast::BigUnsigned(value) => u32::try_from(value) .ok() .and_then(|value| value.try_into().ok()), Cast::BigSigned(value) => i32::try_from(value) .ok() .and_then(|value| value.try_into().ok()), _ => None, } } #[inline] fn as_f64(self) -> f64 { match self { Cast::Float(value) => value, Cast::Unsigned(value) => value as f64, Cast::Signed(value) => value as f64, Cast::BigUnsigned(value) => value as f64, Cast::BigSigned(value) => value as f64, _ => f64::NAN, } } #[inline] fn into_char(self) -> Option { if let Cast::Char(value) = self { Some(value) } else { None } } #[inline] fn into_bool(self) -> Option { if let Cast::Bool(value) = self { Some(value) } else { None } } } #[cfg(feature = "alloc")] mod alloc_support { use super::*; use crate::std::borrow::Cow; impl<'v> ValueBag<'v> { /// Try get a `str` from this value. /// /// This method is cheap for primitive types, but may call arbitrary /// serialization implementations for complex ones. If the serialization /// implementation produces a short lived string it will be allocated. #[inline] pub fn to_str(&self) -> Option> { self.inner.cast().into_str() } } impl<'v> Cast<'v> { #[inline] pub(in crate::internal) fn into_str(self) -> Option> { match self { Cast::Str(value) => Some(value.into()), Cast::String(value) => Some(value.into()), _ => None, } } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use crate::{std::borrow::ToOwned, test::IntoValueBag, ValueBag}; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn primitive_cast() { let short_lived = "a string".to_owned(); assert_eq!( "a string", (&*short_lived) .into_value_bag() .to_borrowed_str() .expect("invalid value") ); assert_eq!( "a string", &*"a string".into_value_bag().to_str().expect("invalid value") ); assert_eq!( "a string", (&*short_lived) .into_value_bag() .to_borrowed_str() .expect("invalid value") ); assert_eq!( "a string", ValueBag::try_capture(&short_lived) .expect("invalid value") .to_borrowed_str() .expect("invalid value") ); } } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::test::IntoValueBag; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn is_empty() { assert!(ValueBag::from(None::).is_empty(),); assert!(ValueBag::try_capture(&None::).unwrap().is_empty(),); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn primitive_capture_str() { let s: &str = "short lived"; assert_eq!( "short lived", ValueBag::try_capture(s) .unwrap() .to_borrowed_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn primitive_cast() { assert_eq!( "a string", "a string" .into_value_bag() .by_ref() .to_borrowed_str() .expect("invalid value") ); assert_eq!( 1u64, 1u8.into_value_bag() .by_ref() .to_u64() .expect("invalid value") ); assert_eq!( 1u64, 1u16.into_value_bag() .by_ref() .to_u64() .expect("invalid value") ); assert_eq!( 1u64, 1u32.into_value_bag() .by_ref() .to_u64() .expect("invalid value") ); assert_eq!( 1u64, 1u64.into_value_bag() .by_ref() .to_u64() .expect("invalid value") ); assert_eq!( 1u64, 1usize .into_value_bag() .by_ref() .to_u64() .expect("invalid value") ); assert_eq!( 1u128, 1u128 .into_value_bag() .by_ref() .to_u128() .expect("invalid value") ); assert_eq!( -1i64, -(1i8 .into_value_bag() .by_ref() .to_i64() .expect("invalid value")) ); assert_eq!( -1i64, -(1i8 .into_value_bag() .by_ref() .to_i64() .expect("invalid value")) ); assert_eq!( -1i64, -(1i8 .into_value_bag() .by_ref() .to_i64() .expect("invalid value")) ); assert_eq!( -1i64, -(1i64 .into_value_bag() .by_ref() .to_i64() .expect("invalid value")) ); assert_eq!( -1i64, -(1isize .into_value_bag() .by_ref() .to_i64() .expect("invalid value")) ); assert_eq!( -1i128, -(1i128 .into_value_bag() .by_ref() .to_i128() .expect("invalid value")) ); assert!(1f64.into_value_bag().by_ref().to_f64().is_some()); assert!(1u64.into_value_bag().by_ref().to_f64().is_some()); assert!((-1i64).into_value_bag().by_ref().to_f64().is_some()); assert!(1u128.into_value_bag().by_ref().to_f64().is_some()); assert!((-1i128).into_value_bag().by_ref().to_f64().is_some()); assert!(u64::MAX.into_value_bag().by_ref().to_u128().is_some()); assert!(i64::MIN.into_value_bag().by_ref().to_i128().is_some()); assert!(i64::MAX.into_value_bag().by_ref().to_u64().is_some()); assert!((-1i64).into_value_bag().by_ref().to_u64().is_none()); assert!(u64::MAX.into_value_bag().by_ref().to_i64().is_none()); assert!(u64::MAX.into_value_bag().by_ref().to_f64().is_none()); assert!(i128::MAX.into_value_bag().by_ref().to_i64().is_none()); assert!(u128::MAX.into_value_bag().by_ref().to_u64().is_none()); assert!(1f64.into_value_bag().by_ref().to_u64().is_none()); assert_eq!( 'a', 'a'.into_value_bag() .by_ref() .to_char() .expect("invalid value") ); assert!(true .into_value_bag() .by_ref() .to_bool() .expect("invalid value")); } #[test] fn as_cast() { assert_eq!(1.0, 1f64.into_value_bag().as_f64()); assert_eq!(1.0, 1u64.into_value_bag().as_f64()); assert_eq!(-1.0, -(1i64.into_value_bag().as_f64())); assert!(true.into_value_bag().as_f64().is_nan()); } } value-bag-1.9.0/src/internal/cast/primitive.rs000064400000000000000000000064761046102023000174260ustar 00000000000000/* This module generates code to try efficiently convert some arbitrary `T: 'static` into a `Internal`. */ #[cfg(feature = "alloc")] use crate::std::string::String; use crate::ValueBag; // NOTE: The casts for unsized values (str) are dubious here. To really do this properly // we need https://github.com/rust-lang/rust/issues/81513 // NOTE: With some kind of const `Any::is` we could do all this at compile-time // Older versions of `value-bag` did this, but the infrastructure just wasn't worth // the tiny performance improvement use crate::std::any::TypeId; enum Void {} #[repr(transparent)] struct VoidRef<'a>(*const &'a Void); macro_rules! check_type_ids { (&$l:lifetime $v:ident => $( $(#[cfg($($cfg:tt)*)])* $ty:ty, )* ) => { $( $(#[cfg($($cfg)*)])* if TypeId::of::() == TypeId::of::<$ty>() { // SAFETY: We verify the value is $ty before casting let v = unsafe { *($v.0 as *const & $l $ty) }; return Some(ValueBag::from(v)); } )* $( $(#[cfg($($cfg)*)])* if TypeId::of::() == TypeId::of::>() { // SAFETY: We verify the value is Option<$ty> before casting let v = unsafe { *($v.0 as *const & $l Option<$ty>) }; if let Some(v) = v { return Some(ValueBag::from(v)); } else { return Some(ValueBag::empty()); } } )* }; } pub(in crate::internal) fn from_any<'v, T: ?Sized + 'static>(value: &'v T) -> Option> { let type_ids = |v: VoidRef<'v>| { if TypeId::of::() == TypeId::of::() { // SAFETY: We verify the value is str before casting let v = unsafe { *(v.0 as *const &'v str) }; return Some(ValueBag::from(v)); } check_type_ids!( &'v v => usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool, &'static str, // We deal with `str` separately because it's unsized // str, #[cfg(feature = "alloc")] String, ); None }; (type_ids)(VoidRef(&(value) as *const &'v T as *const &'v Void)) } #[cfg(feature = "owned")] pub(in crate::internal) fn from_owned_any<'a, T: ?Sized + 'static>( value: &'a T, ) -> Option> { let type_ids = |v: VoidRef<'a>| { check_type_ids!( &'a v => usize, u8, u16, u32, u64, #[cfg(feature = "inline-i128")] u128, isize, i8, i16, i32, i64, #[cfg(feature = "inline-i128")] i128, f32, f64, char, bool, ); None }; (type_ids)(VoidRef(&(value) as *const &'a T as *const &'a Void)) } value-bag-1.9.0/src/internal/error.rs000064400000000000000000000077071046102023000156130ustar 00000000000000use crate::{ fill::Slot, std::{any::Any, error}, ValueBag, }; use super::Internal; impl<'v> ValueBag<'v> { /// Get a value from an error. pub fn capture_error(value: &'v T) -> Self where T: error::Error + 'static, { ValueBag { inner: Internal::Error(value), } } /// Get a value from an erased value. #[inline] pub const fn from_dyn_error(value: &'v (dyn error::Error + 'static)) -> Self { ValueBag { inner: Internal::AnonError(value), } } /// Try get an error from this value. #[inline] pub fn to_borrowed_error(&self) -> Option<&'v (dyn Error + 'static)> { match self.inner { Internal::Error(value) => Some(value.as_super()), Internal::AnonError(value) => Some(value), _ => None, } } } #[cfg(feature = "error")] pub(crate) trait DowncastError { fn as_any(&self) -> &dyn Any; fn as_super(&self) -> &(dyn error::Error + 'static); } #[cfg(feature = "error")] impl DowncastError for T { fn as_any(&self) -> &dyn Any { self } fn as_super(&self) -> &(dyn error::Error + 'static) { self } } impl<'s, 'f> Slot<'s, 'f> { /// Fill the slot with an error. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_error(self, value: T) -> Result<(), crate::Error> where T: error::Error + 'static, { self.fill(|visitor| visitor.error(&value)) } /// Fill the slot with an error. pub fn fill_dyn_error(self, value: &(dyn error::Error + 'static)) -> Result<(), crate::Error> { self.fill(|visitor| visitor.error(value)) } } pub use self::error::Error; #[cfg(feature = "owned")] pub(crate) mod owned { use crate::std::{boxed::Box, error, fmt, string::ToString}; #[derive(Clone, Debug)] pub(crate) struct OwnedError { display: Box, source: Option>, } impl fmt::Display for OwnedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.display, f) } } impl error::Error for OwnedError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { if let Some(ref source) = self.source { Some(&**source) } else { None } } } pub(crate) fn buffer(err: &(dyn error::Error + 'static)) -> OwnedError { OwnedError { display: err.to_string().into(), source: err.source().map(buffer).map(Box::new), } } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::{ std::{io, string::ToString}, test::*, }; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn error_capture() { let err = io::Error::from(io::ErrorKind::Other); assert_eq!( err.to_string(), ValueBag::capture_error(&err) .to_borrowed_error() .expect("invalid value") .to_string() ); assert_eq!( err.to_string(), ValueBag::from_dyn_error(&err) .to_borrowed_error() .expect("invalid value") .to_string() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn error_downcast() { let err = io::Error::from(io::ErrorKind::Other); assert!(ValueBag::capture_error(&err) .downcast_ref::() .is_some()); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn error_visit() { let err = io::Error::from(io::ErrorKind::Other); ValueBag::from_dyn_error(&err) .visit(TestVisit::default()) .expect("failed to visit value"); } } value-bag-1.9.0/src/internal/fmt.rs000064400000000000000000000362201046102023000152400ustar 00000000000000//! Integration between `Value` and `std::fmt`. //! //! This module allows any `Value` to implement the `Debug` and `Display` traits, //! and for any `Debug` or `Display` to be captured as a `Value`. use crate::{ fill::Slot, std::{any::Any, fmt}, Error, ValueBag, }; use super::{Internal, InternalVisitor}; impl<'v> ValueBag<'v> { /// Get a value from a debuggable type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Debug` implementation. pub fn capture_debug(value: &'v T) -> Self where T: Debug + 'static, { Self::try_capture(value).unwrap_or(ValueBag { inner: Internal::Debug(value), }) } /// Get a value from a displayable type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Display` implementation. pub fn capture_display(value: &'v T) -> Self where T: Display + 'static, { Self::try_capture(value).unwrap_or(ValueBag { inner: Internal::Display(value), }) } /// Get a value from a debuggable type without capturing support. pub const fn from_debug(value: &'v T) -> Self where T: Debug, { ValueBag { inner: Internal::AnonDebug(value), } } /// Get a value from a displayable type without capturing support. pub const fn from_display(value: &'v T) -> Self where T: Display, { ValueBag { inner: Internal::AnonDisplay(value), } } /// Get a value from a debuggable type without capturing support. #[inline] pub const fn from_dyn_debug(value: &'v dyn Debug) -> Self { ValueBag { inner: Internal::AnonDebug(value), } } /// Get a value from a displayable type without capturing support. #[inline] pub const fn from_dyn_display(value: &'v dyn Display) -> Self { ValueBag { inner: Internal::AnonDisplay(value), } } } pub(crate) trait DowncastDisplay { fn as_any(&self) -> &dyn Any; fn as_super(&self) -> &dyn fmt::Display; } impl DowncastDisplay for T { fn as_any(&self) -> &dyn Any { self } fn as_super(&self) -> &dyn fmt::Display { self } } impl<'a> fmt::Display for dyn DowncastDisplay + Send + Sync + 'a { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_super().fmt(f) } } pub(crate) trait DowncastDebug { fn as_any(&self) -> &dyn Any; fn as_super(&self) -> &dyn fmt::Debug; } impl DowncastDebug for T { fn as_any(&self) -> &dyn Any { self } fn as_super(&self) -> &dyn fmt::Debug { self } } impl<'a> fmt::Debug for dyn DowncastDebug + Send + Sync + 'a { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_super().fmt(f) } } impl<'s, 'f> Slot<'s, 'f> { /// Fill the slot with a debuggable value. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_debug(self, value: T) -> Result<(), Error> where T: Debug, { self.fill(|visitor| visitor.debug(&value)) } /// Fill the slot with a displayable value. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_display(self, value: T) -> Result<(), Error> where T: Display, { self.fill(|visitor| visitor.display(&value)) } } pub use self::fmt::{Debug, Display}; impl<'v> Debug for ValueBag<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { struct DebugVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>); impl<'a, 'b: 'a, 'v> InternalVisitor<'v> for DebugVisitor<'a, 'b> { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } fn debug(&mut self, v: &dyn Debug) -> Result<(), Error> { Debug::fmt(v, self.0)?; Ok(()) } fn display(&mut self, v: &dyn Display) -> Result<(), Error> { Display::fmt(v, self.0)?; Ok(()) } fn u64(&mut self, v: u64) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn i64(&mut self, v: i64) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn u128(&mut self, v: &u128) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn i128(&mut self, v: &i128) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn f64(&mut self, v: f64) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn bool(&mut self, v: bool) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn char(&mut self, v: char) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn str(&mut self, v: &str) -> Result<(), Error> { Debug::fmt(&v, self.0)?; Ok(()) } fn none(&mut self) -> Result<(), Error> { self.debug(&format_args!("None")) } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn std::error::Error + 'static)) -> Result<(), Error> { Debug::fmt(v, self.0)?; Ok(()) } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> { crate::internal::sval::v2::fmt(self.0, v) } #[cfg(feature = "serde1")] fn serde1( &mut self, v: &dyn crate::internal::serde::v1::Serialize, ) -> Result<(), Error> { crate::internal::serde::v1::fmt(self.0, v) } #[cfg(feature = "seq")] fn seq(&mut self, seq: &dyn crate::internal::seq::Seq) -> Result<(), Error> { let mut visitor = seq::FmtSeq(self.0.debug_list()); seq.visit(&mut visitor); visitor.0.finish()?; Ok(()) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { write!(self.0, "<{msg}>")?; Ok(()) } } self.internal_visit(&mut DebugVisitor(f)) .map_err(|_| fmt::Error)?; Ok(()) } } impl<'v> Display for ValueBag<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { struct DisplayVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>); impl<'a, 'b: 'a, 'v> InternalVisitor<'v> for DisplayVisitor<'a, 'b> { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } fn debug(&mut self, v: &dyn Debug) -> Result<(), Error> { Debug::fmt(v, self.0)?; Ok(()) } fn display(&mut self, v: &dyn Display) -> Result<(), Error> { Display::fmt(v, self.0)?; Ok(()) } fn u64(&mut self, v: u64) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn i64(&mut self, v: i64) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn u128(&mut self, v: &u128) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn i128(&mut self, v: &i128) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn f64(&mut self, v: f64) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn bool(&mut self, v: bool) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn char(&mut self, v: char) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn str(&mut self, v: &str) -> Result<(), Error> { Display::fmt(&v, self.0)?; Ok(()) } fn none(&mut self) -> Result<(), Error> { self.debug(&format_args!("None")) } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn std::error::Error + 'static)) -> Result<(), Error> { Display::fmt(v, self.0)?; Ok(()) } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> { crate::internal::sval::v2::fmt(self.0, v) } #[cfg(feature = "serde1")] fn serde1( &mut self, v: &dyn crate::internal::serde::v1::Serialize, ) -> Result<(), Error> { crate::internal::serde::v1::fmt(self.0, v) } #[cfg(feature = "seq")] fn seq(&mut self, seq: &dyn crate::internal::seq::Seq) -> Result<(), Error> { let mut visitor = seq::FmtSeq(self.0.debug_list()); seq.visit(&mut visitor); visitor.0.finish()?; Ok(()) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { write!(self.0, "<{msg}>")?; Ok(()) } } self.internal_visit(&mut DisplayVisitor(f)) .map_err(|_| fmt::Error)?; Ok(()) } } #[cfg(feature = "seq")] mod seq { use super::*; use core::ops::ControlFlow; pub(super) struct FmtSeq<'a, 'b>(pub(super) fmt::DebugList<'b, 'a>); impl<'a, 'b, 'c> crate::internal::seq::Visitor<'c> for FmtSeq<'a, 'b> { fn element(&mut self, inner: ValueBag) -> ControlFlow<()> { self.0.entry(&inner); ControlFlow::Continue(()) } } } #[cfg(feature = "owned")] pub(crate) mod owned { use crate::std::{boxed::Box, fmt, string::ToString}; impl fmt::Debug for crate::OwnedValueBag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.by_ref(), f) } } impl fmt::Display for crate::OwnedValueBag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.by_ref(), f) } } #[derive(Clone)] pub(crate) struct OwnedFmt(Box); pub(crate) fn buffer_debug(v: impl fmt::Debug) -> OwnedFmt { OwnedFmt(format!("{:?}", v).into()) } pub(crate) fn buffer_display(v: impl fmt::Display) -> OwnedFmt { OwnedFmt(v.to_string().into()) } impl fmt::Debug for OwnedFmt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } impl fmt::Display for OwnedFmt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::{ std::string::ToString, test::{IntoValueBag, TestToken}, }; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_capture() { assert_eq!( ValueBag::capture_debug(&1u16).to_test_token(), TestToken::U64(1) ); assert_eq!( ValueBag::capture_display(&1u16).to_test_token(), TestToken::U64(1) ); assert_eq!( ValueBag::capture_debug(&Some(1u16)).to_test_token(), TestToken::U64(1) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_fill() { assert_eq!( ValueBag::from_fill(&|slot: Slot| slot.fill_debug(1u16)).to_test_token(), TestToken::Str("1".into()) ); assert_eq!( ValueBag::from_fill(&|slot: Slot| slot.fill_display(1u16)).to_test_token(), TestToken::Str("1".into()) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_capture_args() { assert_eq!( ValueBag::from_debug(&format_args!("a {}", "value")).to_string(), "a value" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_cast() { assert_eq!( 42u64, ValueBag::capture_debug(&42u64) .to_u64() .expect("invalid value") ); assert_eq!( "a string", ValueBag::capture_display(&"a string") .to_borrowed_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_downcast() { #[derive(Debug, PartialEq, Eq)] struct Timestamp(usize); impl Display for Timestamp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "time is {}", self.0) } } let ts = Timestamp(42); assert_eq!( &ts, ValueBag::capture_debug(&ts) .downcast_ref::() .expect("invalid value") ); assert_eq!( &ts, ValueBag::capture_display(&ts) .downcast_ref::() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_debug() { assert_eq!( format!("{:?}", "a string"), format!("{:?}", "a string".into_value_bag().by_ref()), ); assert_eq!( format!("{:04?}", 42u64), format!("{:04?}", 42u64.into_value_bag().by_ref()), ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_display() { assert_eq!( format!("{}", "a string"), format!("{}", "a string".into_value_bag().by_ref()), ); assert_eq!( format!("{:04}", 42u64), format!("{:04}", 42u64.into_value_bag().by_ref()), ); } #[cfg(feature = "seq")] mod seq_support { use super::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_debug_seq() { assert_eq!( "[01, 02, 03]", format!("{:>02?}", ValueBag::from_seq_slice(&[1, 2, 3])) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_display_seq() { assert_eq!( "[1, 2, 3]", format!("{}", ValueBag::from_seq_slice(&[1, 2, 3])) ); } } } value-bag-1.9.0/src/internal/mod.rs000064400000000000000000000452151046102023000152350ustar 00000000000000//! The internal `Value` serialization API. //! //! This implementation isn't intended to be public. It may need to change //! for optimizations or to support new external serialization frameworks. use crate::{fill::Fill, Error, ValueBag}; pub(crate) mod cast; #[cfg(feature = "error")] pub(crate) mod error; pub(crate) mod fmt; #[cfg(feature = "seq")] pub(crate) mod seq; #[cfg(feature = "serde1")] pub(crate) mod serde; #[cfg(feature = "sval2")] pub(crate) mod sval; #[cfg(feature = "owned")] pub(crate) mod owned; #[cfg(feature = "owned")] use crate::std::sync::Arc; // NOTE: It takes less space to have separate variants for the presence // of a `TypeId` instead of using `Option`, because `TypeId` doesn't // have a niche value /// A container for a structured value for a specific kind of visitor. #[derive(Clone)] pub(crate) enum Internal<'v> { // Primitive values Signed(i64), Unsigned(u64), #[cfg(not(feature = "inline-i128"))] BigSigned(&'v i128), #[cfg(feature = "inline-i128")] BigSigned(i128), #[cfg(not(feature = "inline-i128"))] BigUnsigned(&'v u128), #[cfg(feature = "inline-i128")] BigUnsigned(u128), Float(f64), Bool(bool), Char(char), Str(&'v str), None, // Captured values Fill(&'v dyn Fill), Debug(&'v dyn fmt::DowncastDebug), Display(&'v dyn fmt::DowncastDisplay), #[cfg(feature = "error")] Error(&'v dyn error::DowncastError), #[cfg(feature = "sval2")] Sval2(&'v dyn sval::v2::DowncastValue), #[cfg(feature = "serde1")] Serde1(&'v dyn serde::v1::DowncastSerialize), // Anonymous values AnonDebug(&'v dyn fmt::Debug), AnonDisplay(&'v dyn fmt::Display), #[cfg(feature = "error")] AnonError(&'v (dyn error::Error + 'static)), #[cfg(feature = "sval2")] AnonSval2(&'v dyn sval::v2::Value), #[cfg(feature = "serde1")] AnonSerde1(&'v dyn serde::v1::Serialize), #[cfg(feature = "seq")] AnonSeq(&'v dyn seq::Seq), // Shared values #[cfg(feature = "owned")] SharedDebug(Arc), #[cfg(feature = "owned")] SharedDisplay(Arc), #[cfg(all(feature = "error", feature = "owned"))] SharedError(Arc), #[cfg(all(feature = "serde1", feature = "owned"))] SharedSerde1(Arc), #[cfg(all(feature = "sval2", feature = "owned"))] SharedSval2(Arc), #[cfg(all(feature = "seq", feature = "owned"))] SharedSeq(Arc), // NOTE: These variants exist because we can't clone an `Arc` in `const` fns // (plus we may not want to anyways) #[cfg(feature = "owned")] SharedRefDebug(&'v Arc), #[cfg(feature = "owned")] SharedRefDisplay(&'v Arc), #[cfg(all(feature = "error", feature = "owned"))] SharedRefError(&'v Arc), #[cfg(all(feature = "serde1", feature = "owned"))] SharedRefSerde1(&'v Arc), #[cfg(all(feature = "sval2", feature = "owned"))] SharedRefSval2(&'v Arc), #[cfg(all(feature = "seq", feature = "owned"))] SharedRefSeq(&'v Arc), // Poisoned value #[cfg_attr(not(feature = "owned"), allow(dead_code))] Poisoned(&'static str), } /// The internal serialization contract. pub(crate) trait InternalVisitor<'v> { fn fill(&mut self, v: &dyn Fill) -> Result<(), Error>; fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error>; fn borrowed_debug(&mut self, v: &'v dyn fmt::Debug) -> Result<(), Error> { self.debug(v) } #[cfg(feature = "owned")] fn shared_debug(&mut self, v: &Arc) -> Result<(), Error> { self.debug(v) } fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error>; fn borrowed_display(&mut self, v: &'v dyn fmt::Display) -> Result<(), Error> { self.display(v) } #[cfg(feature = "owned")] fn shared_display( &mut self, v: &Arc, ) -> Result<(), Error> { self.display(v) } fn u64(&mut self, v: u64) -> Result<(), Error>; fn i64(&mut self, v: i64) -> Result<(), Error>; fn u128(&mut self, v: &u128) -> Result<(), Error>; #[cfg(not(feature = "inline-i128"))] fn borrowed_u128(&mut self, v: &'v u128) -> Result<(), Error> { self.u128(v) } fn i128(&mut self, v: &i128) -> Result<(), Error>; #[cfg(not(feature = "inline-i128"))] fn borrowed_i128(&mut self, v: &'v i128) -> Result<(), Error> { self.i128(v) } fn f64(&mut self, v: f64) -> Result<(), Error>; fn bool(&mut self, v: bool) -> Result<(), Error>; fn char(&mut self, v: char) -> Result<(), Error>; fn str(&mut self, v: &str) -> Result<(), Error>; fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { self.str(v) } fn none(&mut self) -> Result<(), Error>; #[cfg(feature = "error")] fn error(&mut self, v: &(dyn error::Error + 'static)) -> Result<(), Error>; #[cfg(feature = "error")] fn borrowed_error(&mut self, v: &'v (dyn error::Error + 'static)) -> Result<(), Error> { self.error(v) } #[cfg(all(feature = "error", feature = "owned"))] fn shared_error( &mut self, v: &Arc, ) -> Result<(), Error> { self.error(v.as_super()) } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn sval::v2::Value) -> Result<(), Error>; #[cfg(feature = "sval2")] fn borrowed_sval2(&mut self, v: &'v dyn sval::v2::Value) -> Result<(), Error> { self.sval2(v) } #[cfg(all(feature = "sval2", feature = "owned"))] fn shared_sval2( &mut self, v: &Arc, ) -> Result<(), Error> { self.sval2(v.as_super()) } #[cfg(feature = "serde1")] fn serde1(&mut self, v: &dyn serde::v1::Serialize) -> Result<(), Error>; #[cfg(feature = "serde1")] fn borrowed_serde1(&mut self, v: &'v dyn serde::v1::Serialize) -> Result<(), Error> { self.serde1(v) } #[cfg(all(feature = "serde1", feature = "owned"))] fn shared_serde1( &mut self, v: &Arc, ) -> Result<(), Error> { self.serde1(v.as_super()) } #[cfg(feature = "seq")] fn seq(&mut self, v: &dyn seq::Seq) -> Result<(), Error>; #[cfg(feature = "seq")] fn borrowed_seq(&mut self, v: &'v dyn seq::Seq) -> Result<(), Error> { self.seq(v) } #[cfg(all(feature = "seq", feature = "owned"))] fn shared_seq(&mut self, v: &Arc) -> Result<(), Error> { self.seq(v.as_super()) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error>; } impl<'a, 'v, V: InternalVisitor<'v> + ?Sized> InternalVisitor<'v> for &'a mut V { fn fill(&mut self, v: &dyn Fill) -> Result<(), Error> { (**self).fill(v) } fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error> { (**self).debug(v) } fn borrowed_debug(&mut self, v: &'v dyn fmt::Debug) -> Result<(), Error> { (**self).borrowed_debug(v) } #[cfg(feature = "owned")] fn shared_debug(&mut self, v: &Arc) -> Result<(), Error> { (**self).shared_debug(v) } fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error> { (**self).display(v) } fn borrowed_display(&mut self, v: &'v dyn fmt::Display) -> Result<(), Error> { (**self).borrowed_display(v) } #[cfg(feature = "owned")] fn shared_display( &mut self, v: &Arc, ) -> Result<(), Error> { (**self).shared_display(v) } fn u64(&mut self, v: u64) -> Result<(), Error> { (**self).u64(v) } fn i64(&mut self, v: i64) -> Result<(), Error> { (**self).i64(v) } fn u128(&mut self, v: &u128) -> Result<(), Error> { (**self).u128(v) } #[cfg(not(feature = "inline-i128"))] fn borrowed_u128(&mut self, v: &'v u128) -> Result<(), Error> { (**self).borrowed_u128(v) } fn i128(&mut self, v: &i128) -> Result<(), Error> { (**self).i128(v) } #[cfg(not(feature = "inline-i128"))] fn borrowed_i128(&mut self, v: &'v i128) -> Result<(), Error> { (**self).borrowed_i128(v) } fn f64(&mut self, v: f64) -> Result<(), Error> { (**self).f64(v) } fn bool(&mut self, v: bool) -> Result<(), Error> { (**self).bool(v) } fn char(&mut self, v: char) -> Result<(), Error> { (**self).char(v) } fn str(&mut self, v: &str) -> Result<(), Error> { (**self).str(v) } fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { (**self).borrowed_str(v) } fn none(&mut self) -> Result<(), Error> { (**self).none() } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn error::Error + 'static)) -> Result<(), Error> { (**self).error(v) } #[cfg(feature = "error")] fn borrowed_error(&mut self, v: &'v (dyn error::Error + 'static)) -> Result<(), Error> { (**self).borrowed_error(v) } #[cfg(all(feature = "error", feature = "owned"))] fn shared_error( &mut self, v: &Arc, ) -> Result<(), Error> { (**self).shared_error(v) } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn sval::v2::Value) -> Result<(), Error> { (**self).sval2(v) } #[cfg(feature = "sval2")] fn borrowed_sval2(&mut self, v: &'v dyn sval::v2::Value) -> Result<(), Error> { (**self).borrowed_sval2(v) } #[cfg(all(feature = "sval2", feature = "owned"))] fn shared_sval2( &mut self, v: &Arc, ) -> Result<(), Error> { (**self).shared_sval2(v) } #[cfg(feature = "serde1")] fn serde1(&mut self, v: &dyn serde::v1::Serialize) -> Result<(), Error> { (**self).serde1(v) } #[cfg(feature = "serde1")] fn borrowed_serde1(&mut self, v: &'v dyn serde::v1::Serialize) -> Result<(), Error> { (**self).borrowed_serde1(v) } #[cfg(all(feature = "serde1", feature = "owned"))] fn shared_serde1( &mut self, v: &Arc, ) -> Result<(), Error> { (**self).shared_serde1(v) } #[cfg(feature = "seq")] fn seq(&mut self, seq: &dyn seq::Seq) -> Result<(), Error> { (**self).seq(seq) } #[cfg(feature = "seq")] fn borrowed_seq(&mut self, seq: &'v dyn seq::Seq) -> Result<(), Error> { (**self).borrowed_seq(seq) } #[cfg(all(feature = "seq", feature = "owned"))] fn shared_seq(&mut self, seq: &Arc) -> Result<(), Error> { (**self).shared_seq(seq) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { (**self).poisoned(msg) } } impl<'v> ValueBag<'v> { /// Visit the value using an internal visitor. #[inline] pub(crate) fn internal_visit(&self, visitor: impl InternalVisitor<'v>) -> Result<(), Error> { self.inner.internal_visit(visitor) } } impl<'v> Internal<'v> { #[inline] pub(crate) const fn by_ref(&self) -> Internal<'_> { match self { Internal::Signed(value) => Internal::Signed(*value), Internal::Unsigned(value) => Internal::Unsigned(*value), Internal::BigSigned(value) => Internal::BigSigned(*value), Internal::BigUnsigned(value) => Internal::BigUnsigned(*value), Internal::Float(value) => Internal::Float(*value), Internal::Bool(value) => Internal::Bool(*value), Internal::Char(value) => Internal::Char(*value), Internal::Str(value) => Internal::Str(value), Internal::None => Internal::None, Internal::Fill(value) => Internal::Fill(*value), Internal::AnonDebug(value) => Internal::AnonDebug(*value), Internal::Debug(value) => Internal::Debug(*value), Internal::AnonDisplay(value) => Internal::AnonDisplay(*value), Internal::Display(value) => Internal::Display(*value), #[cfg(feature = "error")] Internal::AnonError(value) => Internal::AnonError(*value), #[cfg(feature = "error")] Internal::Error(value) => Internal::Error(*value), #[cfg(feature = "sval2")] Internal::AnonSval2(value) => Internal::AnonSval2(*value), #[cfg(feature = "sval2")] Internal::Sval2(value) => Internal::Sval2(*value), #[cfg(feature = "serde1")] Internal::AnonSerde1(value) => Internal::AnonSerde1(*value), #[cfg(feature = "serde1")] Internal::Serde1(value) => Internal::Serde1(*value), #[cfg(feature = "seq")] Internal::AnonSeq(value) => Internal::AnonSeq(*value), #[cfg(feature = "owned")] Internal::SharedDebug(ref value) => Internal::SharedRefDebug(value), #[cfg(feature = "owned")] Internal::SharedDisplay(ref value) => Internal::SharedRefDisplay(value), #[cfg(all(feature = "error", feature = "owned"))] Internal::SharedError(ref value) => Internal::SharedRefError(value), #[cfg(all(feature = "serde1", feature = "owned"))] Internal::SharedSerde1(ref value) => Internal::SharedRefSerde1(value), #[cfg(all(feature = "sval2", feature = "owned"))] Internal::SharedSval2(ref value) => Internal::SharedRefSval2(value), #[cfg(all(feature = "seq", feature = "owned"))] Internal::SharedSeq(ref value) => Internal::SharedRefSeq(value), #[cfg(feature = "owned")] Internal::SharedRefDebug(value) => Internal::SharedRefDebug(*value), #[cfg(feature = "owned")] Internal::SharedRefDisplay(value) => Internal::SharedRefDisplay(*value), #[cfg(all(feature = "error", feature = "owned"))] Internal::SharedRefError(value) => Internal::SharedRefError(*value), #[cfg(all(feature = "serde1", feature = "owned"))] Internal::SharedRefSerde1(value) => Internal::SharedRefSerde1(*value), #[cfg(all(feature = "sval2", feature = "owned"))] Internal::SharedRefSval2(value) => Internal::SharedRefSval2(*value), #[cfg(all(feature = "seq", feature = "owned"))] Internal::SharedRefSeq(value) => Internal::SharedRefSeq(*value), Internal::Poisoned(msg) => Internal::Poisoned(msg), } } #[inline] pub(crate) fn internal_visit( &self, mut visitor: impl InternalVisitor<'v>, ) -> Result<(), Error> { match self { Internal::Signed(value) => visitor.i64(*value), Internal::Unsigned(value) => visitor.u64(*value), #[cfg(feature = "inline-i128")] Internal::BigSigned(value) => visitor.i128(value), #[cfg(feature = "inline-i128")] Internal::BigUnsigned(value) => visitor.u128(value), #[cfg(not(feature = "inline-i128"))] Internal::BigSigned(value) => visitor.borrowed_i128(value), #[cfg(not(feature = "inline-i128"))] Internal::BigUnsigned(value) => visitor.borrowed_u128(value), Internal::Float(value) => visitor.f64(*value), Internal::Bool(value) => visitor.bool(*value), Internal::Char(value) => visitor.char(*value), Internal::Str(value) => visitor.borrowed_str(value), Internal::None => visitor.none(), Internal::Fill(value) => visitor.fill(*value), Internal::AnonDebug(value) => visitor.borrowed_debug(*value), Internal::Debug(value) => visitor.borrowed_debug(value.as_super()), Internal::AnonDisplay(value) => visitor.borrowed_display(*value), Internal::Display(value) => visitor.borrowed_display(value.as_super()), #[cfg(feature = "error")] Internal::AnonError(value) => visitor.borrowed_error(*value), #[cfg(feature = "error")] Internal::Error(value) => visitor.borrowed_error(value.as_super()), #[cfg(feature = "sval2")] Internal::AnonSval2(value) => visitor.borrowed_sval2(*value), #[cfg(feature = "sval2")] Internal::Sval2(value) => visitor.borrowed_sval2(value.as_super()), #[cfg(feature = "serde1")] Internal::AnonSerde1(value) => visitor.borrowed_serde1(*value), #[cfg(feature = "serde1")] Internal::Serde1(value) => visitor.borrowed_serde1(value.as_super()), #[cfg(feature = "seq")] Internal::AnonSeq(value) => visitor.borrowed_seq(*value), #[cfg(feature = "owned")] Internal::SharedDebug(ref value) => visitor.shared_debug(value), #[cfg(feature = "owned")] Internal::SharedDisplay(ref value) => visitor.shared_display(value), #[cfg(all(feature = "error", feature = "owned"))] Internal::SharedError(ref value) => visitor.shared_error(value), #[cfg(all(feature = "serde1", feature = "owned"))] Internal::SharedSerde1(ref value) => visitor.shared_serde1(value), #[cfg(all(feature = "sval2", feature = "owned"))] Internal::SharedSval2(ref value) => visitor.shared_sval2(value), #[cfg(all(feature = "seq", feature = "owned"))] Internal::SharedSeq(value) => visitor.shared_seq(value), #[cfg(feature = "owned")] Internal::SharedRefDebug(value) => visitor.shared_debug(value), #[cfg(feature = "owned")] Internal::SharedRefDisplay(value) => visitor.shared_display(value), #[cfg(all(feature = "error", feature = "owned"))] Internal::SharedRefError(value) => visitor.shared_error(value), #[cfg(all(feature = "serde1", feature = "owned"))] Internal::SharedRefSerde1(value) => visitor.shared_serde1(value), #[cfg(all(feature = "sval2", feature = "owned"))] Internal::SharedRefSval2(value) => visitor.shared_sval2(value), #[cfg(all(feature = "seq", feature = "owned"))] Internal::SharedRefSeq(value) => visitor.shared_seq(value), Internal::Poisoned(msg) => visitor.poisoned(msg), } } } value-bag-1.9.0/src/internal/owned.rs000064400000000000000000000253001046102023000155630ustar 00000000000000use crate::{ internal::{self, Internal, InternalVisitor}, std::{boxed::Box, sync::Arc}, Error, }; #[derive(Clone)] pub(crate) enum OwnedInternal { // Primitive values BigSigned(i128), BigUnsigned(u128), Float(f64), Bool(bool), Char(char), Str(Box), None, // Buffered values Debug(internal::fmt::owned::OwnedFmt), Display(internal::fmt::owned::OwnedFmt), #[cfg(feature = "error")] Error(internal::error::owned::OwnedError), #[cfg(feature = "serde1")] Serde1(internal::serde::v1::owned::OwnedSerialize), #[cfg(feature = "sval2")] Sval2(internal::sval::v2::owned::OwnedValue), #[cfg(feature = "seq")] Seq(internal::seq::owned::OwnedSeq), // Shared values SharedDebug(Arc), SharedDisplay(Arc), #[cfg(feature = "error")] SharedError(Arc), #[cfg(feature = "serde1")] SharedSerde1(Arc), #[cfg(feature = "sval2")] SharedSval2(Arc), #[cfg(feature = "seq")] SharedSeq(Arc), // Poisoned value Poisoned(&'static str), } impl OwnedInternal { #[inline] pub(crate) const fn by_ref(&self) -> Internal { match self { #[cfg(not(feature = "inline-i128"))] OwnedInternal::BigSigned(v) => Internal::BigSigned(v), #[cfg(feature = "inline-i128")] OwnedInternal::BigSigned(v) => Internal::BigSigned(*v), #[cfg(not(feature = "inline-i128"))] OwnedInternal::BigUnsigned(v) => Internal::BigUnsigned(v), #[cfg(feature = "inline-i128")] OwnedInternal::BigUnsigned(v) => Internal::BigUnsigned(*v), OwnedInternal::Float(v) => Internal::Float(*v), OwnedInternal::Bool(v) => Internal::Bool(*v), OwnedInternal::Char(v) => Internal::Char(*v), OwnedInternal::Str(v) => Internal::Str(v), OwnedInternal::None => Internal::None, OwnedInternal::Debug(v) => Internal::AnonDebug(v), OwnedInternal::Display(v) => Internal::AnonDisplay(v), #[cfg(feature = "error")] OwnedInternal::Error(v) => Internal::AnonError(v), #[cfg(feature = "serde1")] OwnedInternal::Serde1(v) => Internal::AnonSerde1(v), #[cfg(feature = "sval2")] OwnedInternal::Sval2(v) => Internal::AnonSval2(v), #[cfg(feature = "seq")] OwnedInternal::Seq(v) => Internal::AnonSeq(v), OwnedInternal::SharedDebug(ref value) => Internal::SharedRefDebug(value), OwnedInternal::SharedDisplay(ref value) => Internal::SharedRefDisplay(value), #[cfg(feature = "error")] OwnedInternal::SharedError(ref value) => Internal::SharedRefError(value), #[cfg(feature = "serde1")] OwnedInternal::SharedSerde1(ref value) => Internal::SharedRefSerde1(value), #[cfg(feature = "sval2")] OwnedInternal::SharedSval2(ref value) => Internal::SharedRefSval2(value), #[cfg(feature = "seq")] OwnedInternal::SharedSeq(ref value) => Internal::SharedRefSeq(value), OwnedInternal::Poisoned(msg) => Internal::Poisoned(msg), } } #[inline] pub(crate) fn into_shared(self) -> Self { match self { OwnedInternal::BigSigned(v) => OwnedInternal::BigSigned(v), OwnedInternal::BigUnsigned(v) => OwnedInternal::BigUnsigned(v), OwnedInternal::Float(v) => OwnedInternal::Float(v), OwnedInternal::Bool(v) => OwnedInternal::Bool(v), OwnedInternal::Char(v) => OwnedInternal::Char(v), OwnedInternal::Str(v) => OwnedInternal::Str(v), OwnedInternal::None => OwnedInternal::None, OwnedInternal::Debug(v) => OwnedInternal::SharedDebug(Arc::new(v)), OwnedInternal::Display(v) => OwnedInternal::SharedDisplay(Arc::new(v)), #[cfg(feature = "error")] OwnedInternal::Error(v) => OwnedInternal::SharedError(Arc::new(v)), #[cfg(feature = "serde1")] OwnedInternal::Serde1(v) => OwnedInternal::SharedSerde1(Arc::new(v)), #[cfg(feature = "sval2")] OwnedInternal::Sval2(v) => OwnedInternal::SharedSval2(Arc::new(v)), #[cfg(feature = "seq")] OwnedInternal::Seq(v) => OwnedInternal::SharedSeq(Arc::new(v)), OwnedInternal::SharedDebug(v) => OwnedInternal::SharedDebug(v), OwnedInternal::SharedDisplay(v) => OwnedInternal::SharedDisplay(v), #[cfg(feature = "error")] OwnedInternal::SharedError(v) => OwnedInternal::SharedError(v), #[cfg(feature = "serde1")] OwnedInternal::SharedSerde1(v) => OwnedInternal::SharedSerde1(v), #[cfg(feature = "sval2")] OwnedInternal::SharedSval2(v) => OwnedInternal::SharedSval2(v), #[cfg(feature = "seq")] OwnedInternal::SharedSeq(v) => OwnedInternal::SharedSeq(v), OwnedInternal::Poisoned(msg) => OwnedInternal::Poisoned(msg), } } } impl<'v> Internal<'v> { pub(crate) fn to_owned(&self) -> OwnedInternal { struct OwnedVisitor(OwnedInternal); impl<'v> InternalVisitor<'v> for OwnedVisitor { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } fn debug(&mut self, v: &dyn internal::fmt::Debug) -> Result<(), Error> { self.0 = OwnedInternal::Debug(internal::fmt::owned::buffer_debug(v)); Ok(()) } fn shared_debug( &mut self, v: &Arc, ) -> Result<(), Error> { self.0 = OwnedInternal::SharedDebug(v.clone()); Ok(()) } fn display(&mut self, v: &dyn internal::fmt::Display) -> Result<(), Error> { self.0 = OwnedInternal::Display(internal::fmt::owned::buffer_display(v)); Ok(()) } fn shared_display( &mut self, v: &Arc, ) -> Result<(), Error> { self.0 = OwnedInternal::SharedDisplay(v.clone()); Ok(()) } fn u64(&mut self, v: u64) -> Result<(), Error> { self.0 = OwnedInternal::BigUnsigned(v as u128); Ok(()) } fn i64(&mut self, v: i64) -> Result<(), Error> { self.0 = OwnedInternal::BigSigned(v as i128); Ok(()) } fn u128(&mut self, v: &u128) -> Result<(), Error> { self.0 = OwnedInternal::BigUnsigned(*v); Ok(()) } fn i128(&mut self, v: &i128) -> Result<(), Error> { self.0 = OwnedInternal::BigSigned(*v); Ok(()) } fn f64(&mut self, v: f64) -> Result<(), Error> { self.0 = OwnedInternal::Float(v); Ok(()) } fn bool(&mut self, v: bool) -> Result<(), Error> { self.0 = OwnedInternal::Bool(v); Ok(()) } fn char(&mut self, v: char) -> Result<(), Error> { self.0 = OwnedInternal::Char(v); Ok(()) } fn str(&mut self, v: &str) -> Result<(), Error> { self.0 = OwnedInternal::Str(v.into()); Ok(()) } fn none(&mut self) -> Result<(), Error> { self.0 = OwnedInternal::None; Ok(()) } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn internal::error::Error + 'static)) -> Result<(), Error> { self.0 = OwnedInternal::Error(internal::error::owned::buffer(v)); Ok(()) } #[cfg(feature = "error")] fn shared_error( &mut self, v: &Arc, ) -> Result<(), Error> { self.0 = OwnedInternal::SharedError(v.clone()); Ok(()) } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn internal::sval::v2::Value) -> Result<(), Error> { self.0 = internal::sval::v2::owned::buffer(v) .map(OwnedInternal::Sval2) .unwrap_or(OwnedInternal::Poisoned("failed to buffer the value")); Ok(()) } #[cfg(feature = "sval2")] fn shared_sval2( &mut self, v: &Arc, ) -> Result<(), Error> { self.0 = OwnedInternal::SharedSval2(v.clone()); Ok(()) } #[cfg(feature = "serde1")] fn serde1(&mut self, v: &dyn internal::serde::v1::Serialize) -> Result<(), Error> { self.0 = internal::serde::v1::owned::buffer(v) .map(OwnedInternal::Serde1) .unwrap_or(OwnedInternal::Poisoned("failed to buffer the value")); Ok(()) } #[cfg(feature = "serde1")] fn shared_serde1( &mut self, v: &Arc, ) -> Result<(), Error> { self.0 = OwnedInternal::SharedSerde1(v.clone()); Ok(()) } #[cfg(feature = "seq")] fn seq(&mut self, v: &dyn internal::seq::Seq) -> Result<(), Error> { self.0 = internal::seq::owned::buffer(v) .map(OwnedInternal::Seq) .unwrap_or(OwnedInternal::Poisoned("failed to buffer the value")); Ok(()) } #[cfg(feature = "seq")] fn shared_seq( &mut self, v: &Arc, ) -> Result<(), Error> { self.0 = OwnedInternal::SharedSeq(v.clone()); Ok(()) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { self.0 = OwnedInternal::Poisoned(msg); Ok(()) } } let mut visitor = OwnedVisitor(OwnedInternal::None); let _ = self.internal_visit(&mut visitor); visitor.0 } } value-bag-1.9.0/src/internal/seq.rs000064400000000000000000000560141046102023000152450ustar 00000000000000use crate::{ fill::Slot, internal::{Internal, InternalVisitor}, std::{any::Any, fmt, marker::PhantomData, mem, ops::ControlFlow}, Error, ValueBag, }; #[cfg(feature = "alloc")] use crate::std::{string::String, vec::Vec}; impl<'v> ValueBag<'v> { /// Get a value from a sequence of values without capturing support. pub fn from_seq_slice(value: &'v I) -> Self where I: AsRef<[T]>, &'v T: Into> + 'v, { ValueBag { inner: Internal::AnonSeq(SeqSlice::new_ref(value)), } } pub(crate) const fn from_dyn_seq(value: &'v dyn Seq) -> Self { ValueBag { inner: Internal::AnonSeq(value), } } /// Try get a collection `S` of `u64`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_u64_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Try get a collection `S` of `i64`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_i64_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Try get a collection `S` of `u128`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_u128_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Try get a collection `S` of `i128`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_i128_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Try get a collection `S` of `f64`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_f64_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Get a collection `S` of `f64`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the conversion of each of its elements. The conversion is the /// same as [`ValueBag::as_f64`]. /// /// If this value is not a sequence then this method will return an /// empty collection. /// /// This is similar to [`ValueBag::to_f64_seq`], but can be more /// convenient when there's no need to distinguish between an empty /// collection and a non-collection, or between `f64` and non-`f64` elements. pub fn as_f64_seq>(&self) -> S { #[derive(Default)] struct ExtendF64(S); impl<'a, S: Extend> ExtendValue<'a> for ExtendF64 { fn extend(&mut self, inner: Internal<'_>) { self.0.extend(Some(ValueBag { inner }.as_f64())) } } self.inner .extend::>() .map(|seq| seq.0) .unwrap_or_default() } /// Try get a collection `S` of `bool`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_bool_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Try get a collection `S` of `char`s from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. pub fn to_char_seq>>(&self) -> Option { self.inner .extend::>() .map(|seq| seq.into_inner()) } /// Try get a collection `S` of strings from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. #[inline] pub fn to_borrowed_str_seq>>(&self) -> Option { #[derive(Default)] struct ExtendStr<'a, S>(S, PhantomData<&'a str>); impl<'a, S: Extend>> ExtendValue<'a> for ExtendStr<'a, S> { fn extend<'b>(&mut self, _: Internal<'b>) { self.0.extend(Some(None::<&'a str>)) } fn extend_borrowed(&mut self, inner: Internal<'a>) { self.0.extend(Some(ValueBag { inner }.to_borrowed_str())) } } self.inner.extend::>().map(|seq| seq.0) } } impl<'s, 'f> Slot<'s, 'f> { /// Fill the slot with a sequence of values. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_seq_slice(self, value: &'f I) -> Result<(), Error> where I: AsRef<[T]>, &'f T: Into> + 'f, { self.fill(|visitor| visitor.seq(SeqSlice::new_ref(value))) } } /* This is a bit of an ugly way of working around the gulf between lifetimes expressed externally as bounds, and lifetimes implied on methods. */ #[repr(transparent)] struct SeqSlice<'a, I: ?Sized, T>(PhantomData<&'a [T]>, I); impl<'a, I: AsRef<[T]> + ?Sized + 'a, T> SeqSlice<'a, I, T> { fn new_ref(v: &'a I) -> &'a SeqSlice<'a, I, T> { // SAFETY: `SeqSlice<'a, I, T>` and `I` have the same ABI unsafe { &*(v as *const I as *const SeqSlice<'a, I, T>) } } fn as_ref<'b>(&'b self) -> &'a [T] { // SAFETY: `new_ref` requires there's a borrow of `&'a I` // on the borrow stack, so we can safely borrow it for `'a` here let inner = unsafe { mem::transmute::<&'b I, &'a I>(&self.1) }; inner.as_ref() } } impl<'a, I, T> Seq for SeqSlice<'a, I, T> where I: AsRef<[T]> + ?Sized + 'a, &'a T: Into>, { fn visit(&self, visitor: &mut dyn Visitor<'_>) { for v in self.as_ref().iter() { if let ControlFlow::Break(()) = visitor.element(v.into()) { return; } } } fn borrowed_visit<'v>(&'v self, visitor: &mut dyn Visitor<'v>) { for v in self.as_ref().iter() { if let ControlFlow::Break(()) = visitor.borrowed_element(v.into()) { return; } } } } pub(crate) trait Seq { fn visit(&self, visitor: &mut dyn Visitor<'_>); fn borrowed_visit<'v>(&'v self, visitor: &mut dyn Visitor<'v>) { self.visit(visitor) } } impl<'a, S: Seq + ?Sized> Seq for &'a S { fn visit(&self, visitor: &mut dyn Visitor<'_>) { (**self).visit(visitor) } fn borrowed_visit<'v>(&'v self, visitor: &mut dyn Visitor<'v>) { (**self).borrowed_visit(visitor) } } pub(crate) trait Visitor<'v> { fn element(&mut self, v: ValueBag) -> ControlFlow<()>; fn borrowed_element(&mut self, v: ValueBag<'v>) -> ControlFlow<()> { self.element(v) } } impl<'a, 'v, T: Visitor<'v> + ?Sized> Visitor<'v> for &'a mut T { fn element(&mut self, v: ValueBag) -> ControlFlow<()> { (**self).element(v) } fn borrowed_element(&mut self, v: ValueBag<'v>) -> ControlFlow<()> { (**self).borrowed_element(v) } } pub(crate) trait DowncastSeq { // Currently only used when `owned` is also available #[allow(dead_code)] fn as_any(&self) -> &dyn Any; fn as_super(&self) -> &dyn Seq; } impl DowncastSeq for T { fn as_any(&self) -> &dyn Any { self } fn as_super(&self) -> &dyn Seq { self } } impl<'a> Seq for dyn DowncastSeq + Send + Sync + 'a { fn visit(&self, visitor: &mut dyn Visitor<'_>) { self.as_super().visit(visitor) } } macro_rules! convert_primitive( ($($t:ty,)*) => { $( impl<'v, const N: usize> From<&'v [$t; N]> for ValueBag<'v> { fn from(v: &'v [$t; N]) -> Self { ValueBag::from_seq_slice(v) } } impl<'v, const N: usize> From> for ValueBag<'v> { fn from(v: Option<&'v [$t; N]>) -> Self { ValueBag::from_option(v) } } impl<'a, 'v> From<&'v &'a [$t]> for ValueBag<'v> { fn from(v: &'v &'a [$t]) -> Self { ValueBag::from_seq_slice(v) } } impl<'a, 'v> From> for ValueBag<'v> { fn from(v: Option<&'v &'a [$t]>) -> Self { ValueBag::from_option(v) } } #[cfg(feature = "alloc")] impl<'v> From<&'v Vec<$t>> for ValueBag<'v> { fn from(v: &'v Vec<$t>) -> Self { ValueBag::from_seq_slice(v) } } #[cfg(feature = "alloc")] impl<'v> From>> for ValueBag<'v> { fn from(v: Option<&'v Vec<$t>>) -> Self { ValueBag::from_option(v) } } )* } ); convert_primitive![ u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool, char, ]; impl<'v, 'a, const N: usize> From<&'v [&'a str; N]> for ValueBag<'v> { fn from(v: &'v [&'a str; N]) -> Self { ValueBag::from_seq_slice(v) } } impl<'v, 'a, const N: usize> From> for ValueBag<'v> { fn from(v: Option<&'v [&'a str; N]>) -> Self { ValueBag::from_option(v) } } impl<'v, 'a, 'b> From<&'v &'a [&'b str]> for ValueBag<'v> { fn from(v: &'v &'a [&'b str]) -> Self { ValueBag::from_seq_slice(v) } } impl<'v, 'a, 'b> From> for ValueBag<'v> { fn from(v: Option<&'v &'a [&'b str]>) -> Self { ValueBag::from_option(v) } } #[cfg(feature = "alloc")] impl<'v> From<&'v Vec> for ValueBag<'v> { fn from(v: &'v Vec) -> Self { ValueBag::from_seq_slice(v) } } #[cfg(feature = "alloc")] impl<'v> From>> for ValueBag<'v> { fn from(v: Option<&'v Vec>) -> Self { ValueBag::from_option(v) } } #[derive(Default)] pub(crate) struct ExtendPrimitive(S, PhantomData); impl ExtendPrimitive { pub fn into_inner(self) -> S { self.0 } } impl<'a, S: Extend>, T: for<'b> TryFrom>> ExtendValue<'a> for ExtendPrimitive { fn extend(&mut self, inner: Internal) { self.0.extend(Some(ValueBag { inner }.try_into().ok())) } } #[allow(dead_code)] pub(crate) trait ExtendValue<'v> { fn extend(&mut self, v: Internal); fn extend_borrowed(&mut self, v: Internal<'v>) { self.extend(v); } } struct ExtendVisitor(S); impl<'v, S: ExtendValue<'v>> Visitor<'v> for ExtendVisitor { fn element(&mut self, v: ValueBag) -> ControlFlow<()> { self.0.extend(v.inner); ControlFlow::Continue(()) } fn borrowed_element(&mut self, v: ValueBag<'v>) -> ControlFlow<()> { self.0.extend_borrowed(v.inner); ControlFlow::Continue(()) } } impl<'v> Internal<'v> { #[inline] pub(crate) fn extend>(&self) -> Option { struct SeqVisitor(Option); impl<'v, S: Default + ExtendValue<'v>> InternalVisitor<'v> for SeqVisitor { #[inline] fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(Slot::new(self)) } #[inline] fn debug(&mut self, _: &dyn fmt::Debug) -> Result<(), Error> { Ok(()) } #[inline] fn display(&mut self, _: &dyn fmt::Display) -> Result<(), Error> { Ok(()) } #[inline] fn u64(&mut self, _: u64) -> Result<(), Error> { Ok(()) } #[inline] fn i64(&mut self, _: i64) -> Result<(), Error> { Ok(()) } #[inline] fn u128(&mut self, _: &u128) -> Result<(), Error> { Ok(()) } #[inline] fn i128(&mut self, _: &i128) -> Result<(), Error> { Ok(()) } #[inline] fn f64(&mut self, _: f64) -> Result<(), Error> { Ok(()) } #[inline] fn bool(&mut self, _: bool) -> Result<(), Error> { Ok(()) } #[inline] fn char(&mut self, _: char) -> Result<(), Error> { Ok(()) } #[inline] fn str(&mut self, _: &str) -> Result<(), Error> { Ok(()) } #[inline] fn none(&mut self) -> Result<(), Error> { Ok(()) } #[cfg(feature = "error")] #[inline] fn error(&mut self, _: &dyn crate::internal::error::Error) -> Result<(), Error> { Ok(()) } #[cfg(feature = "sval2")] #[inline] fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> { self.0 = crate::internal::sval::v2::seq::extend(v); Ok(()) } #[cfg(feature = "sval2")] #[inline] fn borrowed_sval2( &mut self, v: &'v dyn crate::internal::sval::v2::Value, ) -> Result<(), Error> { self.0 = crate::internal::sval::v2::seq::extend_borrowed(v); Ok(()) } #[cfg(feature = "serde1")] #[inline] fn serde1( &mut self, v: &dyn crate::internal::serde::v1::Serialize, ) -> Result<(), Error> { self.0 = crate::internal::serde::v1::seq::extend(v); Ok(()) } fn seq(&mut self, seq: &dyn Seq) -> Result<(), Error> { let mut s = ExtendVisitor(S::default()); seq.visit(&mut s); self.0 = Some(s.0); Ok(()) } fn borrowed_seq(&mut self, seq: &'v dyn Seq) -> Result<(), Error> { let mut s = ExtendVisitor(S::default()); seq.borrowed_visit(&mut s); self.0 = Some(s.0); Ok(()) } fn poisoned(&mut self, _: &'static str) -> Result<(), Error> { Ok(()) } } let mut visitor = SeqVisitor(None); let _ = self.internal_visit(&mut visitor); visitor.0 } } #[cfg(feature = "alloc")] mod alloc_support { use super::*; use crate::std::borrow::Cow; impl<'v> ValueBag<'v> { /// Try get a collection `S` of strings from this value. /// /// If this value is a sequence then the collection `S` will be extended /// with the attempted conversion of each of its elements. /// /// If this value is not a sequence then this method will return `None`. #[inline] pub fn to_str_seq>>>(&self) -> Option { #[derive(Default)] struct ExtendStr<'a, S>(S, PhantomData>); impl<'a, S: Extend>>> ExtendValue<'a> for ExtendStr<'a, S> { fn extend(&mut self, inner: Internal<'_>) { self.0.extend(Some( ValueBag { inner } .to_str() .map(|s| Cow::Owned(s.into_owned())), )) } fn extend_borrowed(&mut self, inner: Internal<'a>) { self.0.extend(Some(ValueBag { inner }.to_str())) } } self.inner.extend::>().map(|seq| seq.0) } } } #[cfg(feature = "owned")] pub(crate) mod owned { use super::*; use crate::{owned::OwnedValueBag, std::boxed::Box}; #[derive(Clone)] pub(crate) struct OwnedSeq(Box<[OwnedValueBag]>); impl Seq for OwnedSeq { fn visit(&self, visitor: &mut dyn Visitor<'_>) { for item in self.0.iter() { if let ControlFlow::Break(()) = visitor.element(item.by_ref()) { return; } } } } pub(crate) fn buffer(v: &dyn Seq) -> Result { struct BufferVisitor(Vec); impl<'v> Visitor<'v> for BufferVisitor { fn element(&mut self, v: ValueBag) -> ControlFlow<()> { self.0.push(v.to_owned()); ControlFlow::Continue(()) } } let mut buf = BufferVisitor(Vec::new()); v.visit(&mut buf); Ok(OwnedSeq(buf.0.into_boxed_slice())) } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use std::vec::Vec; use super::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_u64_seq() { assert_eq!( Some(vec![Some(1u64), Some(2u64), Some(3u64)]), ValueBag::from(&[1u8, 2u8, 3u8]).to_u64_seq::>>() ); assert_eq!( Some(vec![Some(1u64), Some(2u64), Some(3u64)]), ValueBag::from(&[1u16, 2u16, 3u16]).to_u64_seq::>>() ); assert_eq!( Some(vec![Some(1u64), Some(2u64), Some(3u64)]), ValueBag::from(&[1u32, 2u32, 3u32]).to_u64_seq::>>() ); assert_eq!( Some(vec![Some(1u64), Some(2u64), Some(3u64)]), ValueBag::from(&[1u64, 2u64, 3u64]).to_u64_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_i64_seq() { assert_eq!( Some(vec![Some(1i64), Some(2i64), Some(3i64)]), ValueBag::from(&[1i8, 2i8, 3i8]).to_i64_seq::>>() ); assert_eq!( Some(vec![Some(1i64), Some(2i64), Some(3i64)]), ValueBag::from(&[1i16, 2i16, 3i16]).to_i64_seq::>>() ); assert_eq!( Some(vec![Some(1i64), Some(2i64), Some(3i64)]), ValueBag::from(&[1i32, 2i32, 3i32]).to_i64_seq::>>() ); assert_eq!( Some(vec![Some(1i64), Some(2i64), Some(3i64)]), ValueBag::from(&[1i64, 2i64, 3i64]).to_i64_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_f64_seq() { assert_eq!( Some(vec![Some(1.0f64), Some(2.0f64), Some(3.0f64)]), ValueBag::from(&[1.0f64, 2.0f64, 3.0f64]).to_f64_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn as_f64_seq() { assert_eq!( Vec::::new(), ValueBag::from(1.0f64).as_f64_seq::>() ); assert_eq!( vec![1.0f64, 2.0f64, 3.0f64], ValueBag::from(&[1, 2, 3]).as_f64_seq::>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_u128_seq() { assert_eq!( Some(vec![Some(1u128), Some(2u128), Some(3u128)]), ValueBag::from(&[1u128, 2u128, 3u128]).to_u128_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_i128_seq() { assert_eq!( Some(vec![Some(1i128), Some(2i128), Some(3i128)]), ValueBag::from(&[1i128, 2i128, 3i128]).to_i128_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_bool_seq() { assert_eq!( Some(vec![Some(true), Some(false)]), ValueBag::from(&[true, false]).to_bool_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_char_seq() { assert_eq!( Some(vec![Some('a'), Some('b'), Some('c')]), ValueBag::from(&['a', 'b', 'c']).to_char_seq::>>() ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_borrowed_str_seq() { let v = ["a", "b", "c"]; let v = ValueBag::from(&v); assert_eq!( Some(vec![Some("a"), Some("b"), Some("c")]), v.to_borrowed_str_seq::>>() ); let v = ValueBag::from_fill(&|slot: Slot| slot.fill_seq_slice(&["a", "b", "c"])); assert_eq!( Some(vec![None, None, None]), v.to_borrowed_str_seq::>>() ); } #[cfg(feature = "alloc")] mod alloc_support { use super::*; use crate::std::borrow::Cow; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn to_str_seq() { let v = ["a", "b", "c"]; let v = ValueBag::from(&v); assert_eq!( Some(vec![ Some(Cow::Borrowed("a")), Some(Cow::Borrowed("b")), Some(Cow::Borrowed("c")) ]), v.to_str_seq::>>>() ); let v = ValueBag::from_fill(&|slot: Slot| slot.fill_seq_slice(&["a", "b", "c"])); assert_eq!( Some(vec![ Some(Cow::Owned("a".into())), Some(Cow::Owned("b".into())), Some(Cow::Owned("c".into())) ]), v.to_str_seq::>>>() ); } } } value-bag-1.9.0/src/internal/serde/mod.rs000064400000000000000000000000231046102023000163230ustar 00000000000000pub(crate) mod v1; value-bag-1.9.0/src/internal/serde/v1.rs000064400000000000000000000733741046102023000161150ustar 00000000000000//! Integration between `Value` and `serde`. //! //! This module allows any `Value` to implement the `Serialize` trait, //! and for any `Serialize` to be captured as a `Value`. use crate::{ fill::Slot, internal::{Internal, InternalVisitor}, std::{any::Any, fmt}, Error, ValueBag, }; use value_bag_serde1::lib::ser::{Error as SerdeError, Impossible}; impl<'v> ValueBag<'v> { /// Get a value from a structured type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Value` implementation. pub fn capture_serde1(value: &'v T) -> Self where T: value_bag_serde1::lib::Serialize + 'static, { Self::try_capture(value).unwrap_or(ValueBag { inner: Internal::Serde1(value), }) } /// Get a value from a structured type without capturing support. pub const fn from_serde1(value: &'v T) -> Self where T: value_bag_serde1::lib::Serialize, { ValueBag { inner: Internal::AnonSerde1(value), } } // NOTE: no `from_dyn_serde1` until `erased-serde` stabilizes pub(crate) const fn from_dyn_serde1(value: &'v dyn Serialize) -> Self { ValueBag { inner: Internal::AnonSerde1(value), } } } pub(crate) trait DowncastSerialize { fn as_any(&self) -> &dyn Any; fn as_super(&self) -> &dyn Serialize; } impl DowncastSerialize for T { fn as_any(&self) -> &dyn Any { self } fn as_super(&self) -> &dyn Serialize { self } } impl<'s, 'f> Slot<'s, 'f> { /// Fill the slot with a structured value. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_serde1(self, value: T) -> Result<(), Error> where T: value_bag_serde1::lib::Serialize, { self.fill(|visitor| visitor.serde1(&value)) } } impl<'v> value_bag_serde1::lib::Serialize for ValueBag<'v> { fn serialize(&self, s: S) -> Result where S: value_bag_serde1::lib::Serializer, { struct Serde1Visitor where S: value_bag_serde1::lib::Serializer, { inner: Option, result: Option>, } impl Serde1Visitor where S: value_bag_serde1::lib::Serializer, { fn result(&self) -> Result<(), Error> { match self.result { Some(Ok(_)) => Ok(()), Some(Err(ref e)) => Err(Error::serde(e)), None => Err(Error::msg("`serde` serialization didn't produce a result")), } } fn serializer(&mut self) -> Result { self.inner .take() .ok_or_else(|| Error::msg("`serde` serializer is in an invalid state")) } fn into_result(self) -> Result { self.result.unwrap_or_else(|| { Err(S::Error::custom( "`serde` serialization didn't produce a result", )) }) } } impl<'v, S> InternalVisitor<'v> for Serde1Visitor where S: value_bag_serde1::lib::Serializer, { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(Slot::new(self)) } fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error> { struct DebugToDisplay(T); impl fmt::Display for DebugToDisplay where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) } } self.result = Some(self.serializer()?.collect_str(&DebugToDisplay(v))); self.result() } fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error> { self.result = Some(self.serializer()?.collect_str(v)); self.result() } fn u64(&mut self, v: u64) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_u64(v)); self.result() } fn i64(&mut self, v: i64) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_i64(v)); self.result() } fn u128(&mut self, v: &u128) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_u128(*v)); self.result() } fn i128(&mut self, v: &i128) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_i128(*v)); self.result() } fn f64(&mut self, v: f64) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_f64(v)); self.result() } fn bool(&mut self, v: bool) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_bool(v)); self.result() } fn char(&mut self, v: char) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_char(v)); self.result() } fn str(&mut self, v: &str) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_str(v)); self.result() } fn none(&mut self) -> Result<(), Error> { self.result = Some(self.serializer()?.serialize_none()); self.result() } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn std::error::Error + 'static)) -> Result<(), Error> { self.result = Some(self.serializer()?.collect_str(v)); self.result() } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> { self.result = Some(crate::internal::sval::v2::serde1(self.serializer()?, v)); self.result() } fn serde1(&mut self, v: &dyn Serialize) -> Result<(), Error> { self.result = Some(value_bag_serde1::erased::serialize(v, self.serializer()?)); self.result() } #[cfg(feature = "seq")] fn seq(&mut self, v: &dyn crate::internal::seq::Seq) -> Result<(), Error> { self.result = Some(serialize_seq(self.serializer()?, v)); self.result() } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { self.result = Some(Err(S::Error::custom(msg))); self.result() } } let mut visitor = Serde1Visitor { inner: Some(s), result: None, }; self.internal_visit(&mut visitor) .map_err(S::Error::custom)?; visitor.into_result() } } pub use value_bag_serde1::erased::Serialize; pub(in crate::internal) fn fmt(f: &mut fmt::Formatter, v: &dyn Serialize) -> Result<(), Error> { fmt::Debug::fmt(&value_bag_serde1::fmt::to_debug(v), f)?; Ok(()) } #[cfg(feature = "sval2")] pub(in crate::internal) fn sval2<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( s: &mut S, v: &dyn Serialize, ) -> Result<(), Error> { value_bag_sval2::serde1::stream(s, v).map_err(Error::from_sval2) } #[cfg(feature = "seq")] fn serialize_seq( s: S, seq: &dyn crate::internal::seq::Seq, ) -> Result { use crate::std::ops::ControlFlow; use value_bag_serde1::lib::ser::SerializeSeq; struct SerializeVisitor { serializer: S, err: Option, } impl<'v, S: SerializeSeq> crate::internal::seq::Visitor<'v> for SerializeVisitor { fn element(&mut self, v: ValueBag) -> ControlFlow<()> { match self.serializer.serialize_element(&v) { Ok(()) => ControlFlow::Continue(()), Err(e) => { self.err = Some(e); ControlFlow::Break(()) } } } } let mut s = SerializeVisitor { serializer: s.serialize_seq(None)?, err: None, }; seq.visit(&mut s); if let Some(e) = s.err { return Err(e); } s.serializer.end() } pub(crate) fn internal_visit(v: &dyn Serialize, visitor: &mut dyn InternalVisitor<'_>) -> bool { struct VisitorSerializer<'a, 'v>(&'a mut dyn InternalVisitor<'v>); impl<'a, 'v> value_bag_serde1::lib::Serializer for VisitorSerializer<'a, 'v> { type Ok = (); type Error = Unsupported; type SerializeSeq = Impossible; type SerializeTuple = Impossible; type SerializeTupleStruct = Impossible; type SerializeTupleVariant = Impossible; type SerializeMap = Impossible; type SerializeStruct = Impossible; type SerializeStructVariant = Impossible; fn serialize_u8(self, v: u8) -> Result { self.0.u64(v as u64).map_err(|_| Unsupported) } fn serialize_u16(self, v: u16) -> Result { self.0.u64(v as u64).map_err(|_| Unsupported) } fn serialize_u32(self, v: u32) -> Result { self.0.u64(v as u64).map_err(|_| Unsupported) } fn serialize_u64(self, v: u64) -> Result { self.0.u64(v).map_err(|_| Unsupported) } fn serialize_u128(self, v: u128) -> Result { self.0.u128(&v).map_err(|_| Unsupported) } fn serialize_i8(self, v: i8) -> Result { self.0.i64(v as i64).map_err(|_| Unsupported) } fn serialize_i16(self, v: i16) -> Result { self.0.i64(v as i64).map_err(|_| Unsupported) } fn serialize_i32(self, v: i32) -> Result { self.0.i64(v as i64).map_err(|_| Unsupported) } fn serialize_i64(self, v: i64) -> Result { self.0.i64(v).map_err(|_| Unsupported) } fn serialize_i128(self, v: i128) -> Result { self.0.i128(&v).map_err(|_| Unsupported) } fn serialize_f32(self, v: f32) -> Result { self.0.f64(v as f64).map_err(|_| Unsupported) } fn serialize_f64(self, v: f64) -> Result { self.0.f64(v).map_err(|_| Unsupported) } fn serialize_char(self, v: char) -> Result { self.0.char(v).map_err(|_| Unsupported) } fn serialize_bool(self, v: bool) -> Result { self.0.bool(v).map_err(|_| Unsupported) } fn serialize_some(self, v: &T) -> Result where T: value_bag_serde1::lib::Serialize + ?Sized, { v.serialize(self) } fn serialize_unit(self) -> Result { self.0.none().map_err(|_| Unsupported) } fn serialize_none(self) -> Result { self.0.none().map_err(|_| Unsupported) } fn serialize_bytes(self, _: &[u8]) -> Result { Err(Unsupported) } fn serialize_str(self, s: &str) -> Result { self.0.str(s).map_err(|_| Unsupported) } fn serialize_unit_struct(self, _: &'static str) -> Result { Err(Unsupported) } fn serialize_unit_variant( self, _: &'static str, _: u32, _: &'static str, ) -> Result { Err(Unsupported) } fn serialize_newtype_struct( self, _: &'static str, _: &T, ) -> Result where T: value_bag_serde1::lib::Serialize + ?Sized, { Err(Unsupported) } fn serialize_newtype_variant( self, _: &'static str, _: u32, _: &'static str, _: &T, ) -> Result where T: value_bag_serde1::lib::Serialize + ?Sized, { Err(Unsupported) } fn serialize_seq( self, _: core::option::Option, ) -> Result { Err(Unsupported) } fn serialize_tuple(self, _: usize) -> Result { Err(Unsupported) } fn serialize_tuple_struct( self, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } fn serialize_tuple_variant( self, _: &'static str, _: u32, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } fn serialize_map( self, _: core::option::Option, ) -> Result { Err(Unsupported) } fn serialize_struct( self, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } fn serialize_struct_variant( self, _: &'static str, _: u32, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } } value_bag_serde1::erased::serialize(v, VisitorSerializer(visitor)).is_ok() } impl Error { fn serde(e: impl fmt::Display) -> Self { Error::try_boxed("`serde` serialization failed", e) } } #[derive(Debug)] struct Unsupported; impl fmt::Display for Unsupported { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "invalid cast") } } impl value_bag_serde1::lib::ser::Error for Unsupported { fn custom(_: T) -> Self where T: fmt::Display, { Unsupported } } impl value_bag_serde1::lib::ser::StdError for Unsupported {} #[cfg(feature = "seq")] pub(crate) mod seq { use super::*; use crate::internal::seq::ExtendValue; #[inline] pub(crate) fn extend<'a, S: Default + ExtendValue<'a>>(v: &dyn Serialize) -> Option { use crate::std::marker::PhantomData; struct Root(PhantomData); struct Seq(S); impl<'a, S: Default + ExtendValue<'a>> value_bag_serde1::lib::Serializer for Root { type Ok = S; type Error = Unsupported; type SerializeSeq = Seq; type SerializeTuple = Seq; type SerializeTupleStruct = value_bag_serde1::lib::ser::Impossible; type SerializeTupleVariant = value_bag_serde1::lib::ser::Impossible; type SerializeMap = value_bag_serde1::lib::ser::Impossible; type SerializeStruct = value_bag_serde1::lib::ser::Impossible; type SerializeStructVariant = value_bag_serde1::lib::ser::Impossible; fn serialize_bool(self, _: bool) -> Result { Err(Unsupported) } fn serialize_i8(self, _: i8) -> Result { Err(Unsupported) } fn serialize_i16(self, _: i16) -> Result { Err(Unsupported) } fn serialize_i32(self, _: i32) -> Result { Err(Unsupported) } fn serialize_i64(self, _: i64) -> Result { Err(Unsupported) } fn serialize_u8(self, _: u8) -> Result { Err(Unsupported) } fn serialize_u16(self, _: u16) -> Result { Err(Unsupported) } fn serialize_u32(self, _: u32) -> Result { Err(Unsupported) } fn serialize_u64(self, _: u64) -> Result { Err(Unsupported) } fn serialize_f32(self, _: f32) -> Result { Err(Unsupported) } fn serialize_f64(self, _: f64) -> Result { Err(Unsupported) } fn serialize_char(self, _: char) -> Result { Err(Unsupported) } fn serialize_str(self, _: &str) -> Result { Err(Unsupported) } fn serialize_bytes(self, _: &[u8]) -> Result { Err(Unsupported) } fn serialize_none(self) -> Result { Err(Unsupported) } fn serialize_some( self, value: &T, ) -> Result { value.serialize(self) } fn serialize_unit(self) -> Result { Err(Unsupported) } fn serialize_unit_struct(self, _: &'static str) -> Result { Err(Unsupported) } fn serialize_unit_variant( self, _: &'static str, _: u32, _: &'static str, ) -> Result { Err(Unsupported) } fn serialize_newtype_struct( self, _: &'static str, _: &T, ) -> Result { Err(Unsupported) } fn serialize_newtype_variant( self, _: &'static str, _: u32, _: &'static str, _: &T, ) -> Result { Err(Unsupported) } fn serialize_seq(self, _: Option) -> Result { Ok(Seq(S::default())) } fn serialize_tuple(self, len: usize) -> Result { self.serialize_seq(Some(len)) } fn serialize_tuple_struct( self, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } fn serialize_tuple_variant( self, _: &'static str, _: u32, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } fn serialize_map(self, _: Option) -> Result { Err(Unsupported) } fn serialize_struct( self, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } fn serialize_struct_variant( self, _: &'static str, _: u32, _: &'static str, _: usize, ) -> Result { Err(Unsupported) } } impl<'a, S: ExtendValue<'a>> value_bag_serde1::lib::ser::SerializeSeq for Seq { type Ok = S; type Error = Unsupported; fn serialize_element( &mut self, value: &T, ) -> Result<(), Self::Error> { self.0.extend(Internal::AnonSerde1(&value)); Ok(()) } fn end(self) -> Result { Ok(self.0) } } impl<'a, S: ExtendValue<'a>> value_bag_serde1::lib::ser::SerializeTuple for Seq { type Ok = S; type Error = Unsupported; fn serialize_element( &mut self, value: &T, ) -> Result<(), Self::Error> { value_bag_serde1::lib::ser::SerializeSeq::serialize_element(self, value) } fn end(self) -> Result { value_bag_serde1::lib::ser::SerializeSeq::end(self) } } value_bag_serde1::lib::Serialize::serialize(v, Root::(Default::default())).ok() } } #[cfg(feature = "owned")] pub(crate) mod owned { use crate::std::boxed::Box; impl value_bag_serde1::lib::Serialize for crate::OwnedValueBag { fn serialize(&self, s: S) -> Result where S: value_bag_serde1::lib::Serializer, { value_bag_serde1::lib::Serialize::serialize(&self.by_ref(), s) } } pub(crate) type OwnedSerialize = Box; pub(crate) fn buffer( v: impl value_bag_serde1::lib::Serialize, ) -> Result { value_bag_serde1::buf::Owned::buffer(v).map(Box::new) } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::test::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_capture() { assert_eq!( ValueBag::capture_serde1(&42u64).to_test_token(), TestToken::U64(42) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_fill() { assert_eq!( ValueBag::from_fill(&|slot: Slot| slot.fill_serde1(42u64)).to_test_token(), TestToken::Serde { version: 1 }, ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_capture_cast() { assert_eq!( 42u64, ValueBag::capture_serde1(&42u64) .to_u64() .expect("invalid value") ); assert_eq!( "a string", ValueBag::capture_serde1(&"a string") .to_borrowed_str() .expect("invalid value") ); #[cfg(feature = "std")] assert_eq!( "a string", ValueBag::capture_serde1(&"a string") .to_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_from_cast() { assert_eq!( 42u64, ValueBag::from_serde1(&42u64) .to_u64() .expect("invalid value") ); #[cfg(feature = "std")] assert_eq!( "a string", ValueBag::from_serde1(&"a string") .to_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_downcast() { #[derive(Debug, PartialEq, Eq)] struct Timestamp(usize); impl value_bag_serde1::lib::Serialize for Timestamp { fn serialize(&self, s: S) -> Result where S: value_bag_serde1::lib::Serializer, { s.serialize_u64(self.0 as u64) } } let ts = Timestamp(42); assert_eq!( &ts, ValueBag::capture_serde1(&ts) .downcast_ref::() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_structured() { use value_bag_serde1::test::{assert_ser_tokens, Token}; assert_ser_tokens(&ValueBag::from(42u64), &[Token::U64(42)]); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_debug() { struct TestSerde; impl value_bag_serde1::lib::Serialize for TestSerde { fn serialize(&self, s: S) -> Result where S: value_bag_serde1::lib::Serializer, { s.serialize_u64(42) } } assert_eq!( format!("{:04?}", 42u64), format!("{:04?}", ValueBag::capture_serde1(&TestSerde)), ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_visit() { ValueBag::from_serde1(&42u64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_serde1(&-42i64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_serde1(&11f64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_serde1(&true) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_serde1(&"some string") .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_serde1(&'n') .visit(TestVisit::default()) .expect("failed to visit value"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(feature = "sval2")] fn serde1_sval2() { use value_bag_sval2::test::Token; struct TestSerde; impl value_bag_serde1::lib::Serialize for TestSerde { fn serialize(&self, s: S) -> Result where S: value_bag_serde1::lib::Serializer, { s.serialize_u64(42) } } let value = ValueBag::from_serde1(&TestSerde); value_bag_sval2::test::assert_tokens(&value, &[Token::U64(42)]); } #[cfg(feature = "seq")] mod seq_support { use super::*; use crate::std::vec::Vec; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_stream_str_seq() { use value_bag_serde1::test::{assert_ser_tokens, Token}; assert_ser_tokens( &ValueBag::from_seq_slice(&["a", "b", "c"]), &[ Token::Seq { len: None }, Token::Str("a"), Token::Str("b"), Token::Str("c"), Token::SeqEnd, ], ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_to_seq() { assert_eq!( vec![Some(1.0), None, Some(2.0), Some(3.0), None], ValueBag::capture_serde1(&[ &1.0 as &dyn Serialize, &true as &dyn Serialize, &2.0 as &dyn Serialize, &3.0 as &dyn Serialize, &"a string" as &dyn Serialize, ]) .to_f64_seq::>>() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_as_seq() { assert_eq!( vec![1.0, 2.0, 3.0], ValueBag::capture_serde1(&[1.0, 2.0, 3.0,]).as_f64_seq::>() ); } } #[cfg(feature = "std")] mod std_support { use super::*; use crate::std::borrow::ToOwned; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_cast() { assert_eq!( "a string", ValueBag::capture_serde1(&"a string".to_owned()) .by_ref() .to_str() .expect("invalid value") ); } } #[cfg(feature = "owned")] mod owned_support { use super::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_to_owned_poison() { struct Kaboom; impl value_bag_serde1::lib::Serialize for Kaboom { fn serialize(&self, _: S) -> Result where S: value_bag_serde1::lib::Serializer, { Err(S::Error::custom("kaboom")) } } let value = ValueBag::capture_serde1(&Kaboom) .to_owned() .by_ref() .to_test_token(); assert_eq!( TestToken::Poisoned("failed to buffer the value".into()), value ); } } } value-bag-1.9.0/src/internal/sval/mod.rs000064400000000000000000000000231046102023000161660ustar 00000000000000pub(crate) mod v2; value-bag-1.9.0/src/internal/sval/v2.rs000064400000000000000000000675331046102023000157610ustar 00000000000000//! Integration between `Value` and `sval`. //! //! This module allows any `Value` to implement the `Value` trait, //! and for any `Value` to be captured as a `Value`. use crate::{ fill::Slot, internal::{Internal, InternalVisitor}, std::{any::Any, fmt}, Error, ValueBag, }; impl<'v> ValueBag<'v> { /// Get a value from a structured type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Value` implementation. pub fn capture_sval2(value: &'v T) -> Self where T: value_bag_sval2::lib::Value + 'static, { Self::try_capture(value).unwrap_or(ValueBag { inner: Internal::Sval2(value), }) } /// Get a value from a structured type without capturing support. pub const fn from_sval2(value: &'v T) -> Self where T: value_bag_sval2::lib::Value, { ValueBag { inner: Internal::AnonSval2(value), } } /// Get a value from a structured type without capturing support. #[inline] pub const fn from_dyn_sval2(value: &'v dyn Value) -> Self { ValueBag { inner: Internal::AnonSval2(value), } } } pub(crate) trait DowncastValue { fn as_any(&self) -> &dyn Any; fn as_super(&self) -> &dyn Value; } impl DowncastValue for T { fn as_any(&self) -> &dyn Any { self } fn as_super(&self) -> &dyn Value { self } } impl<'s, 'f> Slot<'s, 'f> { /// Fill the slot with a structured value. /// /// The given value doesn't need to satisfy any particular lifetime constraints. pub fn fill_sval2(self, value: T) -> Result<(), Error> where T: value_bag_sval2::lib::Value, { self.fill(|visitor| visitor.sval2(&value)) } } impl<'v> value_bag_sval2::lib::Value for ValueBag<'v> { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, s: &mut S, ) -> value_bag_sval2::lib::Result { use value_bag_sval2::lib_ref::ValueRef as _; self.stream_ref(s) } } impl<'sval> value_bag_sval2::lib_ref::ValueRef<'sval> for ValueBag<'sval> { fn stream_ref + ?Sized>( &self, s: &mut S, ) -> value_bag_sval2::lib::Result { struct Sval2Visitor<'a, S: ?Sized>(&'a mut S); impl<'a, 'v, S: value_bag_sval2::lib::Stream<'v> + ?Sized> InternalVisitor<'v> for Sval2Visitor<'a, S> { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error> { value_bag_sval2::fmt::stream_debug(self.0, v).map_err(Error::from_sval2) } fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error> { value_bag_sval2::fmt::stream_display(self.0, v).map_err(Error::from_sval2) } fn u64(&mut self, v: u64) -> Result<(), Error> { self.0.u64(v).map_err(Error::from_sval2) } fn i64(&mut self, v: i64) -> Result<(), Error> { self.0.i64(v).map_err(Error::from_sval2) } fn u128(&mut self, v: &u128) -> Result<(), Error> { self.0.u128(*v).map_err(Error::from_sval2) } fn i128(&mut self, v: &i128) -> Result<(), Error> { self.0.i128(*v).map_err(Error::from_sval2) } fn f64(&mut self, v: f64) -> Result<(), Error> { self.0.f64(v).map_err(Error::from_sval2) } fn bool(&mut self, v: bool) -> Result<(), Error> { self.0.bool(v).map_err(Error::from_sval2) } fn char(&mut self, v: char) -> Result<(), Error> { let mut buf = [0; 4]; let v = v.encode_utf8(&mut buf); self.0.value_computed(v).map_err(Error::from_sval2) } fn str(&mut self, v: &str) -> Result<(), Error> { self.0.value_computed(v).map_err(Error::from_sval2) } fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { self.0.value(v).map_err(Error::from_sval2) } fn none(&mut self) -> Result<(), Error> { self.0.null().map_err(Error::from_sval2) } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn std::error::Error + 'static)) -> Result<(), Error> { self.display(&v) } fn sval2(&mut self, v: &dyn Value) -> Result<(), Error> { self.0.value_computed(v).map_err(Error::from_sval2) } fn borrowed_sval2(&mut self, v: &'v dyn Value) -> Result<(), Error> { self.0.value(v).map_err(Error::from_sval2) } #[cfg(feature = "serde1")] fn serde1( &mut self, v: &dyn crate::internal::serde::v1::Serialize, ) -> Result<(), Error> { crate::internal::serde::v1::sval2(self.0, v) } #[cfg(feature = "seq")] fn seq(&mut self, v: &dyn crate::internal::seq::Seq) -> Result<(), Error> { self.0.seq_begin(None).map_err(Error::from_sval2)?; let mut s = seq::StreamVisitor { stream: &mut *self.0, err: None, }; v.visit(&mut s); if let Some(e) = s.err { return Err(Error::from_sval2(e)); } self.0.seq_end().map_err(Error::from_sval2) } #[cfg(feature = "seq")] fn borrowed_seq(&mut self, v: &'v dyn crate::internal::seq::Seq) -> Result<(), Error> { self.0.seq_begin(None).map_err(Error::from_sval2)?; let mut s = seq::StreamVisitor { stream: &mut *self.0, err: None, }; v.borrowed_visit(&mut s); if let Some(e) = s.err { return Err(Error::from_sval2(e)); } self.0.seq_end().map_err(Error::from_sval2) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { Err(Error::msg(msg)) } } self.internal_visit(&mut Sval2Visitor(s)) .map_err(Error::into_sval2)?; Ok(()) } } pub use value_bag_sval2::dynamic::Value; pub(in crate::internal) fn fmt(f: &mut fmt::Formatter, v: &dyn Value) -> Result<(), Error> { value_bag_sval2::fmt::stream_to_fmt(f, v)?; Ok(()) } #[cfg(feature = "serde1")] pub(in crate::internal) fn serde1(s: S, v: &dyn Value) -> Result where S: value_bag_serde1::lib::Serializer, { value_bag_sval2::serde1::serialize(s, v) } pub(crate) fn internal_visit(v: &dyn Value, visitor: &mut dyn InternalVisitor<'_>) -> bool { let mut visitor = VisitorStream { visitor, text_buf: Default::default(), }; value_bag_sval2::lib::stream_computed(&mut visitor, v).is_ok() } pub(crate) fn borrowed_internal_visit<'v>( v: &'v dyn Value, visitor: &mut dyn InternalVisitor<'v>, ) -> bool { let mut visitor = VisitorStream { visitor, text_buf: Default::default(), }; value_bag_sval2::lib::stream(&mut visitor, v).is_ok() } struct VisitorStream<'a, 'v> { visitor: &'a mut dyn InternalVisitor<'v>, text_buf: value_bag_sval2::buffer::TextBuf<'v>, } impl<'a, 'v> value_bag_sval2::lib::Stream<'v> for VisitorStream<'a, 'v> { fn null(&mut self) -> value_bag_sval2::lib::Result { self.visitor.none().map_err(Error::into_sval2) } fn bool(&mut self, v: bool) -> value_bag_sval2::lib::Result { self.visitor.bool(v).map_err(Error::into_sval2) } fn i64(&mut self, v: i64) -> value_bag_sval2::lib::Result { self.visitor.i64(v).map_err(Error::into_sval2) } fn u64(&mut self, v: u64) -> value_bag_sval2::lib::Result { self.visitor.u64(v).map_err(Error::into_sval2) } fn i128(&mut self, v: i128) -> value_bag_sval2::lib::Result { self.visitor.i128(&v).map_err(Error::into_sval2) } fn u128(&mut self, v: u128) -> value_bag_sval2::lib::Result { self.visitor.u128(&v).map_err(Error::into_sval2) } fn f64(&mut self, v: f64) -> value_bag_sval2::lib::Result { self.visitor.f64(v).map_err(Error::into_sval2) } fn text_begin(&mut self, _: Option) -> value_bag_sval2::lib::Result { self.text_buf.clear(); Ok(()) } fn text_fragment_computed(&mut self, f: &str) -> value_bag_sval2::lib::Result { self.text_buf .push_fragment_computed(f) .map_err(|_| value_bag_sval2::lib::Error::new()) } fn text_fragment(&mut self, f: &'v str) -> value_bag_sval2::lib::Result { self.text_buf .push_fragment(f) .map_err(|_| value_bag_sval2::lib::Error::new()) } fn text_end(&mut self) -> value_bag_sval2::lib::Result { if let Some(v) = self.text_buf.as_borrowed_str() { self.visitor.borrowed_str(v).map_err(Error::into_sval2) } else { self.visitor .str(self.text_buf.as_str()) .map_err(Error::into_sval2) } } fn seq_begin(&mut self, _: Option) -> value_bag_sval2::lib::Result { value_bag_sval2::lib::error() } fn seq_value_begin(&mut self) -> value_bag_sval2::lib::Result { value_bag_sval2::lib::error() } fn seq_value_end(&mut self) -> value_bag_sval2::lib::Result { value_bag_sval2::lib::error() } fn seq_end(&mut self) -> value_bag_sval2::lib::Result { value_bag_sval2::lib::error() } } impl Error { pub(in crate::internal) fn from_sval2(_: value_bag_sval2::lib::Error) -> Self { Error::msg("`sval` serialization failed") } pub(in crate::internal) fn into_sval2(self) -> value_bag_sval2::lib::Error { value_bag_sval2::lib::Error::new() } } #[cfg(feature = "seq")] pub(crate) mod seq { use super::*; use crate::{ internal::seq::{ExtendValue, Visitor}, std::ops::ControlFlow, }; pub(super) struct StreamVisitor<'a, S: ?Sized> { pub(super) stream: &'a mut S, pub(super) err: Option, } impl<'a, 'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized> Visitor<'sval> for StreamVisitor<'a, S> { fn element(&mut self, v: ValueBag) -> ControlFlow<()> { if let Err(e) = self.stream.seq_value_begin() { self.err = Some(e); return ControlFlow::Break(()); } if let Err(e) = value_bag_sval2::lib::stream_computed(&mut *self.stream, v) { self.err = Some(e); return ControlFlow::Break(()); } if let Err(e) = self.stream.seq_value_end() { self.err = Some(e); return ControlFlow::Break(()); } ControlFlow::Continue(()) } fn borrowed_element(&mut self, v: ValueBag<'sval>) -> ControlFlow<()> { if let Err(e) = self.stream.seq_value_begin() { self.err = Some(e); return ControlFlow::Break(()); } if let Err(e) = value_bag_sval2::lib_ref::stream_ref(&mut *self.stream, v) { self.err = Some(e); return ControlFlow::Break(()); } if let Err(e) = self.stream.seq_value_end() { self.err = Some(e); return ControlFlow::Break(()); } ControlFlow::Continue(()) } } #[inline] pub(crate) fn extend<'a, 'b, S: Default + ExtendValue<'a>>(v: &'b dyn Value) -> Option { let mut stream = Root { seq: None, text_buf: Default::default(), depth: 0, }; value_bag_sval2::lib::stream_computed(&mut stream, v).ok()?; stream.seq } #[inline] pub(crate) fn extend_borrowed<'a, S: Default + ExtendValue<'a>>(v: &'a dyn Value) -> Option { let mut stream = Root { seq: None, text_buf: Default::default(), depth: 0, }; value_bag_sval2::lib::stream(&mut stream, v).ok()?; stream.seq } struct Root<'v, S> { seq: Option, text_buf: value_bag_sval2::buffer::TextBuf<'v>, depth: usize, } fn extend_borrowed_internal<'sval>( seq: Option<&mut impl ExtendValue<'sval>>, depth: usize, v: impl Into>, ) -> value_bag_sval2::lib::Result { if depth != 1 { return Ok(()); } if let Some(seq) = seq { seq.extend_borrowed(v.into().inner); Ok(()) } else { value_bag_sval2::lib::error() } } fn extend_internal<'a, 'sval>( seq: Option<&mut impl ExtendValue<'sval>>, depth: usize, v: impl Into>, ) -> value_bag_sval2::lib::Result { if depth != 1 { return Ok(()); } if let Some(seq) = seq { seq.extend(v.into().inner); Ok(()) } else { value_bag_sval2::lib::error() } } impl<'sval, S: Default + ExtendValue<'sval>> value_bag_sval2::lib::Stream<'sval> for Root<'sval, S> { fn null(&mut self) -> value_bag_sval2::lib::Result { extend_borrowed_internal(self.seq.as_mut(), self.depth, ()) } fn bool(&mut self, v: bool) -> value_bag_sval2::lib::Result { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } fn i64(&mut self, v: i64) -> value_bag_sval2::lib::Result { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } fn u64(&mut self, v: u64) -> value_bag_sval2::lib::Result { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } fn i128(&mut self, v: i128) -> value_bag_sval2::lib::Result { #[cfg(feature = "inline-i128")] { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } #[cfg(not(feature = "inline-i128"))] { extend_internal(self.seq.as_mut(), self.depth, &v) } } fn u128(&mut self, v: u128) -> value_bag_sval2::lib::Result { #[cfg(feature = "inline-i128")] { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } #[cfg(not(feature = "inline-i128"))] { extend_internal(self.seq.as_mut(), self.depth, &v) } } fn f64(&mut self, v: f64) -> value_bag_sval2::lib::Result { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } fn text_begin(&mut self, _: Option) -> value_bag_sval2::lib::Result { self.text_buf.clear(); Ok(()) } fn text_fragment_computed(&mut self, f: &str) -> value_bag_sval2::lib::Result { self.text_buf .push_fragment_computed(f) .map_err(|_| value_bag_sval2::lib::Error::new()) } fn text_fragment(&mut self, f: &'sval str) -> value_bag_sval2::lib::Result { self.text_buf .push_fragment(f) .map_err(|_| value_bag_sval2::lib::Error::new()) } fn text_end(&mut self) -> value_bag_sval2::lib::Result { if let Some(v) = self.text_buf.as_borrowed_str() { extend_borrowed_internal(self.seq.as_mut(), self.depth, v) } else { let v = self.text_buf.as_str(); extend_internal(self.seq.as_mut(), self.depth, v) } } fn seq_begin(&mut self, _: Option) -> value_bag_sval2::lib::Result { if self.seq.is_none() { self.seq = Some(S::default()); } self.depth += 1; // Treat nested complex values as null // This ensures an upstream visitor sees them, but won't // be able to convert them into anything meaningful if self.depth > 1 { if let Some(ref mut seq) = self.seq { seq.extend_borrowed(ValueBag::from(()).inner); } } Ok(()) } fn seq_value_begin(&mut self) -> value_bag_sval2::lib::Result { Ok(()) } fn seq_value_end(&mut self) -> value_bag_sval2::lib::Result { Ok(()) } fn seq_end(&mut self) -> value_bag_sval2::lib::Result { self.depth -= 1; Ok(()) } } } #[cfg(feature = "owned")] pub(crate) mod owned { impl value_bag_sval2::lib::Value for crate::OwnedValueBag { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, s: &mut S, ) -> value_bag_sval2::lib::Result { value_bag_sval2::lib_ref::ValueRef::stream_ref(&self.by_ref(), s) } } pub(crate) type OwnedValue = value_bag_sval2::buffer::Value<'static>; pub(crate) fn buffer( v: impl value_bag_sval2::lib::Value, ) -> Result { OwnedValue::collect_owned(v) } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::test::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_capture() { assert_eq!( ValueBag::capture_sval2(&42u64).to_test_token(), TestToken::U64(42) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_fill() { assert_eq!( ValueBag::from_fill(&|slot: Slot| slot.fill_sval2(42u64)).to_test_token(), TestToken::Sval { version: 2 }, ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_capture_cast() { assert_eq!( 42u64, ValueBag::capture_sval2(&42u64) .to_u64() .expect("invalid value") ); assert_eq!( "a string", ValueBag::capture_sval2(&"a string") .to_borrowed_str() .expect("invalid value") ); #[cfg(feature = "std")] assert_eq!( "a string", ValueBag::capture_sval2(&"a string") .to_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_capture_cast_borrowed_str() { struct Number<'a>(&'a str); impl<'a> value_bag_sval2::lib::Value for Number<'a> { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> value_bag_sval2::lib::Result { stream.tagged_begin(Some(&value_bag_sval2::lib::tags::NUMBER), None, None)?; stream.value(self.0)?; stream.tagged_end(Some(&value_bag_sval2::lib::tags::NUMBER), None, None) } } assert_eq!( "123.456e789", ValueBag::capture_sval2(&Number("123.456e789")) .to_borrowed_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_from_cast() { assert_eq!( 42u64, ValueBag::from_sval2(&42u64) .to_u64() .expect("invalid value") ); #[cfg(feature = "std")] assert_eq!( "a string", ValueBag::from_sval2(&"a string") .to_str() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_downcast() { #[derive(Debug, PartialEq, Eq)] struct Timestamp(usize); impl value_bag_sval2::lib::Value for Timestamp { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> value_bag_sval2::lib::Result { stream.u64(self.0 as u64) } } let ts = Timestamp(42); assert_eq!( &ts, ValueBag::capture_sval2(&ts) .downcast_ref::() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_structured() { let value = ValueBag::from(42u64); value_bag_sval2::test::assert_tokens(&value, &[value_bag_sval2::test::Token::U64(42)]); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_debug() { struct TestSval; impl value_bag_sval2::lib::Value for TestSval { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> value_bag_sval2::lib::Result { stream.u64(42) } } assert_eq!( format!("{:04?}", 42u64), format!("{:04?}", ValueBag::capture_sval2(&TestSval)), ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_visit() { ValueBag::from_sval2(&42u64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_sval2(&-42i64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_sval2(&11f64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_sval2(&true) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_sval2(&"some borrowed string") .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from_sval2(&'n') .visit(TestVisit { str: "n", ..Default::default() }) .expect("failed to visit value"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(feature = "serde1")] fn sval2_serde1() { use value_bag_serde1::test::{assert_ser_tokens, Token}; struct TestSval; impl value_bag_sval2::lib::Value for TestSval { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> value_bag_sval2::lib::Result { stream.u64(42) } } assert_ser_tokens(&ValueBag::capture_sval2(&TestSval), &[Token::U64(42)]); } #[cfg(feature = "seq")] mod seq_support { use super::*; use crate::std::vec::Vec; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_stream_borrowed_str_seq() { let value = ValueBag::from_seq_slice(&["a", "b", "c"]); value_bag_sval2::test::assert_tokens(&value, { use value_bag_sval2::test::Token::*; &[ SeqBegin(None), SeqValueBegin, TextBegin(Some(1)), TextFragment("a"), TextEnd, SeqValueEnd, SeqValueBegin, TextBegin(Some(1)), TextFragment("b"), TextEnd, SeqValueEnd, SeqValueBegin, TextBegin(Some(1)), TextFragment("c"), TextEnd, SeqValueEnd, SeqEnd, ] }); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_stream_str_seq() { let value = ValueBag::from_fill(&|slot: Slot| slot.fill_seq_slice(&["a", "b", "c"])); value_bag_sval2::test::assert_tokens(&value, { use value_bag_sval2::test::Token::*; &[ SeqBegin(None), SeqValueBegin, TextBegin(Some(1)), TextFragmentComputed("a".into()), TextEnd, SeqValueEnd, SeqValueBegin, TextBegin(Some(1)), TextFragmentComputed("b".into()), TextEnd, SeqValueEnd, SeqValueBegin, TextBegin(Some(1)), TextFragmentComputed("c".into()), TextEnd, SeqValueEnd, SeqEnd, ] }); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(feature = "alloc")] fn sval2_borrowed_str_to_seq() { use crate::std::borrow::Cow; assert_eq!( vec![ Some(Cow::Borrowed("a string 1")), Some(Cow::Borrowed("a string 2")), Some(Cow::Borrowed("a string 3")) ], ValueBag::capture_sval2(&[&"a string 1", &"a string 2", &"a string 3",]) .to_str_seq::>>>() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_to_seq() { assert_eq!( vec![Some(1.0), None, None, Some(2.0), Some(3.0), None], ValueBag::capture_sval2(&[ &1.0 as &dyn Value, &true as &dyn Value, &[1.0, 2.0, 3.0] as &dyn Value, &2.0 as &dyn Value, &3.0 as &dyn Value, &"a string" as &dyn Value, ]) .to_f64_seq::>>() .expect("invalid value") ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_as_seq() { assert_eq!( vec![1.0, 2.0, 3.0], ValueBag::capture_sval2(&[1.0, 2.0, 3.0,]).as_f64_seq::>() ); } } #[cfg(feature = "std")] mod std_support { use super::*; use crate::std::borrow::ToOwned; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_cast() { assert_eq!( "a string", ValueBag::capture_sval2(&"a string".to_owned()) .by_ref() .to_str() .expect("invalid value") ); } } #[cfg(feature = "owned")] mod owned_support { use super::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_to_owned_poison() { struct Kaboom; impl value_bag_sval2::lib::Value for Kaboom { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, _: &mut S, ) -> value_bag_sval2::lib::Result { value_bag_sval2::lib::error() } } let value = ValueBag::capture_sval2(&Kaboom) .to_owned() .by_ref() .to_test_token(); assert_eq!( TestToken::Poisoned("failed to buffer the value".into()), value ); } } } value-bag-1.9.0/src/lib.rs000064400000000000000000000466541046102023000134200ustar 00000000000000//! Structured values. //! //! This crate contains the [`ValueBag`] type, a container for an anonymous structured value. //! `ValueBag`s can be captured in various ways and then formatted, inspected, and serialized //! without losing their original structure. //! //! The producer of a [`ValueBag`] may use a different strategy for capturing than the eventual //! consumer. They don't need to coordinate directly. #![doc(html_root_url = "https://docs.rs/value-bag/1.9.0")] #![no_std] #![allow( clippy::unnecessary_fallible_conversions, clippy::explicit_auto_deref, clippy::wrong_self_convention )] /* # Crate design This library internally ties several frameworks together. The details of how this is done are hidden from end-users. It looks roughly like this: ┌─────┐ ┌──────┐ │sval2│ │serde1│ 1. libs on crates.io └──┬──┘ └─┬─┬──┘ ├──────────┘ │ ┌───────▼──┐ ┌───▼───────┐ │meta/sval2│ │meta/serde1│ 2. meta crates with features └───────┬──┘ └───┬───────┘ │ │ ┌─────────────▼──┐ ┌───▼─────────────┐ │internal/sval/v2◄─────┤internal/serde/v1│ 3. internal modules with `InternalVisitor` └─────────────┬──┘ └───┬─────────────┘ │ │ ┌──────▼────────┬───▼────────────┐ │Internal::Sval2│Internal::Serde1│ 4. variants in `Internal` enum └───────────────┼────────────────┘ │ ┌───────────────────────▼────────────────────────┐ │ValueBag::capture_sval2│ValueBag::capture_serde1│ 5. ctors on `ValueBag` └───────────────────────┼────────────────────────┘ │ ┌───────────────────────▼───────────────────────────┐ │impl Value for ValueBag│impl Serialize for ValueBag│ 6. trait impls on `ValueBag` └───────────────────────┴───────────────────────────┘ ## 1. libs on crates.io These are the frameworks like `serde` or `sval`. ## 2. meta crates with features These are crates that are internal to `value-bag`. They depend on the public framework and any utility crates that come along with it. They also expose features for any other framework. This is done this way so `value-bag` can use Cargo's `crate?/feature` syntax to conditionally add framework support. ## 3. internal modules with `InternalVisitor` These are modules in `value-bag` that integrate the framework using the `InternalVisitor` trait. This makes it possible for that framework to cast primitive values and pass-through any other framework. ## 4. variants in `Internal` enum These are individual variants on the `Internal` enum that the `ValueBag` type wraps. Each framework has one or more variants in this enum. ## 5. ctors on `ValueBag` These are constructors for producers of `ValueBag`s that accept a value implementing a serialization trait from a specific framework, like `serde::Serialize` or `sval::Value`. ## 7. trait impls on `ValueBag` These are trait impls for consumers of `ValueBag`s that serialize the underlying value, bridging it if it was produced for a different framework. */ #[cfg(any(feature = "std", test))] #[macro_use] #[allow(unused_imports)] extern crate std; #[cfg(all(not(test), feature = "alloc", not(feature = "std")))] #[macro_use] #[allow(unused_imports)] extern crate core; #[cfg(all(not(test), feature = "alloc", not(feature = "std")))] #[macro_use] #[allow(unused_imports)] extern crate alloc; #[cfg(all(not(test), feature = "alloc", not(feature = "std")))] #[allow(unused_imports)] mod std { pub use crate::{ alloc::{borrow, boxed, string, vec}, core::*, }; #[cfg(feature = "owned")] pub use crate::alloc::sync; } #[cfg(not(any(feature = "alloc", feature = "std", test)))] #[macro_use] #[allow(unused_imports)] extern crate core as std; mod error; pub mod fill; mod impls; mod internal; pub mod visit; #[cfg(any(test, feature = "test"))] pub mod test; #[cfg(feature = "owned")] mod owned; #[cfg(feature = "owned")] pub use self::owned::*; pub use self::error::Error; /// A dynamic structured value. /// /// # Capturing values /// /// There are a few ways to capture a value: /// /// - Using the `ValueBag::capture_*` and `ValueBag::from_*` methods. /// - Using the standard `From` trait. /// - Using the `Fill` API. /// /// ## Using the `ValueBag::capture_*` methods /// /// `ValueBag` offers a few constructor methods that capture values of different kinds. /// These methods require a `T: 'static` to support downcasting. /// /// ``` /// use value_bag::ValueBag; /// /// let value = ValueBag::capture_debug(&42i32); /// /// assert_eq!(Some(42), value.to_i64()); /// ``` /// /// Capturing a value using these methods will retain type information so that /// the contents of the bag can be serialized using an appropriate type. /// /// For cases where the `'static` bound can't be satisfied, there's also a few /// constructors that exclude it. /// /// ``` /// # use std::fmt::Debug; /// use value_bag::ValueBag; /// /// let value = ValueBag::from_debug(&42i32); /// /// assert_eq!(None, value.to_i64()); /// ``` /// /// These `ValueBag::from_*` methods are lossy though and `ValueBag::capture_*` should be preferred. /// /// ## Using the standard `From` trait /// /// Primitive types can be converted into a `ValueBag` using the standard `From` trait. /// /// ``` /// use value_bag::ValueBag; /// /// let value = ValueBag::from(42i32); /// /// assert_eq!(Some(42), value.to_i64()); /// ``` /// /// ## Using the `Fill` API /// /// The [`fill`] module provides a way to bridge APIs that may not be directly /// compatible with other constructor methods. /// /// The `Fill` trait is automatically implemented for closures, so can usually /// be used in libraries that can't implement the trait themselves. /// /// ``` /// use value_bag::{ValueBag, fill::Slot}; /// /// let value = ValueBag::from_fill(&|slot: Slot| { /// #[derive(Debug)] /// struct MyShortLivedValue; /// /// slot.fill_debug(&MyShortLivedValue) /// }); /// /// assert_eq!("MyShortLivedValue", format!("{:?}", value)); /// ``` /// /// The trait can also be implemented manually: /// /// ``` /// # use std::fmt::Debug; /// use value_bag::{ValueBag, Error, fill::{Slot, Fill}}; /// /// struct FillDebug; /// /// impl Fill for FillDebug { /// fn fill(&self, slot: Slot) -> Result<(), Error> { /// slot.fill_debug(&42i32 as &dyn Debug) /// } /// } /// /// let value = ValueBag::from_fill(&FillDebug); /// /// assert_eq!(None, value.to_i64()); /// ``` /// /// # Inspecting values /// /// Once you have a `ValueBag` there are also a few ways to inspect it: /// /// - Using `std::fmt` /// - Using `sval` /// - Using `serde` /// - Using the `ValueBag::visit` method. /// - Using the `ValueBag::to_*` methods. /// - Using the `ValueBag::downcast_ref` method. /// /// ## Using the `ValueBag::visit` method /// /// The [`visit`] module provides a simple visitor API that can be used to inspect /// the structure of primitives stored in a `ValueBag`. /// More complex datatypes can then be handled using `std::fmt`, `sval`, or `serde`. /// /// ``` /// #[cfg(not(feature = "std"))] fn main() {} /// #[cfg(feature = "std")] /// # fn main() -> Result<(), Box> { /// # fn escape(buf: &[u8]) -> &[u8] { buf } /// # fn itoa_fmt(num: T) -> Vec { vec![] } /// # fn ryu_fmt(num: T) -> Vec { vec![] } /// # use std::io::Write; /// use value_bag::{ValueBag, Error, visit::Visit}; /// /// // Implement some simple custom serialization /// struct MyVisit(Vec); /// impl<'v> Visit<'v> for MyVisit { /// fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> { /// // Fallback to `Debug` if we didn't visit the value specially /// write!(&mut self.0, "{:?}", v).map_err(|_| Error::msg("failed to write value")) /// } /// /// fn visit_u64(&mut self, v: u64) -> Result<(), Error> { /// self.0.extend_from_slice(itoa_fmt(v).as_slice()); /// Ok(()) /// } /// /// fn visit_i64(&mut self, v: i64) -> Result<(), Error> { /// self.0.extend_from_slice(itoa_fmt(v).as_slice()); /// Ok(()) /// } /// /// fn visit_f64(&mut self, v: f64) -> Result<(), Error> { /// self.0.extend_from_slice(ryu_fmt(v).as_slice()); /// Ok(()) /// } /// /// fn visit_str(&mut self, v: &str) -> Result<(), Error> { /// self.0.push(b'\"'); /// self.0.extend_from_slice(escape(v.as_bytes())); /// self.0.push(b'\"'); /// Ok(()) /// } /// /// fn visit_bool(&mut self, v: bool) -> Result<(), Error> { /// self.0.extend_from_slice(if v { b"true" } else { b"false" }); /// Ok(()) /// } /// } /// /// let value = ValueBag::from(42i64); /// /// let mut visitor = MyVisit(vec![]); /// value.visit(&mut visitor)?; /// # Ok(()) /// # } /// ``` /// /// ## Using `std::fmt` /// /// Any `ValueBag` can be formatted using the `std::fmt` machinery as either `Debug` /// or `Display`. /// /// ``` /// use value_bag::ValueBag; /// /// let value = ValueBag::from(true); /// /// assert_eq!("true", format!("{:?}", value)); /// ``` /// /// ## Using `sval` /// /// When the `sval2` feature is enabled, any `ValueBag` can be serialized using `sval`. /// This makes it possible to visit any typed structure captured in the `ValueBag`, /// including complex datatypes like maps and sequences. /// /// `sval` doesn't need to allocate so can be used in no-std environments. /// /// First, enable the `sval2` feature in your `Cargo.toml`: /// /// ```toml /// [dependencies.value-bag] /// features = ["sval2"] /// ``` /// /// Then stream the contents of the `ValueBag` using `sval`. /// /// ``` /// # #[cfg(not(all(feature = "std", feature = "sval2")))] fn main() {} /// # #[cfg(all(feature = "std", feature = "sval2"))] /// # fn main() -> Result<(), Box> { /// # use value_bag_sval2::json as sval_json; /// use value_bag::ValueBag; /// /// let value = ValueBag::from(42i64); /// let json = sval_json::stream_to_string(value)?; /// # Ok(()) /// # } /// ``` /// /// ## Using `serde` /// /// When the `serde1` feature is enabled, any `ValueBag` can be serialized using `serde`. /// This makes it possible to visit any typed structure captured in the `ValueBag`, /// including complex datatypes like maps and sequences. /// /// `serde` needs a few temporary allocations, so also brings in the `std` feature. /// /// First, enable the `serde1` feature in your `Cargo.toml`: /// /// ```toml /// [dependencies.value-bag] /// features = ["serde1"] /// ``` /// /// Then stream the contents of the `ValueBag` using `serde`. /// /// ``` /// # #[cfg(not(all(feature = "std", feature = "serde1")))] fn main() {} /// # #[cfg(all(feature = "std", feature = "serde1"))] /// # fn main() -> Result<(), Box> { /// # use value_bag_serde1::json as serde_json; /// use value_bag::ValueBag; /// /// let value = ValueBag::from(42i64); /// let json = serde_json::to_string(&value)?; /// # Ok(()) /// # } /// ``` /// /// Also see [`serde.rs`](https://serde.rs) for more examples of writing your own serializers. /// /// ## Using the `ValueBag::to_*` methods /// /// `ValueBag` provides a set of methods for attempting to pull a concrete value out. /// These are useful for ad-hoc analysis but aren't intended for exhaustively serializing /// the contents of a `ValueBag`. /// /// ``` /// use value_bag::ValueBag; /// /// let value = ValueBag::capture_display(&42u64); /// /// assert_eq!(Some(42u64), value.to_u64()); /// ``` /// /// ## Using the `ValueBag::downcast_ref` method /// /// When a `ValueBag` is created using one of the `capture_*` constructors, it can be downcast /// back to its original value. /// This can also be useful for ad-hoc analysis where there's a common possible non-primitive /// type that could be captured. /// /// ``` /// # #[derive(Debug)] struct SystemTime; /// # fn now() -> SystemTime { SystemTime } /// use value_bag::ValueBag; /// /// let timestamp = now(); /// let value = ValueBag::capture_debug(×tamp); /// /// assert!(value.downcast_ref::().is_some()); /// ``` /// /// # Working with sequences /// /// The `seq` feature of `value-bag` enables utilities for working with values that are sequences. /// First, enable the `seq` feature in your `Cargo.toml`: /// /// ```toml /// [dependencies.value-bag] /// features = ["seq"] /// ``` /// /// Slices and arrays can be captured as sequences: /// /// ``` /// # #[cfg(not(all(feature = "serde1", feature = "seq")))] fn main() {} /// # #[cfg(all(feature = "serde1", feature = "seq"))] /// # fn main() -> Result<(), Box> { /// # use value_bag_serde1::json as serde_json; /// use value_bag::ValueBag; /// /// let value = ValueBag::from_seq_slice(&[1, 2, 3]); /// /// assert_eq!("[1,2,3]", serde_json::to_string(&value)?); /// # Ok(()) /// # } /// ``` /// /// A sequence captured with either `sval` or `serde` can have its elements extracted: /// /// ``` /// # #[cfg(not(all(feature = "serde1", feature = "seq")))] fn main() {} /// # #[cfg(all(feature = "serde1", feature = "seq"))] /// # fn main() -> Result<(), Box> { /// use value_bag::ValueBag; /// /// let value = ValueBag::from_serde1(&[1.0, 2.0, 3.0]); /// /// let seq = value.to_f64_seq::>>().ok_or("not a sequence")?; /// /// assert_eq!(vec![Some(1.0), Some(2.0), Some(3.0)], seq); /// # Ok(()) /// # } /// ``` #[derive(Clone)] pub struct ValueBag<'v> { inner: internal::Internal<'v>, } impl<'v> ValueBag<'v> { /// Get an empty `ValueBag`. #[inline] pub const fn empty() -> ValueBag<'v> { ValueBag { inner: internal::Internal::None, } } /// Get a `ValueBag` from an `Option`. /// /// This method will return `ValueBag::empty` if the value is `None`. #[inline] pub fn from_option(v: Option>>) -> ValueBag<'v> { match v { Some(v) => v.into(), None => ValueBag::empty(), } } /// Get a `ValueBag` from a `u8`. #[inline] pub const fn from_u8(v: u8) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Unsigned(v as u64), } } /// Get a `ValueBag` from a `u16`. #[inline] pub const fn from_u16(v: u16) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Unsigned(v as u64), } } /// Get a `ValueBag` from a `u32`. #[inline] pub const fn from_u32(v: u32) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Unsigned(v as u64), } } /// Get a `ValueBag` from a `u64`. #[inline] pub const fn from_u64(v: u64) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Unsigned(v), } } /// Get a `ValueBag` from a `usize`. #[inline] pub const fn from_usize(v: usize) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Unsigned(v as u64), } } /// Get a `ValueBag` from a `u128`. #[inline] pub const fn from_u128_ref(v: &'v u128) -> ValueBag<'v> { ValueBag { #[cfg(not(feature = "inline-i128"))] inner: internal::Internal::BigUnsigned(v), #[cfg(feature = "inline-i128")] inner: internal::Internal::BigUnsigned(*v), } } /// Get a `ValueBag` from a `u128`. #[inline] #[cfg(feature = "inline-i128")] pub const fn from_u128(v: u128) -> ValueBag<'v> { ValueBag { inner: internal::Internal::BigUnsigned(v), } } /// Get a `ValueBag` from a `i8`. #[inline] pub const fn from_i8(v: i8) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Signed(v as i64), } } /// Get a `ValueBag` from a `i16`. #[inline] pub const fn from_i16(v: i16) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Signed(v as i64), } } /// Get a `ValueBag` from a `i32`. #[inline] pub const fn from_i32(v: i32) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Signed(v as i64), } } /// Get a `ValueBag` from a `i64`. #[inline] pub const fn from_i64(v: i64) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Signed(v), } } /// Get a `ValueBag` from a `isize`. #[inline] pub const fn from_isize(v: isize) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Signed(v as i64), } } /// Get a `ValueBag` from a `i128`. #[inline] pub const fn from_i128_ref(v: &'v i128) -> ValueBag<'v> { ValueBag { #[cfg(not(feature = "inline-i128"))] inner: internal::Internal::BigSigned(v), #[cfg(feature = "inline-i128")] inner: internal::Internal::BigSigned(*v), } } /// Get a `ValueBag` from a `i128`. #[inline] #[cfg(feature = "inline-i128")] pub const fn from_i128(v: i128) -> ValueBag<'v> { ValueBag { inner: internal::Internal::BigSigned(v), } } /// Get a `ValueBag` from a `f32`. #[inline] pub const fn from_f32(v: f32) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Float(v as f64), } } /// Get a `ValueBag` from a `f64`. #[inline] pub const fn from_f64(v: f64) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Float(v), } } /// Get a `ValueBag` from a `bool`. #[inline] pub const fn from_bool(v: bool) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Bool(v), } } /// Get a `ValueBag` from a `str`. #[inline] pub const fn from_str(v: &'v str) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Str(v), } } /// Get a `ValueBag` from a `char`. #[inline] pub const fn from_char(v: char) -> ValueBag<'v> { ValueBag { inner: internal::Internal::Char(v), } } /// Get a `ValueBag` from a reference to a `ValueBag`. #[inline] pub const fn by_ref(&self) -> ValueBag<'_> { ValueBag { inner: self.inner.by_ref(), } } } #[cfg(test)] mod tests { use super::*; use crate::std::mem; #[cfg(feature = "inline-i128")] const SIZE_LIMIT_U64: usize = 4; #[cfg(not(feature = "inline-i128"))] const SIZE_LIMIT_U64: usize = 3; #[test] fn value_bag_size() { let size = mem::size_of::>(); let limit = mem::size_of::() * SIZE_LIMIT_U64; if size > limit { panic!( "`ValueBag` size ({} bytes) is too large (expected up to {} bytes)", size, limit, ); } } } value-bag-1.9.0/src/owned.rs000064400000000000000000000342731046102023000137600ustar 00000000000000use crate::{ internal::{self, Internal}, std::sync::Arc, ValueBag, }; /// A dynamic structured value. /// /// This type is an owned variant of [`ValueBag`] that can be /// constructed using its [`to_owned`](struct.ValueBag.html#method.to_owned) method. /// `OwnedValueBag`s are suitable for storing and sharing across threads. /// /// `OwnedValueBag`s can be inspected by converting back into a regular `ValueBag` /// using the [`by_ref`](#method.by_ref) method. #[derive(Clone)] pub struct OwnedValueBag { inner: internal::owned::OwnedInternal, } impl<'v> ValueBag<'v> { /// Buffer this value into an [`OwnedValueBag`]. pub fn to_owned(&self) -> OwnedValueBag { OwnedValueBag { inner: self.inner.to_owned(), } } /// Buffer this value into an [`OwnedValueBag`], internally storing it /// in an `Arc` for cheap cloning. pub fn to_shared(&self) -> OwnedValueBag { self.to_owned().into_shared() } } impl ValueBag<'static> { /// Get a value from an owned, sharable, debuggable type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Debug` implementation. /// /// The value will be stored in an `Arc` for cheap cloning. pub fn capture_shared_debug(value: T) -> Self where T: internal::fmt::Debug + Send + Sync + 'static, { Self::try_capture_owned(&value).unwrap_or_else(|| ValueBag { inner: Internal::SharedDebug(Arc::new(value)), }) } /// Get a value from an owned, sharable, displayable type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Display` implementation. /// /// The value will be stored in an `Arc` for cheap cloning. pub fn capture_shared_display(value: T) -> Self where T: internal::fmt::Display + Send + Sync + 'static, { Self::try_capture_owned(&value).unwrap_or_else(|| ValueBag { inner: Internal::SharedDisplay(Arc::new(value)), }) } /// Get a value from an owned, shared error. /// /// The value will be stored in an `Arc` for cheap cloning. #[cfg(feature = "error")] pub fn capture_shared_error(value: T) -> Self where T: internal::error::Error + Send + Sync + 'static, { ValueBag { inner: Internal::SharedError(Arc::new(value)), } } /// Get a value from an owned, shared, structured type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Value` implementation. /// /// The value will be stored in an `Arc` for cheap cloning. #[cfg(feature = "sval2")] pub fn capture_shared_sval2(value: T) -> Self where T: value_bag_sval2::lib::Value + Send + Sync + 'static, { Self::try_capture_owned(&value).unwrap_or(ValueBag { inner: Internal::SharedSval2(Arc::new(value)), }) } /// Get a value from an owned, shared, structured type. /// /// This method will attempt to capture the given value as a well-known primitive /// before resorting to using its `Value` implementation. /// /// The value will be stored in an `Arc` for cheap cloning. #[cfg(feature = "serde1")] pub fn capture_shared_serde1(value: T) -> Self where T: value_bag_serde1::lib::Serialize + Send + Sync + 'static, { Self::try_capture_owned(&value).unwrap_or(ValueBag { inner: Internal::SharedSerde1(Arc::new(value)), }) } /// Get a value from an owned, shared, sequence. /// /// The value will be stored in an `Arc` for cheap cloning. #[cfg(feature = "seq")] pub fn capture_shared_seq_slice(value: I) -> Self where I: AsRef<[T]> + Send + Sync + 'static, T: Send + Sync + 'static, for<'v> &'v T: Into>, { use crate::{ internal::seq::Visitor, std::{marker::PhantomData, ops::ControlFlow}, }; struct OwnedSeqSlice(PhantomData<[T]>, I); impl internal::seq::Seq for OwnedSeqSlice where I: AsRef<[T]> + ?Sized, for<'v> &'v T: Into>, { fn visit(&self, visitor: &mut dyn Visitor<'_>) { for v in self.1.as_ref().iter() { if let ControlFlow::Break(()) = visitor.element(v.into()) { return; } } } } Self::try_capture_owned(&value).unwrap_or(ValueBag { inner: Internal::SharedSeq(Arc::new(OwnedSeqSlice(PhantomData, value))), }) } } impl OwnedValueBag { /// Get a regular [`ValueBag`] from this type. /// /// Once a `ValueBag` has been buffered, it will behave /// slightly differently when converted back: /// /// - `fmt::Debug` won't use formatting flags. /// - `serde::Serialize` will use the text-based representation. /// - The original type may change, so downcasting can stop producing results. pub const fn by_ref(&self) -> ValueBag { ValueBag { inner: self.inner.by_ref(), } } /// Make this value cheap to clone and share by internally storing it in an `Arc`. /// /// If the value is already shared then this method will simply clone it. pub fn into_shared(self) -> Self { OwnedValueBag { inner: self.inner.into_shared(), } } } #[cfg(test)] mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; use super::*; use crate::{ fill, std::{mem, string::ToString}, }; const SIZE_LIMIT_U64: usize = 4; #[test] fn is_send_sync() { fn assert() {} assert::(); } #[test] fn owned_value_bag_size() { let size = mem::size_of::(); let limit = mem::size_of::() * SIZE_LIMIT_U64; if size > limit { panic!( "`OwnedValueBag` size ({} bytes) is too large (expected up to {} bytes)", size, limit, ); } } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_to_owned() { let value = ValueBag::from_fill(&|slot: fill::Slot| slot.fill_any(42u64)).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::BigUnsigned(42) )); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_to_shared() { let value = ValueBag::from_fill(&|slot: fill::Slot| slot.fill_any(42u64)).to_shared(); assert!(matches!( value.inner, internal::owned::OwnedInternal::BigUnsigned(42) )); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_to_owned() { let debug = ValueBag::from_debug(&"a value").to_owned(); let display = ValueBag::from_display(&"a value").to_owned(); assert!(matches!( debug.inner, internal::owned::OwnedInternal::Debug(_) )); assert!(matches!( display.inner, internal::owned::OwnedInternal::Display(_) )); assert_eq!("\"a value\"", debug.to_string()); assert_eq!("a value", display.to_string()); let debug = debug.by_ref(); let display = display.by_ref(); assert!(matches!(debug.inner, internal::Internal::AnonDebug(_))); assert!(matches!(display.inner, internal::Internal::AnonDisplay(_))); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fmt_to_shared() { let debug = ValueBag::from_debug(&"a value").to_shared(); let display = ValueBag::from_display(&"a value").to_shared(); assert!(matches!( debug.inner, internal::owned::OwnedInternal::SharedDebug(_) )); assert!(matches!( display.inner, internal::owned::OwnedInternal::SharedDisplay(_) )); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn owned_fmt_to_owned() { let debug = ValueBag::capture_shared_debug("a value".to_string()).to_owned(); let display = ValueBag::capture_shared_display("a value".to_string()).to_owned(); assert!(matches!( debug.inner, internal::owned::OwnedInternal::SharedDebug(_) )); assert!(matches!( display.inner, internal::owned::OwnedInternal::SharedDisplay(_) )); assert_eq!("\"a value\"", debug.to_string()); assert_eq!("a value", display.to_string()); let debug = debug.by_ref(); let display = display.by_ref(); assert!(matches!(debug.inner, internal::Internal::SharedRefDebug(_))); assert!(matches!( display.inner, internal::Internal::SharedRefDisplay(_) )); } #[test] #[cfg(feature = "error")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn error_to_owned() { use crate::std::io; let value = ValueBag::from_dyn_error(&io::Error::new(io::ErrorKind::Other, "something failed!")) .to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::Error(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::AnonError(_))); assert!(value.to_borrowed_error().is_some()); } #[test] #[cfg(feature = "error")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn error_to_shared() { use crate::std::io; let value = ValueBag::from_dyn_error(&io::Error::new(io::ErrorKind::Other, "something failed!")) .to_shared(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedError(_) )); } #[test] #[cfg(feature = "error")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn owned_error_to_owned() { use crate::std::io; let value = ValueBag::capture_shared_error(io::Error::new( io::ErrorKind::Other, "something failed!", )) .to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedError(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::SharedRefError(_))); } #[test] #[cfg(feature = "serde1")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_to_owned() { let value = ValueBag::from_serde1(&42u64).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::Serde1(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::AnonSerde1(_))); } #[test] #[cfg(feature = "serde1")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn serde1_to_shared() { let value = ValueBag::from_serde1(&42u64).to_shared(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedSerde1(_) )); } #[test] #[cfg(feature = "serde1")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn owned_serde1_to_owned() { let value = ValueBag::capture_shared_serde1("a value".to_string()).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedSerde1(_) )); let value = value.by_ref(); assert!(matches!( value.inner, internal::Internal::SharedRefSerde1(_) )); } #[test] #[cfg(feature = "sval2")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_to_owned() { let value = ValueBag::from_sval2(&42u64).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::Sval2(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::AnonSval2(_))); } #[test] #[cfg(feature = "sval2")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn sval2_to_shared() { let value = ValueBag::from_sval2(&42u64).to_shared(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedSval2(_) )); } #[test] #[cfg(feature = "sval2")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn owned_sval2_to_owned() { let value = ValueBag::capture_shared_sval2("a value".to_string()).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedSval2(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::SharedRefSval2(_))); } #[test] #[cfg(feature = "seq")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn seq_to_owned() { let value = ValueBag::from_seq_slice(&[1, 2, 3]).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::Seq(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::AnonSeq(_))); } #[test] #[cfg(feature = "seq")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn seq_to_shared() { let value = ValueBag::from_seq_slice(&[1, 2, 3]).to_shared(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedSeq(_) )); } #[test] #[cfg(feature = "seq")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn owned_seq_to_owned() { let value = ValueBag::capture_shared_seq_slice(vec![1, 2, 3]).to_owned(); assert!(matches!( value.inner, internal::owned::OwnedInternal::SharedSeq(_) )); let value = value.by_ref(); assert!(matches!(value.inner, internal::Internal::SharedRefSeq(_))); } } value-bag-1.9.0/src/test.rs000064400000000000000000000146731046102023000136250ustar 00000000000000//! Test support for inspecting values. use crate::{ internal, std::{fmt, str, string::String}, visit::Visit, Error, ValueBag, }; #[cfg(test)] pub(crate) trait IntoValueBag<'v> { fn into_value_bag(self) -> ValueBag<'v>; } #[cfg(test)] impl<'v, T> IntoValueBag<'v> for T where T: Into>, { fn into_value_bag(self) -> ValueBag<'v> { self.into() } } /** A tokenized representation of the captured value for testing. */ #[derive(Debug, PartialEq)] #[non_exhaustive] pub enum TestToken { U64(u64), I64(i64), F64(f64), U128(u128), I128(i128), Char(char), Bool(bool), Str(String), None, #[cfg(feature = "error")] Error, #[cfg(feature = "sval2")] Sval { version: u32, }, #[cfg(feature = "serde1")] Serde { version: u32, }, #[cfg(feature = "seq")] Seq, Poisoned(String), } impl<'v> ValueBag<'v> { /** Convert the value bag into a token for testing. This _isn't_ a general-purpose API for working with values outside of testing. */ pub fn to_test_token(&self) -> TestToken { struct TestVisitor(Option); impl<'v> internal::InternalVisitor<'v> for TestVisitor { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } fn debug(&mut self, v: &dyn fmt::Debug) -> Result<(), Error> { self.0 = Some(TestToken::Str(format!("{:?}", v))); Ok(()) } fn display(&mut self, v: &dyn fmt::Display) -> Result<(), Error> { self.0 = Some(TestToken::Str(format!("{}", v))); Ok(()) } fn u64(&mut self, v: u64) -> Result<(), Error> { self.0 = Some(TestToken::U64(v)); Ok(()) } fn i64(&mut self, v: i64) -> Result<(), Error> { self.0 = Some(TestToken::I64(v)); Ok(()) } fn u128(&mut self, v: &u128) -> Result<(), Error> { self.0 = Some(TestToken::U128(*v)); Ok(()) } fn i128(&mut self, v: &i128) -> Result<(), Error> { self.0 = Some(TestToken::I128(*v)); Ok(()) } fn f64(&mut self, v: f64) -> Result<(), Error> { self.0 = Some(TestToken::F64(v)); Ok(()) } fn bool(&mut self, v: bool) -> Result<(), Error> { self.0 = Some(TestToken::Bool(v)); Ok(()) } fn char(&mut self, v: char) -> Result<(), Error> { self.0 = Some(TestToken::Char(v)); Ok(()) } fn str(&mut self, v: &str) -> Result<(), Error> { self.0 = Some(TestToken::Str(v.into())); Ok(()) } fn none(&mut self) -> Result<(), Error> { self.0 = Some(TestToken::None); Ok(()) } #[cfg(feature = "error")] fn error(&mut self, _: &dyn internal::error::Error) -> Result<(), Error> { self.0 = Some(TestToken::Error); Ok(()) } #[cfg(feature = "sval2")] fn sval2(&mut self, _: &dyn internal::sval::v2::Value) -> Result<(), Error> { self.0 = Some(TestToken::Sval { version: 2 }); Ok(()) } #[cfg(feature = "serde1")] fn serde1(&mut self, _: &dyn internal::serde::v1::Serialize) -> Result<(), Error> { self.0 = Some(TestToken::Serde { version: 1 }); Ok(()) } #[cfg(feature = "seq")] fn seq(&mut self, _: &dyn internal::seq::Seq) -> Result<(), Error> { self.0 = Some(TestToken::Seq); Ok(()) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { self.0 = Some(TestToken::Poisoned(msg.into())); Ok(()) } } let mut visitor = TestVisitor(None); self.internal_visit(&mut visitor).unwrap(); visitor.0.unwrap() } } pub(crate) struct TestVisit { pub i64: i64, pub u64: u64, pub i128: i128, pub u128: u128, pub f64: f64, pub bool: bool, pub str: &'static str, pub borrowed_str: &'static str, pub char: char, } impl Default for TestVisit { fn default() -> Self { TestVisit { i64: -42, u64: 42, i128: -42, u128: 42, f64: 11.0, bool: true, str: "some string", borrowed_str: "some borrowed string", char: 'n', } } } impl<'v> Visit<'v> for TestVisit { fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> { panic!("unexpected value: {}", v) } fn visit_i64(&mut self, v: i64) -> Result<(), Error> { assert_eq!(self.i64, v); Ok(()) } fn visit_u64(&mut self, v: u64) -> Result<(), Error> { assert_eq!(self.u64, v); Ok(()) } fn visit_i128(&mut self, v: i128) -> Result<(), Error> { assert_eq!(self.i128, v); Ok(()) } fn visit_u128(&mut self, v: u128) -> Result<(), Error> { assert_eq!(self.u128, v); Ok(()) } fn visit_f64(&mut self, v: f64) -> Result<(), Error> { assert_eq!(self.f64, v); Ok(()) } fn visit_bool(&mut self, v: bool) -> Result<(), Error> { assert_eq!(self.bool, v); Ok(()) } fn visit_str(&mut self, v: &str) -> Result<(), Error> { assert_eq!(self.str, v); Ok(()) } fn visit_borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { assert_eq!(self.borrowed_str, v); Ok(()) } fn visit_char(&mut self, v: char) -> Result<(), Error> { assert_eq!(self.char, v); Ok(()) } #[cfg(feature = "error")] fn visit_error(&mut self, err: &(dyn crate::std::error::Error + 'static)) -> Result<(), Error> { assert!(err.downcast_ref::().is_some()); Ok(()) } #[cfg(feature = "error")] fn visit_borrowed_error( &mut self, err: &'v (dyn crate::std::error::Error + 'static), ) -> Result<(), Error> { assert!(err.downcast_ref::().is_some()); Ok(()) } } value-bag-1.9.0/src/visit.rs000064400000000000000000000354161046102023000140020ustar 00000000000000//! Value inspection. //! //! The [`Visit`] trait provides a simple visitor API that can be used to inspect //! the structure of primitives stored in a [`ValueBag`](../struct.ValueBag.html). //! More complex datatypes can then be handled using `std::fmt`, `sval`, or `serde`. //! //! ``` //! # #[cfg(not(feature = "std"))] fn main() {} //! # #[cfg(feature = "std")] //! # fn main() -> Result<(), Box> { //! # fn escape(buf: &[u8]) -> &[u8] { buf } //! # fn itoa_fmt(num: T) -> Vec { vec![] } //! # fn ryu_fmt(num: T) -> Vec { vec![] } //! # use std::io::Write; //! use value_bag::{ValueBag, Error, visit::Visit}; //! //! // Implement some simple custom serialization //! struct MyVisit(Vec); //! impl<'v> Visit<'v> for MyVisit { //! fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> { //! // Fallback to `Debug` if we didn't visit the value specially //! write!(&mut self.0, "{:?}", v).map_err(|_| Error::msg("failed to write value")) //! } //! //! fn visit_u64(&mut self, v: u64) -> Result<(), Error> { //! self.0.extend_from_slice(itoa_fmt(v).as_slice()); //! Ok(()) //! } //! //! fn visit_i64(&mut self, v: i64) -> Result<(), Error> { //! self.0.extend_from_slice(itoa_fmt(v).as_slice()); //! Ok(()) //! } //! //! fn visit_f64(&mut self, v: f64) -> Result<(), Error> { //! self.0.extend_from_slice(ryu_fmt(v).as_slice()); //! Ok(()) //! } //! //! fn visit_str(&mut self, v: &str) -> Result<(), Error> { //! self.0.push(b'\"'); //! self.0.extend_from_slice(escape(v.as_bytes())); //! self.0.push(b'\"'); //! Ok(()) //! } //! //! fn visit_bool(&mut self, v: bool) -> Result<(), Error> { //! self.0.extend_from_slice(if v { b"true" } else { b"false" }); //! Ok(()) //! } //! } //! //! let value = ValueBag::from(42i64); //! //! let mut visitor = MyVisit(vec![]); //! value.visit(&mut visitor)?; //! # Ok(()) //! # } //! ``` use crate::{ internal::{self, InternalVisitor}, Error, ValueBag, }; /// A visitor for a `ValueBag`. pub trait Visit<'v> { /// Visit a `ValueBag`. /// /// This is the only required method on `Visit` and acts as a fallback for any /// more specific methods that aren't overridden. /// The `ValueBag` may be formatted using its `fmt::Debug` or `fmt::Display` implementation, /// or serialized using its `sval::Value` or `serde::Serialize` implementation. fn visit_any(&mut self, value: ValueBag) -> Result<(), Error>; /// Visit an empty value. #[inline] fn visit_empty(&mut self) -> Result<(), Error> { self.visit_any(ValueBag::empty()) } /// Visit an unsigned integer. #[inline] fn visit_u64(&mut self, value: u64) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a signed integer. #[inline] fn visit_i64(&mut self, value: i64) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a big unsigned integer. #[inline] fn visit_u128(&mut self, value: u128) -> Result<(), Error> { self.visit_any((&value).into()) } /// Visit a big signed integer. #[inline] fn visit_i128(&mut self, value: i128) -> Result<(), Error> { self.visit_any((&value).into()) } /// Visit a floating point. #[inline] fn visit_f64(&mut self, value: f64) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a boolean. #[inline] fn visit_bool(&mut self, value: bool) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a string. #[inline] fn visit_str(&mut self, value: &str) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a string. #[inline] fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { self.visit_str(value) } /// Visit a Unicode character. #[inline] fn visit_char(&mut self, value: char) -> Result<(), Error> { let mut b = [0; 4]; self.visit_str(&*value.encode_utf8(&mut b)) } /// Visit an error. #[inline] #[cfg(feature = "error")] fn visit_error(&mut self, err: &(dyn crate::std::error::Error + 'static)) -> Result<(), Error> { self.visit_any(ValueBag::from_dyn_error(err)) } /// Visit an error. #[inline] #[cfg(feature = "error")] fn visit_borrowed_error( &mut self, err: &'v (dyn crate::std::error::Error + 'static), ) -> Result<(), Error> { self.visit_any(ValueBag::from_dyn_error(err)) } } impl<'a, 'v, T: ?Sized> Visit<'v> for &'a mut T where T: Visit<'v>, { #[inline] fn visit_any(&mut self, value: ValueBag) -> Result<(), Error> { (**self).visit_any(value) } #[inline] fn visit_empty(&mut self) -> Result<(), Error> { (**self).visit_empty() } #[inline] fn visit_u64(&mut self, value: u64) -> Result<(), Error> { (**self).visit_u64(value) } #[inline] fn visit_i64(&mut self, value: i64) -> Result<(), Error> { (**self).visit_i64(value) } #[inline] fn visit_u128(&mut self, value: u128) -> Result<(), Error> { (**self).visit_u128(value) } #[inline] fn visit_i128(&mut self, value: i128) -> Result<(), Error> { (**self).visit_i128(value) } #[inline] fn visit_f64(&mut self, value: f64) -> Result<(), Error> { (**self).visit_f64(value) } #[inline] fn visit_bool(&mut self, value: bool) -> Result<(), Error> { (**self).visit_bool(value) } #[inline] fn visit_str(&mut self, value: &str) -> Result<(), Error> { (**self).visit_str(value) } #[inline] fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { (**self).visit_borrowed_str(value) } #[inline] fn visit_char(&mut self, value: char) -> Result<(), Error> { (**self).visit_char(value) } #[inline] #[cfg(feature = "error")] fn visit_error(&mut self, err: &(dyn crate::std::error::Error + 'static)) -> Result<(), Error> { (**self).visit_error(err) } #[inline] #[cfg(feature = "error")] fn visit_borrowed_error( &mut self, err: &'v (dyn crate::std::error::Error + 'static), ) -> Result<(), Error> { (**self).visit_borrowed_error(err) } } impl<'v> ValueBag<'v> { /// Visit this value using a simple visitor. /// /// The visitor isn't strictly required to inspect the contents of a value bag. /// It's useful for simple cases where a full framework like `serde` or `sval` /// isn't necessary. pub fn visit(&self, visitor: impl Visit<'v>) -> Result<(), Error> { struct Visitor(V); impl<'v, V> InternalVisitor<'v> for Visitor where V: Visit<'v>, { fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { v.fill(crate::fill::Slot::new(self)) } fn debug(&mut self, v: &dyn internal::fmt::Debug) -> Result<(), Error> { self.0.visit_any(ValueBag::from_dyn_debug(v)) } fn display(&mut self, v: &dyn internal::fmt::Display) -> Result<(), Error> { self.0.visit_any(ValueBag::from_dyn_display(v)) } fn u64(&mut self, v: u64) -> Result<(), Error> { self.0.visit_u64(v) } fn i64(&mut self, v: i64) -> Result<(), Error> { self.0.visit_i64(v) } fn u128(&mut self, v: &u128) -> Result<(), Error> { self.0.visit_u128(*v) } fn i128(&mut self, v: &i128) -> Result<(), Error> { self.0.visit_i128(*v) } fn f64(&mut self, v: f64) -> Result<(), Error> { self.0.visit_f64(v) } fn bool(&mut self, v: bool) -> Result<(), Error> { self.0.visit_bool(v) } fn char(&mut self, v: char) -> Result<(), Error> { self.0.visit_char(v) } fn str(&mut self, v: &str) -> Result<(), Error> { self.0.visit_str(v) } fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { self.0.visit_borrowed_str(v) } fn none(&mut self) -> Result<(), Error> { self.0.visit_empty() } #[cfg(feature = "error")] fn error(&mut self, v: &(dyn internal::error::Error + 'static)) -> Result<(), Error> { self.0.visit_error(v) } #[cfg(feature = "error")] fn borrowed_error( &mut self, v: &'v (dyn internal::error::Error + 'static), ) -> Result<(), Error> { self.0.visit_borrowed_error(v) } #[cfg(feature = "sval2")] fn sval2(&mut self, v: &dyn internal::sval::v2::Value) -> Result<(), Error> { if internal::sval::v2::internal_visit(v, self) { Ok(()) } else { self.0.visit_any(ValueBag::from_dyn_sval2(v)) } } #[cfg(feature = "sval2")] fn borrowed_sval2( &mut self, v: &'v dyn internal::sval::v2::Value, ) -> Result<(), Error> { if internal::sval::v2::borrowed_internal_visit(v, self) { Ok(()) } else { self.0.visit_any(ValueBag::from_dyn_sval2(v)) } } #[cfg(feature = "serde1")] fn serde1(&mut self, v: &dyn internal::serde::v1::Serialize) -> Result<(), Error> { if internal::serde::v1::internal_visit(v, self) { Ok(()) } else { self.0.visit_any(ValueBag::from_dyn_serde1(v)) } } #[cfg(feature = "seq")] fn seq(&mut self, v: &dyn internal::seq::Seq) -> Result<(), Error> { self.0.visit_any(ValueBag::from_dyn_seq(v)) } fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { Err(Error::msg(msg)) } } self.internal_visit(&mut Visitor(visitor)) } } #[cfg(test)] mod tests { use super::*; use crate::test::*; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn visit_structured() { ValueBag::from(42u64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from(-42i64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from(&42u128) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from(&-42i128) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from(11f64) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from(true) .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from("some borrowed string") .visit(TestVisit::default()) .expect("failed to visit value"); ValueBag::from('n') .visit(TestVisit::default()) .expect("failed to visit value"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn visit_empty() { struct Visitor(bool); impl<'v> Visit<'v> for Visitor { fn visit_any(&mut self, _: ValueBag) -> Result<(), Error> { Ok(()) } fn visit_empty(&mut self) -> Result<(), Error> { self.0 = true; Ok(()) } } let mut visitor = Visitor(false); ValueBag::empty().visit(&mut visitor).unwrap(); assert!(visitor.0); } #[test] #[cfg(feature = "serde1")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn visit_serde1() { use crate::std::string::{String, ToString}; struct Data; impl value_bag_serde1::lib::Serialize for Data { fn serialize( &self, serializer: S, ) -> Result { use value_bag_serde1::lib::ser::SerializeStruct; let mut s = serializer.serialize_struct("Data", 3)?; s.serialize_field("a", &1)?; s.serialize_field("b", &2)?; s.serialize_field("c", &3)?; s.end() } } struct Visitor(String); impl<'v> Visit<'v> for Visitor { fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> { self.0 = v.to_string(); Ok(()) } } let mut visitor = Visitor("".into()); ValueBag::from_serde1(&Data).visit(&mut visitor).unwrap(); assert_eq!("Data { a: 1, b: 2, c: 3 }", visitor.0); } #[test] #[cfg(feature = "sval2")] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn visit_sval2() { use crate::std::string::{String, ToString}; struct Data; impl value_bag_sval2::lib::Value for Data { fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> value_bag_sval2::lib::Result { stream.map_begin(Some(3))?; stream.map_key_begin()?; stream.value("a")?; stream.map_key_end()?; stream.map_value_begin()?; stream.value(&1)?; stream.map_value_end()?; stream.map_key_begin()?; stream.value("b")?; stream.map_key_end()?; stream.map_value_begin()?; stream.value(&2)?; stream.map_value_end()?; stream.map_key_begin()?; stream.value("c")?; stream.map_key_end()?; stream.map_value_begin()?; stream.value(&3)?; stream.map_value_end()?; stream.map_end() } } struct Visitor(String); impl<'v> Visit<'v> for Visitor { fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> { self.0 = v.to_string(); Ok(()) } } let mut visitor = Visitor("".into()); ValueBag::from_sval2(&Data).visit(&mut visitor).unwrap(); assert_eq!("{ \"a\": 1, \"b\": 2, \"c\": 3 }", visitor.0); } }