diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/beef | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/beef')
| -rw-r--r-- | vendor/beef/.cargo-checksum.json | 1 | ||||
| -rw-r--r-- | vendor/beef/Cargo.toml | 55 | ||||
| -rw-r--r-- | vendor/beef/LICENSE-APACHE | 201 | ||||
| -rw-r--r-- | vendor/beef/LICENSE-MIT | 21 | ||||
| -rw-r--r-- | vendor/beef/README.md | 121 | ||||
| -rw-r--r-- | vendor/beef/benches/bench.rs | 181 | ||||
| -rwxr-xr-x | vendor/beef/ci/miri.sh | 12 | ||||
| -rw-r--r-- | vendor/beef/src/generic.rs | 553 | ||||
| -rw-r--r-- | vendor/beef/src/lean.rs | 69 | ||||
| -rw-r--r-- | vendor/beef/src/lib.rs | 285 | ||||
| -rw-r--r-- | vendor/beef/src/serde.rs | 149 | ||||
| -rw-r--r-- | vendor/beef/src/traits.rs | 175 | ||||
| -rw-r--r-- | vendor/beef/src/wide.rs | 42 |
13 files changed, 1865 insertions, 0 deletions
diff --git a/vendor/beef/.cargo-checksum.json b/vendor/beef/.cargo-checksum.json new file mode 100644 index 00000000..3a0a466a --- /dev/null +++ b/vendor/beef/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b36bcc93cd331f932df3088f291f66a98387c4bf09638795379d1ab22f38bbcc","LICENSE-APACHE":"fe99bc314b2672132fe8b986fdcdf5a4ffb29edfdf6bf79ec88ccc6cbe092b13","LICENSE-MIT":"809a5649163758f9182c72fa09fd50a426b5966dd1b4720915ba024c6b910356","README.md":"01dfa5646b2baba36179b7fe48275eac40b5f5f3cd60f9b4ba3e2903249ed52f","benches/bench.rs":"3ac89c15af14b72e32db96889dbee521f8c3a45de06f7a4febbba55db58a77d8","ci/miri.sh":"8db4f5b506fee85897d4000a51026d09e63447fe0b82cdf2510dbcfb33612297","src/generic.rs":"4036c6f3fd409658083b9cfaa9b52d31f13b7899b687b4aa5eff669d14d12206","src/lean.rs":"c0399c722b61c024783db2b5554b4de004a329f6cf9796ffa92d4dc966d63cc2","src/lib.rs":"f0bb153f21d7259be0d688fcc10489e2f444a0fb352b8ad884bed45234718a95","src/serde.rs":"e8f3bd3f23068b6c3ad7b7557f24bac5b4c503f1dba63eb8e3744ee93315ae90","src/traits.rs":"7f3e37e70c9fd0507a33031587f88ff1672575e6b77891846970bd084797a91c","src/wide.rs":"91b2abbc5a39e9897668cfff4c0bf7ac1b2dd9b1076da0a329f60f174efec065"},"package":"3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"}
\ No newline at end of file diff --git a/vendor/beef/Cargo.toml b/vendor/beef/Cargo.toml new file mode 100644 index 00000000..0e5a1ab8 --- /dev/null +++ b/vendor/beef/Cargo.toml @@ -0,0 +1,55 @@ +# 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 = "2018" +name = "beef" +version = "0.5.2" +authors = ["Maciej Hirsz <hello@maciej.codes>"] +description = "More compact Cow" +documentation = "https://docs.rs/beef/" +readme = "./README.md" +keywords = [ + "cow", + "borrow", + "str", + "slice", +] +categories = [ + "no-std", + "memory-management", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/maciejhirsz/beef" + +[profile.bench] +opt-level = 3 +lto = "fat" +codegen-units = 1 +debug = false +debug-assertions = false + +[dependencies.serde] +version = "1.0.105" +features = ["alloc"] +optional = true +default-features = false + +[dev-dependencies.serde_derive] +version = "1.0.105" + +[dev-dependencies.serde_json] +version = "1.0" + +[features] +const_fn = [] +default = [] +impl_serde = ["serde"] diff --git a/vendor/beef/LICENSE-APACHE b/vendor/beef/LICENSE-APACHE new file mode 100644 index 00000000..efd038e5 --- /dev/null +++ b/vendor/beef/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2020 Maciej Hirsz <hello@maciej.codes> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/beef/LICENSE-MIT b/vendor/beef/LICENSE-MIT new file mode 100644 index 00000000..8c02fab0 --- /dev/null +++ b/vendor/beef/LICENSE-MIT @@ -0,0 +1,21 @@ +Copyright (c) 2020 Maciej Hirsz <hello@maciej.codes> + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/beef/README.md b/vendor/beef/README.md new file mode 100644 index 00000000..73aed63a --- /dev/null +++ b/vendor/beef/README.md @@ -0,0 +1,121 @@ +# beef + +[](https://travis-ci.org/maciejhirsz/beef) +[](https://crates.io/crates/beef) +[](https://crates.io/crates/beef) + +Faster, more compact implementation of `Cow`. + +**[Changelog](https://github.com/maciejhirsz/beef/releases) -** +**[Documentation](https://docs.rs/beef/) -** +**[Cargo](https://crates.io/crates/beef) -** +**[Repository](https://github.com/maciejhirsz/beef)** + +```rust +use beef::Cow; + +let borrowed: Cow<str> = Cow::borrowed("Hello"); +let owned: Cow<str> = Cow::owned(String::from("World")); + +assert_eq!( + format!("{} {}!", borrowed, owned), + "Hello World!", +); +``` + +There are two versions of `Cow` exposed by this crate: + ++ `beef::Cow` is 3 words wide: pointer, length, and capacity. It stores the ownership tag in capacity. ++ `beef::lean::Cow` is 2 words wide, storing length, capacity, and the ownership tag all in one word. + +Both versions are leaner than the `std::borrow::Cow`: + +```rust +use std::mem::size_of; + +const WORD: usize = size_of::<usize>(); + +assert_eq!(size_of::<std::borrow::Cow<str>>(), 4 * WORD); +assert_eq!(size_of::<beef::Cow<str>>(), 3 * WORD); +assert_eq!(size_of::<beef::lean::Cow<str>>(), 2 * WORD); +``` + +## How does it work? + +The standard library `Cow` is an enum with two variants: + +```rust +pub enum Cow<'a, B> where + B: 'a + ToOwned + ?Sized, +{ + Borrowed(&'a B), + Owned(<B as ToOwned>::Owned), +} +``` + +For the most common pairs of values - `&str` and `String`, or `&[u8]` and `Vec<u8>` - this +means that the entire enum is 4 words wide: + +```text + Padding + | + v + +-----------+-----------+-----------+-----------+ +Borrowed: | Tag | Pointer | Length | XXXXXXXXX | + +-----------+-----------+-----------+-----------+ + + +-----------+-----------+-----------+-----------+ +Owned: | Tag | Pointer | Length | Capacity | + +-----------+-----------+-----------+-----------+ +``` + +Instead of being an enum with a tag, `beef::Cow` uses capacity to determine whether the +value it's holding is owned (capacity is greater than 0), or borrowed (capacity is 0). + +`beef::lean::Cow` goes even further and puts length and capacity on a single 64 word. + +```text + +-----------+-----------+-----------+ +beef::Cow | Pointer | Length | Capacity? | + +-----------+-----------+-----------+ + + +-----------+-----------+ +beef::lean::Cow | Pointer | Cap | Len | + +-----------+-----------+ +``` + +Any owned `Vec` or `String` that has 0 capacity is effectively treated as a borrowed +value. Since having no capacity means there is no actual allocation behind the pointer, +this is safe. + +## Benchmarks + +``` +cargo +nightly bench +``` + +Microbenchmarking obtaining a `&str` reference is rather flaky and you can have widely different results. In general the following seems to hold true: + ++ `beef::Cow` and `beef::lean::Cow` are faster than `std::borrow::Cow` at obtaining a reference `&T`. This makes sense since we avoid the enum tag branching. ++ The 3-word `beef::Cow` is faster at creating borrowed variants, but slower at creating owned variants than `std::borrow::Cow`. ++ The 2-word `beef::lean::Cow` is faster at both. + +``` +running 9 tests +test beef_as_ref ... bench: 57 ns/iter (+/- 15) +test beef_create ... bench: 135 ns/iter (+/- 5) +test beef_create_mixed ... bench: 659 ns/iter (+/- 52) +test lean_beef_as_ref ... bench: 50 ns/iter (+/- 2) +test lean_beef_create ... bench: 77 ns/iter (+/- 3) +test lean_beef_create_mixed ... bench: 594 ns/iter (+/- 52) +test std_as_ref ... bench: 70 ns/iter (+/- 6) +test std_create ... bench: 142 ns/iter (+/- 7) +test std_create_mixed ... bench: 663 ns/iter (+/- 32) +``` + +## License + +This crate is distributed under the terms of both the MIT license +and the Apache License (Version 2.0). Choose whichever one works best for you. + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details. diff --git a/vendor/beef/benches/bench.rs b/vendor/beef/benches/bench.rs new file mode 100644 index 00000000..0bf12dd9 --- /dev/null +++ b/vendor/beef/benches/bench.rs @@ -0,0 +1,181 @@ +#![feature(test)] + +extern crate beef; +extern crate test; + +use std::borrow::{Cow as StdCow, ToOwned}; +use test::{black_box, Bencher}; + +const NTH_WORD: usize = 4; +static TEXT: &str = "In less than a half-hour, Joe had distributed ninety-two paper cups of tomato juice containing AUM, the drug that promised to turn neophobes into neophiles. He stood in Pioneer Court, just north of the Michigan Avenue Bridge, at a table from which hung a poster reading FREE TOMATO JUICE. Each person who took a cupful was invited to fill out a short questionnaire and leave it in a box on Joe's table. However, Joe explained, the questionnaire was optional, and anyone who wanted to drink the tomato juice and run was welcome to do so."; + +#[bench] +fn beef_create(b: &mut Bencher) { + use beef::Cow; + + let words: Vec<_> = TEXT.split_whitespace().collect(); + + b.iter(|| { + let cow_words: Vec<Cow<str>> = words.iter().copied().map(Cow::borrowed).collect(); + + black_box(cow_words) + }); +} + +#[bench] +fn beef_create_mixed(b: &mut Bencher) { + use beef::Cow; + + let words: Vec<_> = TEXT.split_whitespace().collect(); + + b.iter(|| { + let cow_words: Vec<Cow<str>> = words + .iter() + .copied() + .map(|word| { + if word.len() % NTH_WORD == 0 { + Cow::owned(word.to_owned()) + } else { + Cow::borrowed(word) + } + }) + .collect(); + + black_box(cow_words) + }); +} + +#[bench] +fn beef_as_ref(b: &mut Bencher) { + use beef::Cow; + + let cow_words: Vec<_> = TEXT + .split_whitespace() + .map(|word| { + if word.len() % NTH_WORD == 0 { + Cow::owned(word.to_owned()) + } else { + Cow::borrowed(word) + } + }) + .collect(); + + b.iter(|| { + for word in cow_words.iter() { + let word: &str = word.as_ref(); + black_box(word); + } + }); +} + +#[bench] +fn lean_beef_create(b: &mut Bencher) { + use beef::lean::Cow; + + let words: Vec<_> = TEXT.split_whitespace().collect(); + + b.iter(|| { + let cow_words: Vec<Cow<str>> = words.iter().copied().map(Cow::borrowed).collect(); + + black_box(cow_words) + }); +} + +#[bench] +fn lean_beef_create_mixed(b: &mut Bencher) { + use beef::lean::Cow; + + let words: Vec<_> = TEXT.split_whitespace().collect(); + + b.iter(|| { + let cow_words: Vec<Cow<str>> = words + .iter() + .copied() + .map(|word| { + if word.len() % NTH_WORD == 0 { + Cow::owned(word.to_owned()) + } else { + Cow::borrowed(word) + } + }) + .collect(); + + black_box(cow_words) + }); +} + +#[bench] +fn lean_beef_as_ref(b: &mut Bencher) { + use beef::lean::Cow; + + let cow_words: Vec<_> = TEXT + .split_whitespace() + .map(|word| { + if word.len() % NTH_WORD == 0 { + Cow::owned(word.to_owned()) + } else { + Cow::borrowed(word) + } + }) + .collect(); + + b.iter(|| { + for word in cow_words.iter() { + let word: &str = word.as_ref(); + black_box(word); + } + }); +} + +#[bench] +fn std_create(b: &mut Bencher) { + let words: Vec<_> = TEXT.split_whitespace().collect(); + + b.iter(|| { + let stdcow_words: Vec<StdCow<str>> = words.iter().copied().map(StdCow::Borrowed).collect(); + + black_box(stdcow_words) + }); +} + +#[bench] +fn std_create_mixed(b: &mut Bencher) { + let words: Vec<_> = TEXT.split_whitespace().collect(); + + b.iter(|| { + let stdcow_words: Vec<StdCow<str>> = words + .iter() + .copied() + .map(|word| { + if word.len() % NTH_WORD == 0 { + StdCow::Owned(word.to_owned()) + } else { + StdCow::Borrowed(word) + } + }) + .collect(); + + black_box(stdcow_words) + }); +} + +#[bench] +fn std_as_ref(b: &mut Bencher) { + let stdcow_words: Vec<_> = TEXT + .split_whitespace() + .map(|word| { + if word.len() % NTH_WORD == 0 { + StdCow::Owned(word.to_owned()) + } else { + StdCow::Borrowed(word) + } + }) + .collect(); + + b.iter(|| { + for word in stdcow_words.iter() { + let word: &str = word.as_ref(); + black_box(word); + } + }); +} diff --git a/vendor/beef/ci/miri.sh b/vendor/beef/ci/miri.sh new file mode 100755 index 00000000..0ffbe96f --- /dev/null +++ b/vendor/beef/ci/miri.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) +echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" +rustup set profile minimal +rustup default "$MIRI_NIGHTLY" + +rustup component add miri +cargo miri setup + +MIRIFLAGS='-Zmiri-strict-provenance' cargo miri test --all-features diff --git a/vendor/beef/src/generic.rs b/vendor/beef/src/generic.rs new file mode 100644 index 00000000..1d7fa2da --- /dev/null +++ b/vendor/beef/src/generic.rs @@ -0,0 +1,553 @@ +//! This module contains the actual, albeit generic, implementaiton of the `Cow`, +//! and the traits that are available to it. + +use alloc::borrow::{Borrow, Cow as StdCow}; +use alloc::string::String; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ptr::NonNull; + +#[cfg(target_pointer_width = "64")] +use crate::lean::internal::Lean; +use crate::traits::{Beef, Capacity}; +use crate::wide::internal::Wide; + +/// A clone-on-write smart pointer, mostly compatible with [`std::borrow::Cow`](https://doc.rust-lang.org/std/borrow/enum.Cow.html). +/// +/// This type is using a generic `U: Capacity`. Use either [`beef::Cow`](../type.Cow.html) or [`beef::lean::Cow`](../lean/type.Cow.html) in your code. +pub struct Cow<'a, T: Beef + ?Sized + 'a, U: Capacity> { + /// Pointer to data + ptr: NonNull<T::PointerT>, + + /// This usize contains length, but it may contain other + /// information pending on impl of `Capacity`, and must therefore + /// always go through `U::len` or `U::unpack` + fat: usize, + + /// Capacity field. For `beef::lean::Cow` this is 0-sized! + cap: U::Field, + + /// Lifetime marker + marker: PhantomData<&'a T>, +} + +impl<T, U> Cow<'_, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + /// Owned data. + /// + /// # Example + /// + /// ```rust + /// use beef::Cow; + /// + /// let owned: Cow<str> = Cow::owned("I own my content".to_string()); + /// ``` + #[inline] + pub fn owned(val: T::Owned) -> Self { + let (ptr, fat, cap) = T::owned_into_parts::<U>(val); + + Cow { + ptr, + fat, + cap, + marker: PhantomData, + } + } +} + +impl<'a, T, U> Cow<'a, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + /// Borrowed data. + /// + /// # Example + /// + /// ```rust + /// use beef::Cow; + /// + /// let borrowed: Cow<str> = Cow::borrowed("I'm just a borrow"); + /// ``` + #[inline] + pub fn borrowed(val: &'a T) -> Self { + let (ptr, fat, cap) = T::ref_into_parts::<U>(val); + + Cow { + ptr, + fat, + cap, + marker: PhantomData, + } + } + + /// Extracts the owned data. + /// + /// Clones the data if it is not already owned. + #[inline] + pub fn into_owned(self) -> T::Owned { + let cow = ManuallyDrop::new(self); + + match cow.capacity() { + Some(capacity) => unsafe { T::owned_from_parts::<U>(cow.ptr, cow.fat, capacity) }, + None => unsafe { &*T::ref_from_parts::<U>(cow.ptr, cow.fat) }.to_owned(), + } + } + + /// Extracts borrowed data. + /// + /// Panics: If the data is owned. + #[inline] + pub fn unwrap_borrowed(self) -> &'a T { + if self.capacity().is_some() { + panic!("Can not turn owned beef::Cow into a borrowed value") + } + unsafe { &*T::ref_from_parts::<U>(self.ptr, self.fat) } + } + + /// Returns `true` if data is borrowed or had no capacity. + /// + /// # Example + /// + /// ```rust + /// use beef::Cow; + /// + /// let borrowed: Cow<str> = Cow::borrowed("Borrowed"); + /// let no_capacity: Cow<str> = Cow::owned(String::new()); + /// let owned: Cow<str> = Cow::owned(String::from("Owned")); + /// + /// assert_eq!(borrowed.is_borrowed(), true); + /// assert_eq!(no_capacity.is_borrowed(), true); + /// assert_eq!(owned.is_borrowed(), false); + /// ``` + #[inline] + pub fn is_borrowed(&self) -> bool { + self.capacity().is_none() + } + + /// Returns `true` if data is owned and has non-0 capacity. + /// + /// # Example + /// + /// ```rust + /// use beef::Cow; + /// + /// let borrowed: Cow<str> = Cow::borrowed("Borrowed"); + /// let no_capacity: Cow<str> = Cow::owned(String::new()); + /// let owned: Cow<str> = Cow::owned(String::from("Owned")); + /// + /// assert_eq!(borrowed.is_owned(), false); + /// assert_eq!(no_capacity.is_owned(), false); + /// assert_eq!(owned.is_owned(), true); + /// ``` + #[inline] + pub fn is_owned(&self) -> bool { + self.capacity().is_some() + } + + /// Internal convenience method for casting `ptr` into a `&T` + #[inline] + fn borrow(&self) -> &T { + unsafe { &*T::ref_from_parts::<U>(self.ptr, self.fat) } + } + + #[inline] + fn capacity(&self) -> Option<U::NonZero> { + U::maybe(self.fat, self.cap) + } +} + +impl<'a> Cow<'a, str, Wide> { + /// Borrowed data. + /// + /// This is functionally identical to [`borrow`](./generic/struct.Cow.html#method.borrow). + /// We use impl specialization to allow this function to be `const`. + /// + /// # Example + /// + /// ```rust + /// use beef::Cow; + /// + /// const HELLO: Cow<str> = Cow::const_str("Hello"); + /// ``` + pub const fn const_str(val: &'a str) -> Self { + Cow { + // We are casting *const T to *mut T, however for all borrowed values + // this raw pointer is only ever dereferenced back to &T. + ptr: unsafe { NonNull::new_unchecked(val.as_ptr() as *mut u8) }, + fat: val.len(), + cap: None, + marker: PhantomData, + } + } +} + +#[cfg(target_pointer_width = "64")] +impl<'a> Cow<'a, str, Lean> { + /// Borrowed data. + /// + /// This is functionally identical to [`borrow`](./generic/struct.Cow.html#method.borrow). + /// We use impl specialization to allow this function to be `const`. + /// + /// # Example + /// + /// ```rust + /// use beef::lean::Cow; + /// + /// const HELLO: Cow<str> = Cow::const_str("Hello"); + /// ``` + pub const fn const_str(val: &'a str) -> Self { + Cow { + // We are casting *const T to *mut T, however for all borrowed values + // this raw pointer is only ever dereferenced back to &T. + ptr: unsafe { NonNull::new_unchecked(val.as_ptr() as *mut u8) }, + fat: Lean::mask_len(val.len()), + cap: Lean, + marker: PhantomData, + } + } +} + +// This requires nightly: +// https://github.com/rust-lang/rust/issues/57563 +#[cfg(feature = "const_fn")] +impl<'a, T> Cow<'a, [T], Wide> +where + T: Clone, +{ + /// Borrowed data. + /// + /// This is functionally identical to [`borrow`](./generic/struct.Cow.html#method.borrow). + /// We use impl specialization to allow this function to be `const`. + /// + /// # Example + /// + /// ```rust + /// use beef::Cow; + /// + /// const HELLO: Cow<[u8]> = Cow::const_slice(&[1, 2, 3]); + /// ``` + pub const fn const_slice(val: &'a [T]) -> Self { + Cow { + // We are casting *const T to *mut T, however for all borrowed values + // this raw pointer is only ever dereferenced back to &T. + ptr: unsafe { NonNull::new_unchecked(val.as_ptr() as *mut T) }, + fat: val.len(), + cap: None, + marker: PhantomData, + } + } +} + +// This requires nightly: +// https://github.com/rust-lang/rust/issues/57563 +#[cfg(all(feature = "const_fn", target_pointer_width = "64"))] +impl<'a, T> Cow<'a, [T], Lean> +where + T: Clone, +{ + /// Borrowed data. + /// + /// This i functionally identical to [`borrow`](./generic/struct.Cow.html#method.borrow). + /// We use impl specialization to allow this function to be `const`. + /// + /// # Example + /// + /// ```rust + /// use beef::lean::Cow; + /// + /// const HELLO: Cow<[u8]> = Cow::const_slice(&[1, 2, 3]); + /// ``` + pub const fn const_slice(val: &'a [T]) -> Self { + Cow { + // We are casting *const T to *mut T, however for all borrowed values + // this raw pointer is only ever dereferenced back to &T. + ptr: unsafe { NonNull::new_unchecked(val.as_ptr() as *mut T) }, + fat: Lean::mask_len(val.len()), + cap: Lean, + marker: PhantomData, + } + } +} + +impl<T, U> Hash for Cow<'_, T, U> +where + T: Hash + Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + self.borrow().hash(state) + } +} + +impl<'a, T, U> Default for Cow<'a, T, U> +where + T: Beef + ?Sized, + U: Capacity, + &'a T: Default, +{ + #[inline] + fn default() -> Self { + Cow::borrowed(Default::default()) + } +} + +impl<T, U> Eq for Cow<'_, T, U> +where + T: Eq + Beef + ?Sized, + U: Capacity, +{ +} + +impl<A, B, U, V> PartialOrd<Cow<'_, B, V>> for Cow<'_, A, U> +where + A: Beef + ?Sized + PartialOrd<B>, + B: Beef + ?Sized, + U: Capacity, + V: Capacity, +{ + #[inline] + fn partial_cmp(&self, other: &Cow<'_, B, V>) -> Option<Ordering> { + PartialOrd::partial_cmp(self.borrow(), other.borrow()) + } +} + +impl<T, U> Ord for Cow<'_, T, U> +where + T: Ord + Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(self.borrow(), other.borrow()) + } +} + +impl<'a, T, U> From<&'a T> for Cow<'a, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn from(val: &'a T) -> Self { + Cow::borrowed(val) + } +} + +impl<U> From<String> for Cow<'_, str, U> +where + U: Capacity, +{ + #[inline] + fn from(s: String) -> Self { + Cow::owned(s) + } +} + +impl<T, U> From<Vec<T>> for Cow<'_, [T], U> +where + T: Clone, + U: Capacity, +{ + #[inline] + fn from(v: Vec<T>) -> Self { + Cow::owned(v) + } +} + +impl<T, U> Drop for Cow<'_, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn drop(&mut self) { + if let Some(capacity) = self.capacity() { + unsafe { T::owned_from_parts::<U>(self.ptr, self.fat, capacity) }; + } + } +} + +impl<'a, T, U> Clone for Cow<'a, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn clone(&self) -> Self { + match self.capacity() { + Some(_) => Cow::owned(self.borrow().to_owned()), + None => Cow { ..*self }, + } + } +} + +impl<T, U> core::ops::Deref for Cow<'_, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + type Target = T; + + #[inline] + fn deref(&self) -> &T { + self.borrow() + } +} + +impl<T, U> AsRef<T> for Cow<'_, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn as_ref(&self) -> &T { + self.borrow() + } +} + +impl<T, U> Borrow<T> for Cow<'_, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn borrow(&self) -> &T { + self.borrow() + } +} + +impl<'a, T, U> From<StdCow<'a, T>> for Cow<'a, T, U> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn from(stdcow: StdCow<'a, T>) -> Self { + match stdcow { + StdCow::Borrowed(v) => Self::borrowed(v), + StdCow::Owned(v) => Self::owned(v), + } + } +} + +impl<'a, T, U> From<Cow<'a, T, U>> for StdCow<'a, T> +where + T: Beef + ?Sized, + U: Capacity, +{ + #[inline] + fn from(cow: Cow<'a, T, U>) -> Self { + let cow = ManuallyDrop::new(cow); + + match cow.capacity() { + Some(capacity) => { + StdCow::Owned(unsafe { T::owned_from_parts::<U>(cow.ptr, cow.fat, capacity) }) + } + None => StdCow::Borrowed(unsafe { &*T::ref_from_parts::<U>(cow.ptr, cow.fat) }), + } + } +} + +impl<A, B, U, V> PartialEq<Cow<'_, B, V>> for Cow<'_, A, U> +where + A: Beef + ?Sized, + B: Beef + ?Sized, + U: Capacity, + V: Capacity, + A: PartialEq<B>, +{ + fn eq(&self, other: &Cow<B, V>) -> bool { + self.borrow() == other.borrow() + } +} + +macro_rules! impl_eq { + ($($(@for< $bounds:tt >)? $ptr:ty => $([$($deref:tt)+])? <$with:ty>,)*) => {$( + impl<U $(, $bounds)*> PartialEq<$with> for Cow<'_, $ptr, U> + where + U: Capacity, + $( $bounds: Clone + PartialEq, )* + { + #[inline] + fn eq(&self, other: &$with) -> bool { + self.borrow() == $($($deref)*)* other + } + } + + impl<U $(, $bounds)*> PartialEq<Cow<'_, $ptr, U>> for $with + where + U: Capacity, + $( $bounds: Clone + PartialEq, )* + { + #[inline] + fn eq(&self, other: &Cow<$ptr, U>) -> bool { + $($($deref)*)* self == other.borrow() + } + } + )*}; +} + +impl_eq! { + str => <str>, + str => [*]<&str>, + str => <String>, + @for<T> [T] => <[T]>, + @for<T> [T] => [*]<&[T]>, + @for<T> [T] => [&**]<Vec<T>>, +} + +impl<T, U> fmt::Debug for Cow<'_, T, U> +where + T: Beef + fmt::Debug + ?Sized, + U: Capacity, +{ + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.borrow().fmt(f) + } +} + +impl<T, U> fmt::Display for Cow<'_, T, U> +where + T: Beef + fmt::Display + ?Sized, + U: Capacity, +{ + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.borrow().fmt(f) + } +} + +// Safety: Same bounds as `std::borrow::Cow`. +unsafe impl<T, U> Sync for Cow<'_, T, U> +where + U: Capacity, + T: Beef + Sync + ?Sized, + T::Owned: Sync, +{ +} + +unsafe impl<T, U> Send for Cow<'_, T, U> +where + U: Capacity, + T: Beef + Sync + ?Sized, + T::Owned: Send, +{ +} + +impl<T, U> Unpin for Cow<'_, T, U> +where + U: Capacity, + T: Beef + ?Sized, + T::Owned: Unpin, +{ +} diff --git a/vendor/beef/src/lean.rs b/vendor/beef/src/lean.rs new file mode 100644 index 00000000..cb3c1943 --- /dev/null +++ b/vendor/beef/src/lean.rs @@ -0,0 +1,69 @@ +//! Namespace containing the 2-word `Cow` implementation. + +use crate::traits::Capacity; + +/// Faster, 2-word `Cow`. This version is available only on 64-bit architecture, +/// and it puts both capacity and length together in a fat pointer. Both length and capacity +/// is limited to 32 bits. +/// +/// # Panics +/// +/// [`Cow::owned`](../generic/struct.Cow.html#method.owned) will panic if capacity is larger than `u32::max_size()`. Use the +/// top level `beef::Cow` if you wish to avoid this problem. +pub type Cow<'a, T> = crate::generic::Cow<'a, T, Lean>; + +pub(crate) mod internal { + #[derive(Clone, Copy, PartialEq, Eq)] + pub struct Lean; +} +use internal::Lean; + +const MASK_LO: usize = u32::MAX as usize; +const MASK_HI: usize = !MASK_LO; + +impl Lean { + #[inline] + pub const fn mask_len(len: usize) -> usize { + len & MASK_LO + } +} + +impl Capacity for Lean { + type Field = Lean; + type NonZero = Lean; + + #[inline] + fn len(fat: usize) -> usize { + fat & MASK_LO + } + + #[inline] + fn empty(len: usize) -> (usize, Lean) { + (len & MASK_LO, Lean) + } + + #[inline] + fn store(len: usize, capacity: usize) -> (usize, Lean) { + if capacity & MASK_HI != 0 { + panic!("beef::lean::Cow: Capacity out of bounds"); + } + + let fat = ((capacity & MASK_LO) << 32) | (len & MASK_LO); + + (fat, Lean) + } + + #[inline] + fn unpack(fat: usize, _: Lean) -> (usize, usize) { + (fat & MASK_LO, (fat & MASK_HI) >> 32) + } + + #[inline] + fn maybe(fat: usize, _: Lean) -> Option<Lean> { + if fat & MASK_HI != 0 { + Some(Lean) + } else { + None + } + } +} diff --git a/vendor/beef/src/lib.rs b/vendor/beef/src/lib.rs new file mode 100644 index 00000000..62a503a3 --- /dev/null +++ b/vendor/beef/src/lib.rs @@ -0,0 +1,285 @@ +//! Faster, more compact implementation of `Cow`. +//! +//! **[Changelog](https://github.com/maciejhirsz/beef/releases) -** +//! **[Cargo](https://crates.io/crates/beef) -** +//! **[Repository](https://github.com/maciejhirsz/beef)** +//! +//! ```rust +//! use beef::Cow; +//! +//! let borrowed: Cow<str> = Cow::borrowed("Hello"); +//! let owned: Cow<str> = Cow::owned(String::from("World")); +//! +//! assert_eq!( +//! format!("{} {}!", borrowed, owned), +//! "Hello World!", +//! ); +//! ``` +//! +//! There are two versions of `Cow` exposed by this crate: +//! +//! + `beef::Cow` is 3 words wide: pointer, length, and capacity. It stores the ownership tag in capacity. +//! + `beef::lean::Cow` is 2 words wide, storing length, capacity, and the ownership tag all in one word. +//! +//! Both versions are leaner than the `std::borrow::Cow`: +//! +//! ```rust +//! use std::mem::size_of; +//! +//! const WORD: usize = size_of::<usize>(); +//! +//! assert_eq!(size_of::<std::borrow::Cow<str>>(), 4 * WORD); +//! assert_eq!(size_of::<beef::Cow<str>>(), 3 * WORD); +//! +//! // Lean variant is two words on 64-bit architecture +//! #[cfg(target_pointer_width = "64")] +//! assert_eq!(size_of::<beef::lean::Cow<str>>(), 2 * WORD); +//! ``` +#![cfg_attr(feature = "const_fn", feature(const_fn_trait_bound))] +#![warn(missing_docs)] +#![cfg_attr(not(test), no_std)] +extern crate alloc; + +mod traits; +mod wide; + +#[cfg(feature = "impl_serde")] +mod serde; + +pub mod generic; +#[cfg(target_pointer_width = "64")] +pub mod lean; + +#[cfg(not(target_pointer_width = "64"))] +pub mod lean { + /// Re-exports 3-word Cow for non-64-bit targets + pub use super::wide::Cow; +} + +pub use wide::Cow; + +#[rustfmt::skip] +macro_rules! test { ($tmod:ident => $cow:path) => { + #[cfg(test)] + mod $tmod { + use $cow; + + #[test] + fn borrowed_str() { + let s = "Hello World"; + let c = Cow::borrowed(s); + + assert_eq!(s, c); + assert_eq!(s, c.as_ref()); + assert_eq!(s, &*c); + } + + #[test] + fn owned_string() { + let s = String::from("Hello World"); + let c: Cow<str> = Cow::owned(s.clone()); + + assert_eq!(s, c); + } + + #[test] + fn into_owned() { + let hello = "Hello World"; + let borrowed = Cow::borrowed(hello); + let owned: Cow<str> = Cow::owned(String::from(hello)); + + assert_eq!(borrowed.into_owned(), hello); + assert_eq!(owned.into_owned(), hello); + } + + #[test] + fn borrowed_slice() { + let s: &[_] = &[1, 2, 42]; + let c = Cow::borrowed(s); + + assert_eq!(s, c); + assert_eq!(s, c.as_ref()); + assert_eq!(s, &*c); + } + + #[test] + fn owned_slice() { + let s = vec![1, 2, 42]; + let c: Cow<[_]> = Cow::owned(s.clone()); + + assert_eq!(s, c); + } + + #[test] + fn into_owned_vec() { + let hello: &[u8] = b"Hello World"; + let borrowed = Cow::borrowed(hello); + let owned: Cow<[u8]> = Cow::owned(hello.to_vec()); + + assert_eq!(borrowed.into_owned(), hello); + assert_eq!(owned.into_owned(), hello); + } + + #[test] + fn hash() { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + let slice = "Hello World!"; + let borrowed = Cow::borrowed(slice); + let owned: Cow<str> = Cow::owned(slice.to_owned()); + + let hash1 = { + let mut hasher = DefaultHasher::default(); + + slice.hash(&mut hasher); + + hasher.finish() + }; + + let hash2 = { + let mut hasher = DefaultHasher::default(); + + borrowed.hash(&mut hasher); + + hasher.finish() + }; + + let hash3 = { + let mut hasher = DefaultHasher::default(); + + owned.hash(&mut hasher); + + hasher.finish() + }; + + assert_eq!(hash1, hash2); + assert_eq!(hash1, hash3); + assert_eq!(hash2, hash3); + } + + #[test] + fn ord_and_partial_ord() { + use std::cmp::Ordering; + + macro_rules! generate_order_tests { + ( $f:tt => $order:expr => $left:expr, $right:expr ) => { + assert_eq!( + Cow::<str>::borrowed($left).$f(&Cow::<str>::borrowed($right)), + $order + ); + + assert_eq!( + Cow::<str>::owned($left.to_owned()) + .$f(&Cow::<str>::borrowed($right)), + $order + ); + + assert_eq!( + Cow::<str>::borrowed($left) + .$f(&Cow::<str>::owned($right.to_owned())), + $order + ); + + assert_eq!( + Cow::<str>::owned($left.to_owned()) + .$f(&Cow::<str>::owned($right.to_owned())), + $order + ); + } + } + + generate_order_tests!(partial_cmp => Some(Ordering::Equal) => "a", "a"); + generate_order_tests!(partial_cmp => Some(Ordering::Less) => "a", "b"); + generate_order_tests!(partial_cmp => Some(Ordering::Greater) => "b", "a"); + + generate_order_tests!(cmp => Ordering::Equal => "a", "a"); + generate_order_tests!(cmp => Ordering::Less => "a", "b"); + generate_order_tests!(cmp => Ordering::Greater => "b", "a"); + } + + #[test] + fn from_std_cow() { + let std = std::borrow::Cow::Borrowed("Hello World"); + let beef = Cow::from(std.clone()); + + assert_eq!(&*std, &*beef); + } + + #[test] + fn unwrap_borrowed() { + let borrowed = Cow::borrowed("Hello"); + + assert_eq!(borrowed.unwrap_borrowed(), "Hello"); + } + + #[test] + #[should_panic] + fn unwrap_owned() { + let borrowed: Cow<str> = Cow::owned("Hello".to_string()); + + borrowed.unwrap_borrowed(); + } + + #[test] + fn stress_test_owned() { + let mut expected = String::from("Hello... "); + let mut cow: Cow<str> = Cow::borrowed("Hello... "); + + #[cfg(not(miri))] + let iterations = 1024; + #[cfg(miri)] + let iterations = 10; + + for i in 0..iterations { + if i % 3 == 0 { + let old = cow; + cow = old.clone(); + + std::mem::drop(old); + } + + let mut owned = cow.into_owned(); + + expected.push_str("Hello?.. "); + owned.push_str("Hello?.. "); + + cow = owned.into(); + } + + assert_eq!(expected, cow.into_owned()); + } + + #[test] + fn const_fn_str() { + const HELLO: Cow<str> = Cow::const_str("Hello"); + + assert_eq!(&*HELLO, "Hello"); + } + + #[test] + #[cfg(feature = "const_fn")] + fn const_fn_slice() { + const FOO: Cow<[u8]> = Cow::const_slice(b"bar"); + + assert_eq!(&*FOO, b"bar"); + } + + #[test] + fn default_str() { + let empty: Cow<str> = Default::default(); + + assert_eq!(&*empty, ""); + } + + #[test] + fn default_slice() { + let empty: Cow<[u8]> = Default::default(); + + assert_eq!(&*empty, b""); + } + } +} } + +test!(test_wide => crate::wide::Cow); +test!(test_lean => crate::lean::Cow); diff --git a/vendor/beef/src/serde.rs b/vendor/beef/src/serde.rs new file mode 100644 index 00000000..a85fbc6f --- /dev/null +++ b/vendor/beef/src/serde.rs @@ -0,0 +1,149 @@ +use alloc::{borrow::ToOwned, string::String}; +use core::{fmt, marker::PhantomData}; + +use serde::de::{self, Deserialize, Deserializer, Visitor}; +use serde::ser::{Serialize, Serializer}; + +use crate::generic::Cow; +use crate::traits::internal::{Beef, Capacity}; + +impl<T, U> Serialize for Cow<'_, T, U> +where + T: Beef + Serialize + ?Sized, + U: Capacity, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + T::serialize(self.as_ref(), serializer) + } +} + +struct CowVisitor<'de, 'a, T: Beef + ?Sized, U: Capacity>( + PhantomData<fn() -> (&'de T, Cow<'a, T, U>)>, +); + +impl<'de, 'a, U> Visitor<'de> for CowVisitor<'de, 'a, str, U> +where + 'de: 'a, + U: Capacity, +{ + type Value = Cow<'a, str, U>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Cow::borrowed(value)) + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Cow::owned(value.to_owned())) + } + + fn visit_string<E>(self, value: String) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Cow::owned(value)) + } +} + +impl<'de, 'a, U> Deserialize<'de> for Cow<'a, str, U> +where + 'de: 'a, + U: Capacity, +{ + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(CowVisitor::<'de, 'a, str, U>(PhantomData)) + } +} + +impl<'de, 'a, T, U> Deserialize<'de> for Cow<'a, [T], U> +where + [T]: Beef, + U: Capacity, + <[T] as ToOwned>::Owned: Deserialize<'de>, +{ + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + <[T] as ToOwned>::Owned::deserialize(deserializer).map(Cow::owned) + } +} + +#[cfg(test)] +mod tests { + use serde_derive::{Deserialize, Serialize}; + + #[test] + fn wide_cow_de() { + use crate::Cow; + + #[derive(Serialize, Deserialize)] + struct Test<'a> { + #[serde(borrow)] + foo: Cow<'a, str>, + bar: Cow<'a, str>, + } + + let json = r#"{"foo":"Hello","bar":"\tWorld!"}"#; + let test: Test = serde_json::from_str(json).unwrap(); + + assert_eq!(test.foo, "Hello"); + assert_eq!(test.bar, "\tWorld!"); + + assert!(test.foo.is_borrowed()); + assert!(test.bar.is_owned()); + + let out = serde_json::to_string(&test).unwrap(); + + assert_eq!(json, out); + } + + #[test] + fn wide_cow_direct() { + use crate::Cow; + + let json = r#""foo""#; + let cow: Cow<str> = serde_json::from_str(json).unwrap(); + + assert_eq!(cow, "foo"); + + assert!(cow.is_borrowed()); + + let json = r#""\tfoo""#; + let cow: Cow<str> = serde_json::from_str(json).unwrap(); + + assert_eq!(cow, "\tfoo"); + + assert!(cow.is_owned()); + } + + #[test] + fn wide_cow_direct_bytes() { + use crate::Cow; + + let json = r#"[102, 111, 111]"#; + let cow: Cow<[u8]> = serde_json::from_str(json).unwrap(); + + assert_eq!(cow, &b"foo"[..]); + + // We need to stay generic over `[T]`, so no specialization for byte slices + assert!(cow.is_owned()); + } +} diff --git a/vendor/beef/src/traits.rs b/vendor/beef/src/traits.rs new file mode 100644 index 00000000..4be2d2d0 --- /dev/null +++ b/vendor/beef/src/traits.rs @@ -0,0 +1,175 @@ +pub(crate) use internal::Beef; +pub(crate) use internal::Capacity; + +pub(crate) mod internal { + use alloc::borrow::ToOwned; + use alloc::string::String; + use alloc::vec::Vec; + use core::mem::ManuallyDrop; + use core::ptr::{slice_from_raw_parts, NonNull}; + + pub trait Capacity { + type Field: Copy; + type NonZero: Copy; + + fn len(fat: usize) -> usize; + + fn empty(len: usize) -> (usize, Self::Field); + + fn store(len: usize, capacity: usize) -> (usize, Self::Field); + + fn unpack(fat: usize, capacity: Self::NonZero) -> (usize, usize); + + fn maybe(fat: usize, capacity: Self::Field) -> Option<Self::NonZero>; + } + + /// Helper trait required by `Cow<T>` to extract capacity of owned + /// variant of `T`, and manage conversions. + /// + /// This can be only implemented on types that match requirements: + /// + /// + `T::Owned` has a `capacity`, which is an extra word that is absent in `T`. + /// + `T::Owned` with `capacity` of `0` does not allocate memory. + /// + `T::Owned` can be reconstructed from `*mut T` borrowed out of it, plus capacity. + pub unsafe trait Beef: ToOwned { + type PointerT; + + fn ref_into_parts<U>(&self) -> (NonNull<Self::PointerT>, usize, U::Field) + where + U: Capacity; + + unsafe fn ref_from_parts<U>(ptr: NonNull<Self::PointerT>, len: usize) -> *const Self + where + U: Capacity; + + /// Convert `T::Owned` to `NonNull<T>` and capacity. + /// Return `None` for `0` capacity. + fn owned_into_parts<U>(owned: Self::Owned) -> (NonNull<Self::PointerT>, usize, U::Field) + where + U: Capacity; + + /// Rebuild `T::Owned` from `NonNull<T>` and `capacity`. This can be done by the likes + /// of [`Vec::from_raw_parts`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts). + unsafe fn owned_from_parts<U>( + ptr: NonNull<Self::PointerT>, + fat: usize, + capacity: U::NonZero, + ) -> Self::Owned + where + U: Capacity; + } + + unsafe impl Beef for str { + type PointerT = u8; + + #[inline] + fn ref_into_parts<U>(&self) -> (NonNull<u8>, usize, U::Field) + where + U: Capacity, + { + let (fat, cap) = U::empty(self.len()); + + // A note on soundness: + // + // We are casting *const T to *mut T, however for all borrowed values + // this raw pointer is only ever dereferenced back to &T. + ( + unsafe { NonNull::new_unchecked(self.as_ptr() as *mut u8) }, + fat, + cap, + ) + } + + #[inline] + unsafe fn ref_from_parts<U>(ptr: NonNull<u8>, fat: usize) -> *const str + where + U: Capacity, + { + slice_from_raw_parts(ptr.as_ptr(), U::len(fat)) as *const str + } + + #[inline] + fn owned_into_parts<U>(owned: String) -> (NonNull<u8>, usize, U::Field) + where + U: Capacity, + { + // Convert to `String::into_raw_parts` once stabilized + // We need to go through Vec here to get provenance for the entire allocation + // instead of just the initialized parts. + let mut owned = ManuallyDrop::new(owned.into_bytes()); + let (fat, cap) = U::store(owned.len(), owned.capacity()); + + ( + unsafe { NonNull::new_unchecked(owned.as_mut_ptr()) }, + fat, + cap, + ) + } + + #[inline] + unsafe fn owned_from_parts<U>(ptr: NonNull<u8>, fat: usize, capacity: U::NonZero) -> String + where + U: Capacity, + { + let (len, cap) = U::unpack(fat, capacity); + + String::from_utf8_unchecked(Vec::from_raw_parts(ptr.as_ptr(), len, cap)) + } + } + + unsafe impl<T: Clone> Beef for [T] { + type PointerT = T; + + #[inline] + fn ref_into_parts<U>(&self) -> (NonNull<T>, usize, U::Field) + where + U: Capacity, + { + let (fat, cap) = U::empty(self.len()); + + // A note on soundness: + // + // We are casting *const T to *mut T, however for all borrowed values + // this raw pointer is only ever dereferenced back to &T. + ( + unsafe { NonNull::new_unchecked(self.as_ptr() as *mut T) }, + fat, + cap, + ) + } + + #[inline] + unsafe fn ref_from_parts<U>(ptr: NonNull<T>, fat: usize) -> *const [T] + where + U: Capacity, + { + slice_from_raw_parts(ptr.as_ptr(), U::len(fat)) + } + + #[inline] + fn owned_into_parts<U>(owned: Vec<T>) -> (NonNull<T>, usize, U::Field) + where + U: Capacity, + { + // Convert to `Vec::into_raw_parts` once stabilized + let mut owned = ManuallyDrop::new(owned); + let (fat, cap) = U::store(owned.len(), owned.capacity()); + + ( + unsafe { NonNull::new_unchecked(owned.as_mut_ptr()) }, + fat, + cap, + ) + } + + #[inline] + unsafe fn owned_from_parts<U>(ptr: NonNull<T>, fat: usize, capacity: U::NonZero) -> Vec<T> + where + U: Capacity, + { + let (len, cap) = U::unpack(fat, capacity); + + Vec::from_raw_parts(ptr.as_ptr(), len, cap) + } + } +} diff --git a/vendor/beef/src/wide.rs b/vendor/beef/src/wide.rs new file mode 100644 index 00000000..466e594c --- /dev/null +++ b/vendor/beef/src/wide.rs @@ -0,0 +1,42 @@ +use crate::traits::Capacity; +use core::num::NonZeroUsize; + +/// Compact three word `Cow` that puts the ownership tag in capacity. +/// This is a type alias, for documentation see [`beef::generic::Cow`](./generic/struct.Cow.html). +pub type Cow<'a, T> = crate::generic::Cow<'a, T, Wide>; + +pub(crate) mod internal { + #[derive(Clone, Copy, PartialEq, Eq)] + pub struct Wide; +} +use internal::Wide; + +impl Capacity for Wide { + type Field = Option<NonZeroUsize>; + type NonZero = NonZeroUsize; + + #[inline] + fn len(fat: usize) -> usize { + fat + } + + #[inline] + fn empty(len: usize) -> (usize, Self::Field) { + (len, None) + } + + #[inline] + fn store(len: usize, capacity: usize) -> (usize, Self::Field) { + (len, NonZeroUsize::new(capacity)) + } + + #[inline] + fn unpack(fat: usize, capacity: NonZeroUsize) -> (usize, usize) { + (fat, capacity.get()) + } + + #[inline] + fn maybe(_: usize, capacity: Option<NonZeroUsize>) -> Option<NonZeroUsize> { + capacity + } +} |
