diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /vendor/powerfmt | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/powerfmt')
-rw-r--r-- | vendor/powerfmt/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/powerfmt/Cargo.toml | 59 | ||||
-rw-r--r-- | vendor/powerfmt/LICENSE-Apache | 202 | ||||
-rw-r--r-- | vendor/powerfmt/LICENSE-MIT | 19 | ||||
-rw-r--r-- | vendor/powerfmt/README.md | 45 | ||||
-rw-r--r-- | vendor/powerfmt/src/buf.rs | 198 | ||||
-rw-r--r-- | vendor/powerfmt/src/ext.rs | 54 | ||||
-rw-r--r-- | vendor/powerfmt/src/lib.rs | 15 | ||||
-rw-r--r-- | vendor/powerfmt/src/smart_display.rs | 695 | ||||
-rw-r--r-- | vendor/powerfmt/src/smart_display_impls.rs | 303 |
10 files changed, 1591 insertions, 0 deletions
diff --git a/vendor/powerfmt/.cargo-checksum.json b/vendor/powerfmt/.cargo-checksum.json new file mode 100644 index 000000000..15fec1302 --- /dev/null +++ b/vendor/powerfmt/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"59fa10abb1a34f70e61c97022938b02ec77ea0b161524f4a2599440bd3190c3b","LICENSE-Apache":"155420c6403d4e0fca34105e3c03fdd6939b64c393c7ec6f95f5b72c5474eab0","LICENSE-MIT":"070dbc7dda03a29296f2d58bdb9b7331af90f2abc9f31df22875d1eabaf29852","README.md":"188fa8a1323086828b9eeaf5a2031d66f066b617fc7dec318835a685d7c2e3c7","src/buf.rs":"b76bcb3daff67ed24e3e5fd958d98565c753107d368c3204ae0d70f9ca7394d4","src/ext.rs":"e6e5063f0006bfe92b59712032d4c6dfe1e1d302d8c92596f3eb7b42f747b9b4","src/lib.rs":"b7a6d061f8d79ed7d78088edefb5946d8eb911b1b523ef849f5f989533955b03","src/smart_display.rs":"44d89db6dbefc1b90e2e3e42279d9ae58f77baeab27a30cafebdb84bfdfaf03c","src/smart_display_impls.rs":"833c5dcb851f7979b222f4736e704ab50bba4d42ef264253dc57237381ef0e5b"},"package":"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"}
\ No newline at end of file diff --git a/vendor/powerfmt/Cargo.toml b/vendor/powerfmt/Cargo.toml new file mode 100644 index 000000000..f7acec394 --- /dev/null +++ b/vendor/powerfmt/Cargo.toml @@ -0,0 +1,59 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.67.0" +name = "powerfmt" +version = "0.2.0" +authors = ["Jacob Pratt <jacob@jhpratt.dev>"] +description = """ + `powerfmt` is a library that provides utilities for formatting values. This crate makes it + significantly easier to support filling to a minimum width with alignment, avoid heap + allocation, and avoid repetitive calculations. +""" +readme = "README.md" +keywords = [ + "display", + "format", + "fmt", + "formatter", + "extension", +] +categories = [ + "no-std", + "no-std::no-alloc", + "rust-patterns", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/jhpratt/powerfmt" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "__powerfmt_docs", + "--generate-link-to-definition", +] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies.powerfmt-macros] +version = "=0.1.0" +optional = true + +[features] +alloc = [] +default = [ + "std", + "macros", +] +macros = ["dep:powerfmt-macros"] +std = ["alloc"] diff --git a/vendor/powerfmt/LICENSE-Apache b/vendor/powerfmt/LICENSE-Apache new file mode 100644 index 000000000..ddde1f9a0 --- /dev/null +++ b/vendor/powerfmt/LICENSE-Apache @@ -0,0 +1,202 @@ + + 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 2023 Jacob Pratt et al. + + 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/powerfmt/LICENSE-MIT b/vendor/powerfmt/LICENSE-MIT new file mode 100644 index 000000000..89c1f78cb --- /dev/null +++ b/vendor/powerfmt/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2023 Jacob Pratt et al. + +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/powerfmt/README.md b/vendor/powerfmt/README.md new file mode 100644 index 000000000..c22a3e2fe --- /dev/null +++ b/vendor/powerfmt/README.md @@ -0,0 +1,45 @@ +# `powerfmt` + +[![minimum rustc: 1.65](https://img.shields.io/badge/minimum%20rustc-1.65-yellowgreen?logo=rust&style=flat-square)](https://www.whatrustisit.com) +[![version](https://img.shields.io/crates/v/powerfmt?color=blue&logo=rust&style=flat-square)](https://crates.io/crates/powerfmt) +[![build status](https://img.shields.io/github/actions/workflow/status/jhpratt/powerfmt/build.yaml?branch=main&style=flat-square)](https://github.com/jhpratt/powerfmt/actions) + +Documentation is available [on docs.rs](https://docs.rs/powerfmt). + +## Minimum Rust version policy + +`powerfmt` is guaranteed to compile with the latest stable release of Rust in addition to the two +prior minor releases. For example, if the latest stable Rust release is 1.70, then `powerfmt` is +guaranteed to compile with Rust 1.68, 1.69, and 1.70. + +The minimum supported Rust version may be increased to one of the aforementioned versions if doing +so provides the end user a benefit. However, the minimum supported Rust version may also be bumped +to a version four minor releases prior to the most recent stable release if doing so improves code +quality or maintainability. + +For interoperability with third-party crates, it is guaranteed that there exists a version of that +crate that supports the minimum supported Rust version of `powerfmt`. This does not mean that the +latest version of the third-party crate supports the minimum supported Rust version of `powerfmt`. + +## Contributing + +Contributions are always welcome! If you have an idea, it's best to float it by me before working on +it to ensure no effort is wasted. If there's already an open issue for it, knock yourself out. + +If you have any questions, feel free to use [Discussions]. Don't hesitate to ask questions — that's +what I'm here for! + +[Discussions]: https://github.com/jhpratt/powerfmt/discussions + +## License + +This project is licensed under either of + +- [Apache License, Version 2.0](https://github.com/jhpratt/powerfmt/blob/main/LICENSE-Apache) +- [MIT license](https://github.com/jhpratt/powerfmt/blob/main/LICENSE-MIT) + +at your option. + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in +time by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/vendor/powerfmt/src/buf.rs b/vendor/powerfmt/src/buf.rs new file mode 100644 index 000000000..5a57a60a3 --- /dev/null +++ b/vendor/powerfmt/src/buf.rs @@ -0,0 +1,198 @@ +//! A buffer for constructing a string while avoiding heap allocation. + +use core::hash::{Hash, Hasher}; +use core::mem::MaybeUninit; +use core::{fmt, str}; + +use crate::smart_display::{FormatterOptions, Metadata, SmartDisplay}; + +/// A buffer for construct a string while avoiding heap allocation. +/// +/// The only requirement is that the buffer is large enough to hold the formatted string. +pub struct WriteBuffer<const SIZE: usize> { + buf: [MaybeUninit<u8>; SIZE], + len: usize, +} + +impl<const SIZE: usize> fmt::Debug for WriteBuffer<SIZE> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DisplayBuffer") + .field("buf", &self.as_str()) + .field("remaining_capacity", &self.remaining_capacity()) + .finish() + } +} + +impl<const SIZE: usize> WriteBuffer<SIZE> { + /// Creates an empty buffer. + pub const fn new() -> Self { + Self { + buf: maybe_uninit_uninit_array::<_, SIZE>(), + len: 0, + } + } + + /// Obtain the contents of the buffer as a string. + pub fn as_str(&self) -> &str { + self + } + + /// Determine how many bytes are remaining in the buffer. + pub const fn remaining_capacity(&self) -> usize { + SIZE - self.len + } +} + +impl<const SIZE: usize> Default for WriteBuffer<SIZE> { + fn default() -> Self { + Self::new() + } +} + +impl<const LEFT_SIZE: usize, const RIGHT_SIZE: usize> PartialOrd<WriteBuffer<RIGHT_SIZE>> + for WriteBuffer<LEFT_SIZE> +{ + fn partial_cmp(&self, other: &WriteBuffer<RIGHT_SIZE>) -> Option<core::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<const LEFT_SIZE: usize, const RIGHT_SIZE: usize> PartialEq<WriteBuffer<RIGHT_SIZE>> + for WriteBuffer<LEFT_SIZE> +{ + fn eq(&self, other: &WriteBuffer<RIGHT_SIZE>) -> bool { + self.as_str() == other.as_str() + } +} + +impl<const SIZE: usize> Eq for WriteBuffer<SIZE> {} + +impl<const SIZE: usize> Ord for WriteBuffer<SIZE> { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<const SIZE: usize> Hash for WriteBuffer<SIZE> { + fn hash<H: Hasher>(&self, state: &mut H) { + self.as_str().hash(state) + } +} + +impl<const SIZE: usize> AsRef<str> for WriteBuffer<SIZE> { + fn as_ref(&self) -> &str { + self + } +} + +impl<const SIZE: usize> AsRef<[u8]> for WriteBuffer<SIZE> { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<const SIZE: usize> core::borrow::Borrow<str> for WriteBuffer<SIZE> { + fn borrow(&self) -> &str { + self + } +} + +impl<const SIZE: usize> core::ops::Deref for WriteBuffer<SIZE> { + type Target = str; + + fn deref(&self) -> &Self::Target { + // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation which + // writes a valid UTF-8 string to `buf` and correctly sets `len`. + unsafe { + let s = maybe_uninit_slice_assume_init_ref(&self.buf[..self.len]); + str::from_utf8_unchecked(s) + } + } +} + +impl<const SIZE: usize> fmt::Display for WriteBuffer<SIZE> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self) + } +} + +impl<const SIZE: usize> SmartDisplay for WriteBuffer<SIZE> { + type Metadata = (); + + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + Metadata::new(self.len, self, ()) + } + + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad(self) + } +} + +impl<const SIZE: usize> fmt::Write for WriteBuffer<SIZE> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let bytes = s.as_bytes(); + + if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) { + maybe_uninit_write_slice(buf, bytes); + self.len += bytes.len(); + Ok(()) + } else { + Err(fmt::Error) + } + } +} + +/// Equivalent of [`MaybeUninit::uninit_array`] that compiles on stable. +#[must_use] +#[inline(always)] +const fn maybe_uninit_uninit_array<T, const N: usize>() -> [MaybeUninit<T>; N] { + // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. + unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() } +} + +/// Equivalent of [`MaybeUninit::write_slice`] that compiles on stable. +fn maybe_uninit_write_slice<'a, T>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T] +where + T: Copy, +{ + #[allow(trivial_casts)] + // SAFETY: T and MaybeUninit<T> have the same layout + let uninit_src = unsafe { &*(src as *const [T] as *const [MaybeUninit<T>]) }; + + this.copy_from_slice(uninit_src); + + // SAFETY: Valid elements have just been copied into `this` so it is initialized + unsafe { maybe_uninit_slice_assume_init_mut(this) } +} + +/// Equivalent of [`MaybeUninit::slice_assume_init_mut`] that compiles on stable. +/// +/// # Safety +/// +/// See [`MaybeUninit::slice_assume_init_mut`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.slice_assume_init_mut). +#[inline(always)] +unsafe fn maybe_uninit_slice_assume_init_mut<T, U>(slice: &mut [MaybeUninit<T>]) -> &mut [U] { + #[allow(trivial_casts)] + // SAFETY: similar to safety notes for `slice_get_ref`, but we have a mutable reference which is + // also guaranteed to be valid for writes. + unsafe { + &mut *(slice as *mut [MaybeUninit<T>] as *mut [U]) + } +} + +/// Equivalent of [`MaybeUninit::slice_assume_init_ref`] that compiles on stable. +/// +/// # Safety +/// +/// See [`MaybeUninit::slice_assume_init_ref`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.slice_assume_init_ref). +#[inline(always)] +const unsafe fn maybe_uninit_slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] { + #[allow(trivial_casts)] + // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that `slice` is + // initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`. The pointer + // obtained is valid since it refers to memory owned by `slice` which is a reference and thus + // guaranteed to be valid for reads. + unsafe { + &*(slice as *const [MaybeUninit<T>] as *const [T]) + } +} diff --git a/vendor/powerfmt/src/ext.rs b/vendor/powerfmt/src/ext.rs new file mode 100644 index 000000000..20af7c0aa --- /dev/null +++ b/vendor/powerfmt/src/ext.rs @@ -0,0 +1,54 @@ +//! Extension traits. + +use core::fmt::{Alignment, Arguments, Formatter, Result, Write}; + +mod sealed { + pub trait Sealed {} + + impl Sealed for core::fmt::Formatter<'_> {} +} + +/// An extension trait for [`core::fmt::Formatter`]. +pub trait FormatterExt: sealed::Sealed { + /// Writes the given arguments to the formatter, padding them with the given width. If `width` + /// is incorrect, the resulting output will not be the requested width. + fn pad_with_width(&mut self, width: usize, args: Arguments<'_>) -> Result; +} + +impl FormatterExt for Formatter<'_> { + fn pad_with_width(&mut self, args_width: usize, args: Arguments<'_>) -> Result { + let Some(final_width) = self.width() else { + // The caller has not requested a width. Write the arguments as-is. + return self.write_fmt(args); + }; + let Some(fill_width @ 1..) = final_width.checked_sub(args_width) else { + // No padding will be present. Write the arguments as-is. + return self.write_fmt(args); + }; + + let alignment = self.align().unwrap_or(Alignment::Left); + let fill = self.fill(); + + let left_fill_width = match alignment { + Alignment::Left => 0, + Alignment::Right => fill_width, + Alignment::Center => fill_width / 2, + }; + let right_fill_width = match alignment { + Alignment::Left => fill_width, + Alignment::Right => 0, + // When the fill is not even on both sides, the extra fill goes on the right. + Alignment::Center => (fill_width + 1) / 2, + }; + + for _ in 0..left_fill_width { + self.write_char(fill)?; + } + self.write_fmt(args)?; + for _ in 0..right_fill_width { + self.write_char(fill)?; + } + + Ok(()) + } +} diff --git a/vendor/powerfmt/src/lib.rs b/vendor/powerfmt/src/lib.rs new file mode 100644 index 000000000..0cd6f7cbb --- /dev/null +++ b/vendor/powerfmt/src/lib.rs @@ -0,0 +1,15 @@ +//! `powerfmt` is a library that provides utilities for formatting values. Specifically, it makes it +//! significantly easier to support filling to a minimum width with alignment, avoid heap +//! allocation, and avoid repetitive calculations. + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(__powerfmt_docs, feature(doc_auto_cfg, rustc_attrs))] +#![cfg_attr(__powerfmt_docs, allow(internal_features))] + +#[cfg(feature = "alloc")] +extern crate alloc; + +pub mod buf; +pub mod ext; +pub mod smart_display; +mod smart_display_impls; diff --git a/vendor/powerfmt/src/smart_display.rs b/vendor/powerfmt/src/smart_display.rs new file mode 100644 index 000000000..bb55554b8 --- /dev/null +++ b/vendor/powerfmt/src/smart_display.rs @@ -0,0 +1,695 @@ +//! Definition of [`SmartDisplay`] and its related items. +//! +//! [`SmartDisplay`] is a trait that allows authors to provide additional information to both the +//! formatter and other users. This information is provided in the form of a metadata type. The only +//! required piece of metadata is the width of the value. This is _before_ it is passed to the +//! formatter (i.e. it does not include any padding added by the formatter). Other information +//! can be stored in a custom metadata type as needed. This information may be made available to +//! downstream users, but it is not required. +//! +//! This module contains the [`SmartDisplay`] and associated items. +//! +//! # Example +//! +//! ```rust +//! use std::fmt; +//! +//! use powerfmt::ext::FormatterExt as _; +//! use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay}; +//! +//! #[derive(Debug)] +//! struct User { +//! id: usize, +//! } +//! +//! // If you try to use `UserMetadata` in the `SmartDisplay` implementation, you will get a +//! // compiler error about a private type being used publicly. To avoid this, use this attribute to +//! // declare a private metadata type. You shouldn't need to worry about how this works, but be +//! // aware that any public fields or methods remain usable by downstream users. +//! #[smart_display::private_metadata] +//! struct UserMetadata { +//! username: String, +//! legal_name: String, +//! } +//! +//! // This attribute can be applied to `SmartDisplay` implementations. It will generate an +//! // implementation of `Display` that delegates to `SmartDisplay`, avoiding the need to write +//! // boilerplate. +//! #[smart_display::delegate] +//! impl SmartDisplay for User { +//! type Metadata = UserMetadata; +//! +//! fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { +//! // This could be obtained from a database, for example. +//! let legal_name = "John Doe".to_owned(); +//! let username = "jdoe".to_owned(); +//! +//! // Note that this must be kept in sync with the implementation of `fmt_with_metadata`. +//! let width = smart_display::padded_width_of!(username, " (", legal_name, ")",); +//! +//! Metadata::new( +//! width, +//! self, +//! UserMetadata { +//! username, +//! legal_name, +//! }, +//! ) +//! } +//! +//! // Use the now-generated metadata to format the value. Here we use the `pad_with_width` +//! // method to use the alignment and desired width from the formatter. +//! fn fmt_with_metadata( +//! &self, +//! f: &mut fmt::Formatter<'_>, +//! metadata: Metadata<Self>, +//! ) -> fmt::Result { +//! f.pad_with_width( +//! metadata.unpadded_width(), +//! format_args!("{} ({})", metadata.username, metadata.legal_name), +//! ) +//! } +//! } +//! +//! let user = User { id: 42 }; +//! assert_eq!(user.to_string(), "jdoe (John Doe)"); +//! assert_eq!(format!("{user:>20}"), " jdoe (John Doe)"); +//! ``` + +use core::cmp; +use core::convert::Infallible; +use core::fmt::{Alignment, Debug, Display, Formatter, Result}; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::ops::Deref; + +/// Compute the width of multiple items while optionally declaring the options for each item. +/// +/// ```rust +/// # use powerfmt::smart_display; +/// let alpha = 0; +/// let beta = 1; +/// let gamma = 100; +/// +/// let width = smart_display::padded_width_of!( +/// alpha, // use the default options +/// beta => width(2), // use the specified options +/// gamma => width(2) sign_plus(true), // use multiple options +/// ); +/// assert_eq!(width, 7); +/// +/// let formatted = format!("{alpha}{beta:2}{gamma:+2}"); +/// assert_eq!(formatted.len(), width); +/// ``` +/// +/// Supported options are: +/// +/// Option | Method called +/// --- | --- +/// `fill(char)` | [`FormatterOptions::with_fill`] +/// `sign_plus(bool)` | [`FormatterOptions::with_sign_plus`] +/// `sign_minus(bool)` | [`FormatterOptions::with_sign_minus`] +/// `align(Alignment)` | [`FormatterOptions::with_align`] +/// `width(usize)` | [`FormatterOptions::with_width`] +/// `precision(usize)` | [`FormatterOptions::with_precision`] +/// `alternate(bool)` | [`FormatterOptions::with_alternate`] +/// `sign_aware_zero_pad(bool)` | [`FormatterOptions::with_sign_aware_zero_pad`] +/// +/// If there are future additions to [`FormatterOptions`], they will be added to this macro as well. +/// +/// Options may be provided in any order and will be called in the order they are provided. The +/// ordering matters if providing both `sign_plus` and `sign_minus`. +#[cfg(doc)] +#[doc(hidden)] // Don't show at crate root. +#[macro_export] +macro_rules! padded_width_of { + ($($t:tt)*) => {}; +} + +#[cfg(not(doc))] +#[allow(missing_docs)] // This is done with `#[cfg(doc)]` to avoid showing the various rules. +#[macro_export] +macro_rules! __not_public_at_root__padded_width_of { + // Base case + (@inner [] [$($output:tt)+]) => { $($output)+ }; + (@inner [$e:expr $(, $($remaining:tt)*)?] [$($expansion:tt)+]) => { + $crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [ + $($expansion)+ + $crate::smart_display::Metadata::padded_width_of( + &$e, + $crate::smart_display::padded_width_of!(@options) + ) + ]) + }; + (@inner + [$e:expr => $($call:ident($call_expr:expr))+ $(, $($remaining:tt)*)?] + [$($expansion:tt)+] + ) => { + $crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [ + $($expansion)+ + $crate::smart_display::Metadata::padded_width_of( + &$e, + *$crate::smart_display::padded_width_of!(@options $($call($call_expr))+) + ) + ]) + }; + + // Options base case + (@options_inner [] [$($output:tt)+]) => { $($output)+ }; + (@options_inner [fill($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_fill($e) + ]) + }; + (@options_inner [sign_plus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_sign_plus($e) + ]) + }; + (@options_inner [sign_minus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_sign_minus($e) + ]) + }; + (@options_inner [align($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_align(Some($e)) + ]) + }; + (@options_inner [width($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_width(Some($e)) + ]) + }; + (@options_inner [precision($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_precision(Some($e)) + ]) + }; + (@options_inner [alternate($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_width($e) + ]) + }; + (@options_inner [sign_aware_zero_pad($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_sign_aware_zero_pad($e) + ]) + }; + // Options entry point + (@options $($e:tt)*) => { + $crate::smart_display::padded_width_of!(@options_inner [$($e)*] [ + $crate::smart_display::FormatterOptions::default() + ]) + }; + + // Entry point + ($($t:tt)*) => { + $crate::smart_display::padded_width_of!( + @inner [$($t)*] [0] + ) + }; +} + +#[cfg(not(doc))] +pub use __not_public_at_root__padded_width_of as padded_width_of; +#[cfg(doc)] +#[doc(inline)] // Show in this module. +pub use padded_width_of; +/// Implement [`Display`] for a type by using its implementation of [`SmartDisplay`]. +/// +/// This attribute is applied to the `SmartDisplay` implementation. +/// +/// ```rust,no_run +/// # use powerfmt::smart_display::{self, SmartDisplay, Metadata, FormatterOptions}; +/// # struct Foo; +/// #[smart_display::delegate] +/// impl SmartDisplay for Foo { +/// # type Metadata = (); +/// # fn metadata(&self, f: FormatterOptions) -> Metadata<Self> { +/// # todo!() +/// # } +/// // ... +/// } +/// ``` +#[cfg(feature = "macros")] +pub use powerfmt_macros::smart_display_delegate as delegate; +/// Declare a private metadata type for `SmartDisplay`. +/// +/// Use this attribute if you want to provide metadata for a type that is not public. Doing +/// this will avoid a compiler error about a private type being used publicly. Keep in mind +/// that any public fields, public methods, and trait implementations _will_ be able to be used +/// by downstream users. +/// +/// To avoid accidentally exposing details, such as when all fields are public or if the type +/// is a unit struct, the type is annotated with `#[non_exhaustive]` automatically. +/// +/// ```rust,no_run +/// # use powerfmt::smart_display; +/// /// Metadata for `Foo` +/// #[smart_display::private_metadata] +/// #[derive(Debug)] +/// pub(crate) struct FooMetadata { +/// pub(crate) expensive_to_calculate: usize, +/// } +/// ``` +#[cfg(feature = "macros")] +pub use powerfmt_macros::smart_display_private_metadata as private_metadata; + +#[derive(Debug)] +enum FlagBit { + SignPlus, + SignMinus, + Alternate, + SignAwareZeroPad, + WidthIsInitialized, + PrecisionIsInitialized, +} + +/// Configuration for formatting. +/// +/// This struct is obtained from a [`Formatter`]. It provides the same functionality as that of a +/// reference to a `Formatter`. However, it is not possible to construct a `Formatter`, which is +/// necessary for some use cases of [`SmartDisplay`]. `FormatterOptions` implements [`Default`] and +/// has builder methods to alleviate this. +#[derive(Clone, Copy)] +pub struct FormatterOptions { + flags: u8, + fill: char, + align: Option<Alignment>, + width: MaybeUninit<usize>, + precision: MaybeUninit<usize>, +} + +impl Debug for FormatterOptions { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("FormatterOptions") + .field("fill", &self.fill) + .field("align", &self.align()) + .field("width", &self.width()) + .field("precision", &self.precision()) + .field("sign_plus", &self.sign_plus()) + .field("sign_minus", &self.sign_minus()) + .field("alternate", &self.alternate()) + .field("sign_aware_zero_pad", &self.sign_aware_zero_pad()) + .finish() + } +} + +impl Default for FormatterOptions { + #[inline] + fn default() -> Self { + Self { + flags: 0, + fill: ' ', + align: None, + width: MaybeUninit::uninit(), + precision: MaybeUninit::uninit(), + } + } +} + +impl FormatterOptions { + /// Sets the fill character to use whenever there is alignment. + #[inline] + pub fn with_fill(&mut self, c: char) -> &mut Self { + self.fill = c; + self + } + + /// Set whether the `+` flag is specified. + #[inline] + pub fn with_sign_plus(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::SignPlus as u8; + self.flags &= !(1 << FlagBit::SignMinus as u8); + } else { + self.flags &= !(1 << FlagBit::SignPlus as u8); + } + self + } + + /// Set whether the `-` flag is specified. + #[inline] + pub fn with_sign_minus(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::SignMinus as u8; + self.flags &= !(1 << FlagBit::SignPlus as u8); + } else { + self.flags &= !(1 << FlagBit::SignMinus as u8); + } + self + } + + /// Set the flag indicating what form of alignment is requested, if any. + #[inline] + pub fn with_align(&mut self, align: Option<Alignment>) -> &mut Self { + self.align = align; + self + } + + /// Set the optional integer width that the output should be. + #[inline] + pub fn with_width(&mut self, width: Option<usize>) -> &mut Self { + if let Some(width) = width { + self.flags |= 1 << FlagBit::WidthIsInitialized as u8; + self.width = MaybeUninit::new(width); + } else { + self.flags &= !(1 << FlagBit::WidthIsInitialized as u8); + } + self + } + + /// Set the optional precision for numeric types. Alternatively, the maximum width for string + /// types. + #[inline] + pub fn with_precision(&mut self, precision: Option<usize>) -> &mut Self { + if let Some(precision) = precision { + self.flags |= 1 << FlagBit::PrecisionIsInitialized as u8; + self.precision = MaybeUninit::new(precision); + } else { + self.flags &= !(1 << FlagBit::PrecisionIsInitialized as u8); + } + self + } + + /// Set whether the `#` flag is specified. + #[inline] + pub fn with_alternate(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::Alternate as u8; + } else { + self.flags &= !(1 << FlagBit::Alternate as u8); + } + self + } + + /// Set whether the `0` flag is specified. + #[inline] + pub fn with_sign_aware_zero_pad(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::SignAwareZeroPad as u8; + } else { + self.flags &= !(1 << FlagBit::SignAwareZeroPad as u8); + } + self + } +} + +impl FormatterOptions { + /// Character used as 'fill' whenever there is alignment. + #[inline] + #[must_use] + pub const fn fill(&self) -> char { + self.fill + } + + /// Flag indicating what form of alignment was requested. + #[inline] + #[must_use] + pub const fn align(&self) -> Option<Alignment> { + self.align + } + + /// Optionally specified integer width that the output should be. + #[inline] + #[must_use] + pub const fn width(&self) -> Option<usize> { + if (self.flags >> FlagBit::WidthIsInitialized as u8) & 1 == 1 { + // Safety: `width` is initialized if the flag is set. + Some(unsafe { self.width.assume_init() }) + } else { + None + } + } + + /// Optionally specified precision for numeric types. Alternatively, the maximum width for + /// string types. + #[inline] + #[must_use] + pub const fn precision(&self) -> Option<usize> { + if (self.flags >> FlagBit::PrecisionIsInitialized as u8) & 1 == 1 { + // Safety: `precision` is initialized if the flag is set. + Some(unsafe { self.precision.assume_init() }) + } else { + None + } + } + + /// Determines if the `+` flag was specified. + #[inline] + #[must_use] + pub const fn sign_plus(&self) -> bool { + (self.flags >> FlagBit::SignPlus as u8) & 1 == 1 + } + + /// Determines if the `-` flag was specified. + #[inline] + #[must_use] + pub const fn sign_minus(&self) -> bool { + (self.flags >> FlagBit::SignMinus as u8) & 1 == 1 + } + + /// Determines if the `#` flag was specified. + #[inline] + #[must_use] + pub const fn alternate(&self) -> bool { + (self.flags >> FlagBit::Alternate as u8) & 1 == 1 + } + + /// Determines if the `0` flag was specified. + #[inline] + #[must_use] + pub const fn sign_aware_zero_pad(&self) -> bool { + (self.flags >> FlagBit::SignAwareZeroPad as u8) & 1 == 1 + } +} + +impl From<&Formatter<'_>> for FormatterOptions { + fn from(value: &Formatter<'_>) -> Self { + *Self::default() + .with_fill(value.fill()) + .with_sign_plus(value.sign_plus()) + .with_sign_minus(value.sign_minus()) + .with_align(value.align()) + .with_width(value.width()) + .with_precision(value.precision()) + .with_alternate(value.alternate()) + .with_sign_aware_zero_pad(value.sign_aware_zero_pad()) + } +} + +impl From<&mut Formatter<'_>> for FormatterOptions { + #[inline] + fn from(value: &mut Formatter<'_>) -> Self { + (&*value).into() + } +} + +/// Information used to format a value. This is returned by [`SmartDisplay::metadata`]. +/// +/// This type is generic over any user-provided type. This allows the author to store any +/// information that is needed. For example, a type's implementation of [`SmartDisplay`] may need +/// to calculate something before knowing its width. This calculation can be performed, with the +/// result being stored in the custom metadata type. +/// +/// Note that `Metadata` _always_ contains the width of the type. Authors do not need to store this +/// information in their custom metadata type. +/// +/// Generally speaking, a type should be able to be formatted using only its metadata, fields, and +/// the formatter. Any other information should be stored in the metadata type. +pub struct Metadata<'a, T> +where + T: SmartDisplay + ?Sized, +{ + unpadded_width: usize, + metadata: T::Metadata, + _value: PhantomData<&'a T>, // variance +} + +// manual impls for bounds +impl<T> Debug for Metadata<'_, T> +where + T: SmartDisplay, + T::Metadata: Debug, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("Metadata") + .field("unpadded_width", &self.unpadded_width) + .field("metadata", &self.metadata) + .finish() + } +} + +impl<T> Clone for Metadata<'_, T> +where + T: SmartDisplay, + T::Metadata: Clone, +{ + fn clone(&self) -> Self { + Self { + unpadded_width: self.unpadded_width, + metadata: self.metadata.clone(), + _value: self._value, + } + } +} + +impl<T> Copy for Metadata<'_, T> +where + T: SmartDisplay, + T::Metadata: Copy, +{ +} + +impl<'a, T> Metadata<'a, T> +where + T: SmartDisplay + ?Sized, +{ + /// Creates a new `Metadata` with the given width and metadata. While the width _should_ be + /// exact, this is not a requirement for soundness. + pub const fn new(unpadded_width: usize, _value: &T, metadata: T::Metadata) -> Self { + Self { + unpadded_width, + metadata, + _value: PhantomData, + } + } + + /// Reuse the metadata for another type. This is useful when implementing [`SmartDisplay`] for a + /// type that wraps another type. Both type's metadata type must be the same. + pub fn reuse<'b, U>(self) -> Metadata<'b, U> + where + 'a: 'b, + U: SmartDisplay<Metadata = T::Metadata> + ?Sized, + { + Metadata { + unpadded_width: self.unpadded_width, + metadata: self.metadata, + _value: PhantomData, + } + } + + /// Obtain the width of the value before padding. + pub const fn unpadded_width(&self) -> usize { + self.unpadded_width + } + + /// Obtain the width of the value after padding. + pub fn padded_width(&self, f: FormatterOptions) -> usize { + match f.width() { + Some(requested_width) => cmp::max(self.unpadded_width(), requested_width), + None => self.unpadded_width(), + } + } +} + +impl Metadata<'_, Infallible> { + /// Obtain the width of the value before padding, given the formatter options. + pub fn unpadded_width_of<T>(value: T, f: FormatterOptions) -> usize + where + T: SmartDisplay, + { + value.metadata(f).unpadded_width + } + + /// Obtain the width of the value after padding, given the formatter options. + pub fn padded_width_of<T>(value: T, f: FormatterOptions) -> usize + where + T: SmartDisplay, + { + value.metadata(f).padded_width(f) + } +} + +/// Permit using `Metadata` as a smart pointer to the user-provided metadata. +impl<T> Deref for Metadata<'_, T> +where + T: SmartDisplay + ?Sized, +{ + type Target = T::Metadata; + + fn deref(&self) -> &T::Metadata { + &self.metadata + } +} + +/// Format trait that allows authors to provide additional information. +/// +/// This trait is similar to [`Display`], but allows the author to provide additional information +/// to the formatter. This information is provided in the form of a custom metadata type. +/// +/// The only required piece of metadata is the width of the value. This is _before_ it is passed to +/// the formatter (i.e. it does not include any padding added by the formatter). Other information +/// can be stored in a custom metadata type as needed. This information may be made available to +/// downstream users, but it is not required. +/// +/// **Note**: While both `fmt_with_metadata` and `fmt` have default implementations, it is strongly +/// recommended to implement only `fmt_with_metadata`. `fmt` should be implemented if and only if +/// the type does not require any of the calculated metadata. In that situation, `fmt_with_metadata` +/// should be omitted. +#[cfg_attr(__powerfmt_docs, rustc_must_implement_one_of(fmt, fmt_with_metadata))] +pub trait SmartDisplay: Display { + /// User-provided metadata type. + type Metadata; + + /// Compute any information needed to format the value. This must, at a minimum, determine the + /// width of the value before any padding is added by the formatter. + /// + /// If the type uses other types that implement `SmartDisplay` verbatim, the inner types should + /// have their metadata calculated and included in the returned value. + /// + /// # Lifetimes + /// + /// This method's return type contains a lifetime to `self`. This ensures that the metadata will + /// neither outlive the value nor be invalidated by a mutation of the value (barring interior + /// mutability). + /// + /// ```rust,compile_fail + /// # use std::fmt; + /// # use std::fmt::Write; + /// # use powerfmt::buf::WriteBuffer; + /// # use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay}; + /// #[derive(Debug)] + /// struct WrappedBuffer(WriteBuffer<128>); + /// + /// #[smart_display::delegate] + /// impl SmartDisplay for WrappedBuffer { + /// type Metadata = (); + /// + /// fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + /// Metadata::new(self.0.len(), self, ()) + /// } + /// + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// f.pad(self.0.as_str()) + /// } + /// } + /// + /// let mut buf = WrappedBuffer(WriteBuffer::new()); + /// let metadata = buf.metadata(FormatterOptions::default()); + /// // We cannot mutate the buffer while it is borrowed and use its previous metadata on the + /// // following line. + /// write!(buf.0, "Hello, world!")?; + /// assert_eq!(metadata.width(), 13); + /// # Ok::<(), Box<dyn std::error::Error>>(()) + /// ``` + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self>; + + /// Format the value using the given formatter and metadata. The formatted output should have + /// the width indicated by the metadata. This is before any padding is added by the + /// formatter. + /// + /// If the metadata is not needed, you should implement the `fmt` method instead. + fn fmt_with_metadata(&self, f: &mut Formatter<'_>, _metadata: Metadata<'_, Self>) -> Result { + SmartDisplay::fmt(self, f) + } + + /// Format the value using the given formatter. This is the same as [`Display::fmt`]. + /// + /// The default implementation of this method calls `fmt_with_metadata` with the result of + /// `metadata`. Generally speaking, this method should not be implemented. You should implement + /// the `fmt_with_metadata` method instead. + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let metadata = self.metadata(f.into()); + self.fmt_with_metadata(f, metadata) + } +} diff --git a/vendor/powerfmt/src/smart_display_impls.rs b/vendor/powerfmt/src/smart_display_impls.rs new file mode 100644 index 000000000..dc82395f2 --- /dev/null +++ b/vendor/powerfmt/src/smart_display_impls.rs @@ -0,0 +1,303 @@ +//! Implementation of [`SmartDisplay`] for various types. + +#[cfg(feature = "alloc")] +use alloc::borrow::{Cow, ToOwned}; +#[cfg(feature = "alloc")] +use alloc::boxed::Box; +#[cfg(feature = "alloc")] +use alloc::rc::Rc; +#[cfg(feature = "alloc")] +use alloc::string::String; +#[cfg(feature = "alloc")] +use alloc::sync::Arc; +use core::cell::{Ref, RefMut}; +use core::cmp::min; +use core::convert::Infallible; +use core::fmt::{self, Display, Formatter}; +use core::num::Wrapping; +use core::pin::Pin; + +use crate::smart_display::{FormatterOptions, Metadata, SmartDisplay}; + +impl SmartDisplay for Infallible { + type Metadata = Self; + + #[inline] + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + match *self {} + } + + #[inline] + fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { + match *self {} + } +} + +impl SmartDisplay for bool { + type Metadata = (); + + #[inline] + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + Metadata::new(if *self { 4 } else { 5 }, self, ()) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +impl SmartDisplay for str { + type Metadata = (); + + #[inline] + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + Metadata::new( + match f.precision() { + Some(max_len) => min(self.len(), max_len), + None => self.len(), + }, + self, + (), + ) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +#[cfg(feature = "alloc")] +impl SmartDisplay for String { + type Metadata = (); + + #[inline] + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +#[cfg(feature = "alloc")] +impl<'a, B, O> SmartDisplay for Cow<'a, B> +where + B: SmartDisplay + ToOwned<Owned = O> + ?Sized, + O: SmartDisplay<Metadata = B::Metadata> + 'a, +{ + type Metadata = B::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + match *self { + Cow::Borrowed(ref b) => b.metadata(f).reuse(), + Cow::Owned(ref o) => o.metadata(f).reuse(), + } + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +impl<T> SmartDisplay for Pin<&T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + self.get_ref().metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(self.get_ref(), f) + } +} + +impl<T> SmartDisplay for &T +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(*self, f) + } +} + +impl<T> SmartDisplay for &mut T +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(*self, f) + } +} + +impl<T> SmartDisplay for Ref<'_, T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +impl<T> SmartDisplay for RefMut<'_, T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +impl<T> SmartDisplay for Wrapping<T> +where + T: SmartDisplay, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + self.0.metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&self.0, f) + } +} + +#[cfg(feature = "alloc")] +impl<T> SmartDisplay for Rc<T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +#[cfg(feature = "alloc")] +impl<T> SmartDisplay for Arc<T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +#[cfg(feature = "alloc")] +impl<T> SmartDisplay for Box<T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +/// Implement [`SmartDisplay`] for unsigned integers. +macro_rules! impl_uint { + ($($t:ty)*) => {$( + impl SmartDisplay for $t { + type Metadata = (); + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + let mut width = self.checked_ilog10().map_or(1, |n| n as usize + 1); + if f.sign_plus() || f.sign_minus() { + width += 1; + } + Metadata::new(width, self, ()) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } + } + )*}; +} + +impl_uint![u8 u16 u32 u64 u128 usize]; + +/// Implement [`SmartDisplay`] for signed integers. +macro_rules! impl_int { + ($($t:ty)*) => {$( + impl SmartDisplay for $t { + type Metadata = (); + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + let mut width = if f.sign_plus() || *self < 0 { 1 } else { 0 }; + width += self.unsigned_abs().checked_ilog10().map_or(1, |n| n as usize + 1); + Metadata::new(width, self, ()) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } + } + )*}; +} + +impl_int![i8 i16 i32 i64 i128 isize]; + +impl SmartDisplay for char { + type Metadata = (); + + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + let mut buf = [0; 4]; + let c = self.encode_utf8(&mut buf); + + Metadata::new(c.len(), self, ()) + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} |