value-bag-1.4.1/.cargo_vcs_info.json0000644000000001360000000000100127020ustar { "git": { "sha1": "18b80917ba3b00c16e67cff27d6b28d18a235f6e" }, "path_in_vcs": "" }value-bag-1.4.1/.gitignore000064400000000000000000000004771046102023000134720ustar 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.4.1/Cargo.toml0000644000000033430000000000100107030ustar # 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.4.1" 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", ] [dependencies.value-bag-serde1] version = "1.4.1" optional = true [dependencies.value-bag-sval2] version = "1.4.1" optional = true [dev-dependencies] [features] alloc = [ "value-bag-sval2?/alloc", "value-bag-serde1?/alloc", ] error = ["std"] inline-i128 = [] owned = [ "alloc", "value-bag-serde1?/owned", ] 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.4.1/Cargo.toml.orig000064400000000000000000000034721046102023000143670ustar 00000000000000[package] name = "value-bag" version = "1.4.1" 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"] [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", ] # 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.4.1" path = "meta/sval2" optional = true [dependencies.value-bag-serde1] version = "1.4.1" 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.4.1/LICENSE-APACHE000064400000000000000000000251371046102023000134260ustar 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.4.1/LICENSE-MIT000064400000000000000000000020501046102023000131230ustar 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.4.1/README.md000064400000000000000000000072331046102023000127560ustar 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.4.1" ``` 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.4.1" features = ["sval2"] ``` ```rust [dependencies.value-bag] version = "1.4.1" 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. - `test`: Add test helpers for inspecting the shape of the value inside a `ValueBag`. value-bag-1.4.1/benches/by_ref.rs000064400000000000000000000002551046102023000147170ustar 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.4.1/benches/capture.rs000064400000000000000000000045441046102023000151210ustar 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.4.1/benches/owned.rs000064400000000000000000000041511046102023000145640ustar 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.4.1/src/error.rs000064400000000000000000000027161046102023000137660ustar 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), } } } 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.4.1/src/fill.rs000064400000000000000000000115711046102023000135620ustar 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::InternalVisitor; use super::{Error, ValueBag}; /// 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: &dyn fmt::Debug = &1; slot.fill_debug(&dbg) } } assert_eq!("1", ValueBag::from_fill(&TestFill).to_string()); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn fill_value_owned() { struct TestFill; impl Fill for TestFill { fn fill(&self, slot: Slot) -> Result<(), Error> { slot.fill_any("a 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_debug() { struct TestFill; impl Fill for TestFill { fn fill(&self, slot: Slot) -> Result<(), Error> { slot.fill_any(42u64) } } assert_eq!( format!("{:04?}", 42u64), format!("{:04?}", ValueBag::from_fill(&TestFill)), ) } #[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.4.1/src/impls.rs000064400000000000000000000103211046102023000137500ustar 00000000000000//! Converting standard types into `ValueBag`s. use super::ValueBag; macro_rules! impl_from_internal { ($($into_ty:ty,)*) => { $( impl<'v> From<$into_ty> for ValueBag<'v> { #[inline] fn from(value: $into_ty) -> Self { ValueBag::from_internal(value) } } impl<'a, 'v> From<&'a $into_ty> for ValueBag<'v> { #[inline] fn from(value: &'a $into_ty) -> Self { ValueBag::from_internal(*value) } } )* }; } impl_from_internal![ (), usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32, f64, char, bool, ]; impl<'v> From<&'v str> for ValueBag<'v> { #[inline] fn from(value: &'v str) -> Self { ValueBag::from_internal(value) } } impl<'v> From<&'v u128> for ValueBag<'v> { #[inline] fn from(value: &'v u128) -> Self { ValueBag::from_internal(value) } } impl<'v> From<&'v i128> for ValueBag<'v> { #[inline] fn from(value: &'v i128) -> Self { ValueBag::from_internal(value) } } #[cfg(feature = "inline-i128")] impl<'v> From for ValueBag<'v> { #[inline] fn from(value: u128) -> Self { ValueBag::from_internal(value) } } #[cfg(feature = "inline-i128")] impl<'v> From for ValueBag<'v> { #[inline] fn from(value: i128) -> Self { ValueBag::from_internal(value) } } #[cfg(feature = "std")] mod std_support { use super::*; use crate::std::string::String; impl<'v> From<&'v String> for ValueBag<'v> { #[inline] fn from(v: &'v String) -> ValueBag<'v> { ValueBag::from_internal(&**v) } } } #[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.4.1/src/internal/cast/mod.rs000064400000000000000000000423151046102023000161610ustar 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::{ convert::{TryFrom, TryInto}, fmt, }; #[cfg(feature = "std")] use crate::std::{borrow::ToOwned, string::String}; use super::{Internal, InternalVisitor}; use crate::{Error, ValueBag}; mod primitive; 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).map(|inner| ValueBag { inner }) } /// 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. pub fn to_f64(&self) -> Option { self.inner.cast().into_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 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(), _ => 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 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 = "std")] #[inline] fn str(&mut self, s: &str) -> Result<(), Error> { self.0 = Cast::String(s.to_owned()); Ok(()) } #[cfg(not(feature = "std"))] #[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> { super::sval::v2::internal_visit(v, self) } #[cfg(feature = "sval2")] fn borrowed_sval2(&mut self, v: &'v dyn super::sval::v2::Value) -> Result<(), Error> { super::sval::v2::borrowed_internal_visit(v, self) } #[cfg(feature = "serde1")] #[inline] fn serde1(&mut self, v: &dyn super::serde::v1::Serialize) -> Result<(), Error> { super::serde::v1::internal_visit(v, self) } } 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 = "std")] 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 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 = "std")] mod std_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::std::string::ToString; use crate::test::IntoValueBag; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn primitive_capture_str() { let s: &str = &"short lived".to_string(); 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_eq!( true, true.into_value_bag() .by_ref() .to_bool() .expect("invalid value") ); } } value-bag-1.4.1/src/internal/cast/primitive.rs000064400000000000000000000053011046102023000174040ustar 00000000000000/* This module generates code to try efficiently convert some arbitrary `T: 'static` into a `Internal`. */ #[cfg(feature = "std")] use crate::std::string::String; use crate::internal::Internal; pub(in crate::internal) fn from_any<'v, T: ?Sized + 'static>(value: &'v T) -> Option> { // 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! type_ids { ($( $(#[cfg($($cfg:tt)*)])* $ty:ty, )*) => { |v: VoidRef<'_>| { if TypeId::of::() == TypeId::of::() { // SAFETY: We verify the value is str before casting let v = unsafe { *(v.0 as *const &'_ str) }; return Some(Internal::from(v)); } $( $(#[cfg($($cfg)*)])* if TypeId::of::() == TypeId::of::<$ty>() { // SAFETY: We verify the value is $ty before casting let v = unsafe { *(v.0 as *const &'_ $ty) }; return Some(Internal::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 &'_ Option<$ty>) }; if let Some(v) = v { return Some(Internal::from(v)); } else { return Some(Internal::None); } } )* None } }; } let type_ids = type_ids![ 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 = "std")] String, ]; (type_ids)(VoidRef(&(value) as *const &'v T as *const &'v Void)) } value-bag-1.4.1/src/internal/error.rs000064400000000000000000000077011046102023000156010ustar 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 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.4.1/src/internal/fill.rs000064400000000000000000000004311046102023000153670ustar 00000000000000use super::Internal; use crate::{fill::Fill, ValueBag}; impl<'v> ValueBag<'v> { /// Get a value from a fillable slot. pub fn from_fill(value: &'v T) -> Self where T: Fill, { ValueBag { inner: Internal::Fill(value), } } } value-bag-1.4.1/src/internal/fmt.rs000064400000000000000000000303231046102023000152320ustar 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 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 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 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 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 } } 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<'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 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) } } 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 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) } } self.internal_visit(&mut DisplayVisitor(f)) .map_err(|_| fmt::Error)?; Ok(()) } } #[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_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()), ); } } value-bag-1.4.1/src/internal/mod.rs000064400000000000000000000373461046102023000152370ustar 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, Slot}, Error, ValueBag, }; pub(crate) mod cast; #[cfg(feature = "error")] pub(crate) mod error; pub(crate) mod fill; pub(crate) mod fmt; #[cfg(feature = "serde1")] pub(crate) mod serde; #[cfg(feature = "sval2")] pub(crate) mod sval; #[cfg(feature = "owned")] pub(crate) mod owned; // 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> { /// A signed integer. Signed(i64), /// An unsigned integer. Unsigned(u64), /// An extra large signed integer. #[cfg(not(feature = "inline-i128"))] BigSigned(&'v i128), #[cfg(feature = "inline-i128")] BigSigned(i128), /// An extra large unsigned integer. #[cfg(not(feature = "inline-i128"))] BigUnsigned(&'v u128), #[cfg(feature = "inline-i128")] BigUnsigned(u128), /// A floating point number. Float(f64), /// A boolean value. Bool(bool), /// A UTF8 codepoint. Char(char), /// A UTF8 string. Str(&'v str), /// An empty value. None, /// A value that can be filled. Fill(&'v dyn Fill), /// A debuggable value. AnonDebug(&'v dyn fmt::Debug), /// A debuggable value. Debug(&'v dyn fmt::DowncastDebug), /// A displayable value. AnonDisplay(&'v dyn fmt::Display), /// A displayable value. Display(&'v dyn fmt::DowncastDisplay), #[cfg(feature = "error")] /// An error. AnonError(&'v (dyn error::Error + 'static)), #[cfg(feature = "error")] /// An error. Error(&'v dyn error::DowncastError), #[cfg(feature = "sval2")] /// A structured value from `sval`. AnonSval2(&'v dyn sval::v2::Value), #[cfg(feature = "sval2")] /// A structured value from `sval`. Sval2(&'v dyn sval::v2::DowncastValue), #[cfg(feature = "serde1")] /// A structured value from `serde`. AnonSerde1(&'v dyn serde::v1::Serialize), #[cfg(feature = "serde1")] /// A structured value from `serde`. Serde1(&'v dyn serde::v1::DowncastSerialize), } /// The internal serialization contract. pub(crate) trait InternalVisitor<'v> { 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) } 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) } fn u64(&mut self, v: u64) -> Result<(), Error>; fn i64(&mut self, v: i64) -> Result<(), Error>; fn u128(&mut self, v: &u128) -> Result<(), Error>; fn borrowed_u128(&mut self, v: &'v u128) -> Result<(), Error> { self.u128(v) } fn i128(&mut self, v: &i128) -> Result<(), Error>; 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(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(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) } } impl<'a, 'v, V: InternalVisitor<'v> + ?Sized> InternalVisitor<'v> for &'a mut 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) } 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) } 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) } 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) } 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(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(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) } } impl<'v> ValueBag<'v> { /// Get a value from an internal primitive. pub(crate) fn from_internal(value: T) -> Self where T: Into>, { ValueBag { inner: value.into(), } } /// 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) fn by_ref<'u>(&'u self) -> Internal<'u> { 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), } } #[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), Internal::BigSigned(value) => visitor.i128(value), Internal::BigUnsigned(value) => visitor.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) => value.fill(Slot::new(&mut visitor)), Internal::AnonDebug(value) => visitor.debug(value), Internal::Debug(value) => visitor.debug(value.as_super()), Internal::AnonDisplay(value) => visitor.display(value), Internal::Display(value) => visitor.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()), } } } impl<'v> From<()> for Internal<'v> { #[inline] fn from(_: ()) -> Self { Internal::None } } impl<'v> From for Internal<'v> { #[inline] fn from(v: u8) -> Self { Internal::Unsigned(v as u64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: u16) -> Self { Internal::Unsigned(v as u64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: u32) -> Self { Internal::Unsigned(v as u64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: u64) -> Self { Internal::Unsigned(v) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: usize) -> Self { Internal::Unsigned(v as u64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: i8) -> Self { Internal::Signed(v as i64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: i16) -> Self { Internal::Signed(v as i64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: i32) -> Self { Internal::Signed(v as i64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: i64) -> Self { Internal::Signed(v) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: isize) -> Self { Internal::Signed(v as i64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: f32) -> Self { Internal::Float(v as f64) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: f64) -> Self { Internal::Float(v) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: bool) -> Self { Internal::Bool(v) } } impl<'v> From for Internal<'v> { #[inline] fn from(v: char) -> Self { Internal::Char(v) } } impl<'v> From<&'v str> for Internal<'v> { #[inline] fn from(v: &'v str) -> Self { Internal::Str(v) } } impl<'v> From<&'v ()> for Internal<'v> { #[inline] fn from(_: &'v ()) -> Self { Internal::None } } impl<'v> From<&'v u8> for Internal<'v> { #[inline] fn from(v: &'v u8) -> Self { Internal::Unsigned(*v as u64) } } impl<'v> From<&'v u16> for Internal<'v> { #[inline] fn from(v: &'v u16) -> Self { Internal::Unsigned(*v as u64) } } impl<'v> From<&'v u32> for Internal<'v> { #[inline] fn from(v: &'v u32) -> Self { Internal::Unsigned(*v as u64) } } impl<'v> From<&'v u64> for Internal<'v> { #[inline] fn from(v: &'v u64) -> Self { Internal::Unsigned(*v) } } impl<'v> From<&'v u128> for Internal<'v> { #[inline] fn from(v: &'v u128) -> Self { #[cfg(feature = "inline-i128")] { Internal::BigUnsigned(*v) } #[cfg(not(feature = "inline-i128"))] { Internal::BigUnsigned(v) } } } #[cfg(feature = "inline-i128")] impl<'v> From for Internal<'v> { #[inline] fn from(v: u128) -> Self { Internal::BigUnsigned(v) } } impl<'v> From<&'v usize> for Internal<'v> { #[inline] fn from(v: &'v usize) -> Self { Internal::Unsigned(*v as u64) } } impl<'v> From<&'v i8> for Internal<'v> { #[inline] fn from(v: &'v i8) -> Self { Internal::Signed(*v as i64) } } impl<'v> From<&'v i16> for Internal<'v> { #[inline] fn from(v: &'v i16) -> Self { Internal::Signed(*v as i64) } } impl<'v> From<&'v i32> for Internal<'v> { #[inline] fn from(v: &'v i32) -> Self { Internal::Signed(*v as i64) } } impl<'v> From<&'v i64> for Internal<'v> { #[inline] fn from(v: &'v i64) -> Self { Internal::Signed(*v) } } impl<'v> From<&'v i128> for Internal<'v> { #[inline] fn from(v: &'v i128) -> Self { #[cfg(feature = "inline-i128")] { Internal::BigSigned(*v) } #[cfg(not(feature = "inline-i128"))] { Internal::BigSigned(v) } } } #[cfg(feature = "inline-i128")] impl<'v> From for Internal<'v> { #[inline] fn from(v: i128) -> Self { Internal::BigSigned(v) } } impl<'v> From<&'v isize> for Internal<'v> { #[inline] fn from(v: &'v isize) -> Self { Internal::Signed(*v as i64) } } impl<'v> From<&'v f32> for Internal<'v> { #[inline] fn from(v: &'v f32) -> Self { Internal::Float(*v as f64) } } impl<'v> From<&'v f64> for Internal<'v> { #[inline] fn from(v: &'v f64) -> Self { Internal::Float(*v) } } impl<'v> From<&'v bool> for Internal<'v> { #[inline] fn from(v: &'v bool) -> Self { Internal::Bool(*v) } } impl<'v> From<&'v char> for Internal<'v> { #[inline] fn from(v: &'v char) -> Self { Internal::Char(*v) } } impl<'v, 'u> From<&'v &'u str> for Internal<'v> where 'u: 'v, { #[inline] fn from(v: &'v &'u str) -> Self { Internal::Str(*v) } } #[cfg(feature = "std")] mod std_support { use super::*; use std::string::String; impl<'v> From<&'v String> for Internal<'v> { #[inline] fn from(v: &'v String) -> Self { Internal::Str(&**v) } } } value-bag-1.4.1/src/internal/owned.rs000064400000000000000000000117331046102023000155640ustar 00000000000000use crate::{ internal::{self, Internal, InternalVisitor}, std::boxed::Box, Error, }; #[derive(Clone)] pub(crate) enum OwnedInternal { /// An extra large signed integer. BigSigned(i128), /// An extra large unsigned integer. BigUnsigned(u128), /// A floating point number. Float(f64), /// A boolean value. Bool(bool), /// A UTF8 codepoint. Char(char), /// A UTF8 string. Str(Box), /// An empty value. None, /// A debuggable value. Debug(internal::fmt::owned::OwnedFmt), /// A displayable value. 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), } impl OwnedInternal { pub(crate) fn by_ref<'v>(&'v self) -> Internal<'v> { 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), } } } impl<'v> Internal<'v> { pub(crate) fn to_owned(&self) -> OwnedInternal { struct OwnedVisitor(OwnedInternal); impl<'v> InternalVisitor<'v> for OwnedVisitor { fn debug(&mut self, v: &dyn internal::fmt::Debug) -> Result<(), Error> { self.0 = OwnedInternal::Debug(internal::fmt::owned::buffer_debug(v)); Ok(()) } fn display(&mut self, v: &dyn internal::fmt::Display) -> Result<(), Error> { self.0 = OwnedInternal::Display(internal::fmt::owned::buffer_display(v)); 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 = "sval2")] fn sval2(&mut self, v: &dyn internal::sval::v2::Value) -> Result<(), Error> { self.0 = OwnedInternal::Sval2(internal::sval::v2::owned::buffer(v)); Ok(()) } #[cfg(feature = "serde1")] fn serde1(&mut self, v: &dyn internal::serde::v1::Serialize) -> Result<(), Error> { self.0 = OwnedInternal::Serde1(internal::serde::v1::owned::buffer(v)); Ok(()) } } let mut visitor = OwnedVisitor(OwnedInternal::None); let _ = self.internal_visit(&mut visitor); visitor.0 } } value-bag-1.4.1/src/internal/serde/mod.rs000064400000000000000000000000231046102023000163170ustar 00000000000000pub(crate) mod v1; value-bag-1.4.1/src/internal/serde/v1.rs000064400000000000000000000445711046102023000161060ustar 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 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) 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(_)) | None => Err(Error::serde()), } } fn serializer(&mut self) -> Result { self.inner.take().ok_or_else(|| Error::serde()) } fn into_result(self) -> Result { self.result .unwrap_or_else(|| Err(S::Error::custom("`serde` serialization failed"))) } } impl<'v, S> InternalVisitor<'v> for Serde1Visitor where S: value_bag_serde1::lib::Serializer, { 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() } } let mut visitor = Serde1Visitor { inner: Some(s), result: None, }; self.internal_visit(&mut visitor) .map_err(|e| S::Error::custom(e))?; 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) } pub(crate) fn internal_visit<'v>( v: &dyn Serialize, visitor: &mut dyn InternalVisitor<'v>, ) -> Result<(), Error> { 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)).map_err(|_| Error::serde()) } impl Error { fn serde() -> Self { Error::msg("`serde` serialization failed") } } #[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 = "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) -> OwnedSerialize { Box::new(value_bag_serde1::buf::Owned::buffer(v).unwrap()) } } #[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_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 = "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") ); } } } value-bag-1.4.1/src/internal/sval/mod.rs000064400000000000000000000000231046102023000161620ustar 00000000000000pub(crate) mod v2; value-bag-1.4.1/src/internal/sval/v2.rs000064400000000000000000000361731046102023000157510ustar 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 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 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 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) } } 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>( v: &dyn Value, visitor: &mut dyn InternalVisitor<'v>, ) -> Result<(), Error> { let mut visitor = VisitorStream { visitor, text_buf: Default::default(), }; value_bag_sval2::lib::stream_computed(&mut visitor, v).map_err(Error::from_sval2)?; Ok(()) } pub(crate) fn borrowed_internal_visit<'v>( v: &'v dyn Value, visitor: &mut dyn InternalVisitor<'v>, ) -> Result<(), Error> { let mut visitor = VisitorStream { visitor, text_buf: Default::default(), }; value_bag_sval2::lib::stream(&mut visitor, v).map_err(Error::from_sval2)?; 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 = "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) -> OwnedValue { OwnedValue::collect_owned(v).unwrap() } } #[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_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 = "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") ); } } } value-bag-1.4.1/src/lib.rs000064400000000000000000000326451046102023000134070ustar 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.4.1")] #![no_std] /* # 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")))] mod std { pub use crate::{ alloc::{boxed, string}, core::*, }; } #[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()); /// ``` #[derive(Clone)] pub struct ValueBag<'v> { inner: internal::Internal<'v>, } impl<'v> ValueBag<'v> { /// Get a `ValueBag` from a reference to a `ValueBag`. #[inline] pub fn by_ref<'u>(&'u self) -> ValueBag<'u> { 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.4.1/src/owned.rs000064400000000000000000000102601046102023000137420ustar 00000000000000use crate::{internal, 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(), } } } 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 will change, so downcasting won't work. pub fn by_ref<'v>(&'v self) -> ValueBag<'v> { ValueBag { inner: self.inner.by_ref(), } } } #[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 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(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 = "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 = "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(_))); } } value-bag-1.4.1/src/test.rs000064400000000000000000000135221046102023000136110ustar 00000000000000//! Test support for inspecting values. use crate::{ internal, std::{fmt, str, string::String}, visit::Visit, Error, ValueBag, }; pub(crate) trait IntoValueBag<'v> { fn into_value_bag(self) -> ValueBag<'v>; } 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, }, } 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 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(()) } } 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.4.1/src/visit.rs000064400000000000000000000243651046102023000137770ustar 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 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_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 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_any(ValueBag::from(())) } #[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> { internal::sval::v2::internal_visit(v, self) } #[cfg(feature = "sval2")] fn borrowed_sval2( &mut self, v: &'v dyn internal::sval::v2::Value, ) -> Result<(), Error> { internal::sval::v2::borrowed_internal_visit(v, self) } #[cfg(feature = "serde1")] fn serde1(&mut self, v: &dyn internal::serde::v1::Serialize) -> Result<(), Error> { internal::serde::v1::internal_visit(v, self) } } self.internal_visit(&mut Visitor(visitor)) } } #[cfg(test)] mod tests { use super::*; use crate::test::*; #[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"); } }