You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

writeable

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

writeable - cargo Package Compare versions

Comparing version
0.5.5
to
0.6.0
+210
src/to_string_or_borrow.rs
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
use crate::Writeable;
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt;
/// Bytes that have been partially validated as UTF-8 up to an offset.
struct PartiallyValidatedUtf8<'a> {
// Safety Invariants:
// 1. The offset is less than or equal to the length of the slice.
// 2. The slice is valid UTF-8 up to the offset.
slice: &'a [u8],
offset: usize,
}
impl<'a> PartiallyValidatedUtf8<'a> {
fn new(slice: &'a [u8]) -> Self {
// Safety: Field invariants maintained here trivially:
// 1. The offset 0 is ≤ all possible lengths of slice
// 2. The slice contains nothing up to the offset zero
Self { slice, offset: 0 }
}
/// Check whether the given string is the next chunk of unvalidated bytes.
/// If so, increment offset and return true. Otherwise, return false.
fn try_push(&mut self, valid_str: &str) -> bool {
let new_offset = self.offset + valid_str.len();
if self.slice.get(self.offset..new_offset) == Some(valid_str.as_bytes()) {
// Safety: Field invariants maintained here:
// 1. In the line above, `self.slice.get()` returned `Some()` for `new_offset` at
// the end of a `Range`, so `new_offset` is ≤ the length of `self.slice`.
// 2. By invariant, we have already validated the string up to `self.offset`, and
// the portion of the slice between `self.offset` and `new_offset` is equal to
// `valid_str`, which is a `&str`, so the string is valid up to `new_offset`.
self.offset = new_offset;
true
} else {
false
}
}
/// Return the validated portion as `&str`.
fn validated_as_str(&self) -> &'a str {
debug_assert!(self.offset <= self.slice.len());
// Safety: self.offset is a valid end index in a range (from field invariant)
let valid_slice = unsafe { self.slice.get_unchecked(..self.offset) };
debug_assert!(core::str::from_utf8(valid_slice).is_ok());
// Safety: the UTF-8 of slice has been validated up to offset (from field invariant)
unsafe { core::str::from_utf8_unchecked(valid_slice) }
}
}
enum SliceOrString<'a> {
Slice(PartiallyValidatedUtf8<'a>),
String(String),
}
/// This is an infallible impl. Functions always return Ok, not Err.
impl fmt::Write for SliceOrString<'_> {
#[inline]
fn write_str(&mut self, other: &str) -> fmt::Result {
match self {
SliceOrString::Slice(slice) => {
if !slice.try_push(other) {
// We failed to match. Convert to owned.
let valid_str = slice.validated_as_str();
let mut owned = String::with_capacity(valid_str.len() + other.len());
owned.push_str(valid_str);
owned.push_str(other);
*self = SliceOrString::String(owned);
}
Ok(())
}
SliceOrString::String(owned) => owned.write_str(other),
}
}
}
impl<'a> SliceOrString<'a> {
#[inline]
fn new(slice: &'a [u8]) -> Self {
Self::Slice(PartiallyValidatedUtf8::new(slice))
}
#[inline]
fn finish(self) -> Cow<'a, str> {
match self {
SliceOrString::Slice(slice) => Cow::Borrowed(slice.validated_as_str()),
SliceOrString::String(owned) => Cow::Owned(owned),
}
}
}
/// Writes the contents of a `Writeable` to a string, returning a reference
/// to a slice if it matches the provided reference bytes, and allocating a
/// String otherwise.
///
/// This function is useful if you have borrowed bytes which you expect
/// to be equal to a writeable a high percentage of the time.
///
/// You can also use this function to make a more efficient implementation of
/// [`Writeable::write_to_string`].
///
/// # Examples
///
/// Basic usage and behavior:
///
/// ```
/// use std::fmt;
/// use std::borrow::Cow;
/// use writeable::Writeable;
///
/// struct WelcomeMessage<'s> {
/// pub name: &'s str,
/// }
///
/// impl<'s> Writeable for WelcomeMessage<'s> {
/// // see impl in Writeable docs
/// # fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
/// # sink.write_str("Hello, ")?;
/// # sink.write_str(self.name)?;
/// # sink.write_char('!')?;
/// # Ok(())
/// # }
/// }
///
/// let message = WelcomeMessage { name: "Alice" };
///
/// assert!(matches!(
/// writeable::to_string_or_borrow(&message, b""),
/// Cow::Owned(s) if s == "Hello, Alice!"
/// ));
/// assert!(matches!(
/// writeable::to_string_or_borrow(&message, b"Hello"),
/// Cow::Owned(s) if s == "Hello, Alice!"
/// ));
/// assert!(matches!(
/// writeable::to_string_or_borrow(&message, b"Hello, Bob!"),
/// Cow::Owned(s) if s == "Hello, Alice!"
/// ));
/// assert!(matches!(
/// writeable::to_string_or_borrow(&message, b"Hello, Alice!"),
/// Cow::Borrowed("Hello, Alice!")
/// ));
///
/// // Borrowing can use a prefix:
/// assert!(matches!(
/// writeable::to_string_or_borrow(&message, b"Hello, Alice!..\xFF\x00\xFF"),
/// Cow::Borrowed("Hello, Alice!")
/// ));
/// ```
///
/// Example use case: a function that transforms a string to lowercase.
/// We are also able to write a more efficient implementation of
/// [`Writeable::write_to_string`] in this situation.
///
/// ```
/// use std::fmt;
/// use std::borrow::Cow;
/// use writeable::Writeable;
///
/// struct MakeAsciiLower<'a>(&'a str);
///
/// impl<'a> Writeable for MakeAsciiLower<'a> {
/// fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
/// for c in self.0.chars() {
/// sink.write_char(c.to_ascii_lowercase())?;
/// }
/// Ok(())
/// }
/// #[inline]
/// fn write_to_string(&self) -> Cow<str> {
/// writeable::to_string_or_borrow(self, self.0.as_bytes())
/// }
/// }
///
/// fn make_lowercase(input: &str) -> Cow<str> {
/// let writeable = MakeAsciiLower(input);
/// writeable::to_string_or_borrow(&writeable, input.as_bytes())
/// }
///
/// assert!(matches!(
/// make_lowercase("this is lowercase"),
/// Cow::Borrowed("this is lowercase")
/// ));
/// assert!(matches!(
/// make_lowercase("this is UPPERCASE"),
/// Cow::Owned(s) if s == "this is uppercase"
/// ));
///
/// assert!(matches!(
/// MakeAsciiLower("this is lowercase").write_to_string(),
/// Cow::Borrowed("this is lowercase")
/// ));
/// assert!(matches!(
/// MakeAsciiLower("this is UPPERCASE").write_to_string(),
/// Cow::Owned(s) if s == "this is uppercase"
/// ));
/// ```
pub fn to_string_or_borrow<'a>(
writeable: &impl Writeable,
reference_bytes: &'a [u8],
) -> Cow<'a, str> {
let mut sink = SliceOrString::new(reference_bytes);
let _ = writeable.write_to(&mut sink);
sink.finish()
}
+1
-1
{
"git": {
"sha1": "55cd12ebb25c6261492e1e3dfa2e6453c54dde31"
"sha1": "6bd4893cc44c2ca2718de47a119a31cc40045fe5"
},
"path_in_vcs": "utils/writeable"
}

@@ -28,2 +28,3 @@ // This file is part of ICU4X. For terms of use, please see the file

/// A sample type implementing Display
#[cfg(feature = "bench")]
struct DisplayMessage<'s> {

@@ -33,2 +34,3 @@ message: &'s str,

#[cfg(feature = "bench")]
impl fmt::Display for DisplayMessage<'_> {

@@ -41,2 +43,3 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

/// A sample type that contains multiple fields
#[cfg(feature = "bench")]
struct ComplexWriteable<'a> {

@@ -50,2 +53,3 @@ prefix: &'a str,

#[cfg(feature = "bench")]
impl Writeable for ComplexWriteable<'_> {

@@ -70,2 +74,3 @@ fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {

#[cfg(feature = "bench")]
writeable::impl_display_with_writeable!(ComplexWriteable<'_>);

@@ -76,2 +81,5 @@

const LONG_STR: &str = "this string is very very very very very very very very very very very very very very very very very very very very very very very very long";
#[cfg(feature = "bench")]
const LONG_OVERLAP_STR: &str =
"this string is very very very very very very very long but different";

@@ -135,2 +143,16 @@ fn overview_bench(c: &mut Criterion) {

});
c.bench_function("writeable/cmp_str", |b| {
b.iter(|| {
let short = black_box(SHORT_STR);
let medium = black_box(MEDIUM_STR);
let long = black_box(LONG_STR);
let long_overlap = black_box(LONG_OVERLAP_STR);
[short, medium, long, long_overlap].map(|s1| {
[short, medium, long, long_overlap].map(|s2| {
let message = WriteableMessage { message: s1 };
writeable::cmp_str(&message, s2)
})
})
});
});
}

@@ -218,2 +240,16 @@

});
const REFERENCE_STRS: [&str; 6] = [
"There are 55 apples and 8124 oranges",
"There are 55 apples and 0 oranges",
"There are no apples",
SHORT_STR,
MEDIUM_STR,
LONG_STR,
];
c.bench_function("complex/cmp_str", |b| {
b.iter(|| {
black_box(REFERENCE_STRS)
.map(|s| writeable::cmp_str(black_box(&COMPLEX_WRITEABLE_MEDIUM), s))
});
});
}

@@ -220,0 +256,0 @@

+197
-253

@@ -6,2 +6,11 @@ # This file is automatically @generated by Cargo.

[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anes"

@@ -13,24 +22,24 @@ version = "0.1.6"

[[package]]
name = "autocfg"
version = "1.1.0"
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "bitflags"
version = "1.3.2"
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "2.4.2"
name = "bumpalo"
version = "3.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
[[package]]
name = "bumpalo"
version = "3.14.0"
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"

@@ -51,5 +60,5 @@ [[package]]

name = "ciborium"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [

@@ -63,11 +72,11 @@ "ciborium-io",

name = "ciborium-io"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [

@@ -80,5 +89,5 @@ "ciborium-io",

name = "clap"
version = "4.2.1"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d"
dependencies = [

@@ -90,7 +99,7 @@ "clap_builder",

name = "clap_builder"
version = "4.2.1"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6"
dependencies = [
"bitflags 1.3.2",
"anstyle",
"clap_lex",

@@ -101,5 +110,5 @@ ]

name = "clap_lex"
version = "0.4.1"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"

@@ -144,7 +153,6 @@ [[package]]

name = "crossbeam-deque"
version = "0.8.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"cfg-if",
"crossbeam-epoch",

@@ -156,11 +164,7 @@ "crossbeam-utils",

name = "crossbeam-epoch"
version = "0.9.15"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]

@@ -170,27 +174,23 @@

name = "crossbeam-utils"
version = "0.8.19"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "either"
version = "1.9.0"
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "errno"
version = "0.3.8"
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "getrandom"
version = "0.2.10"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [

@@ -204,21 +204,25 @@ "cfg-if",

name = "half"
version = "1.8.2"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
dependencies = [
"cfg-if",
"crunchy",
]
[[package]]
name = "hermit-abi"
version = "0.3.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "is-terminal"
version = "0.4.9"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys 0.48.0",
"libc",
"windows-sys 0.52.0",
]

@@ -237,11 +241,11 @@

name = "itoa"
version = "1.0.9"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2"
[[package]]
name = "js-sys"
version = "0.3.64"
version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
dependencies = [

@@ -253,32 +257,23 @@ "wasm-bindgen",

name = "libc"
version = "0.2.153"
version = "0.2.164"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "log"
version = "0.4.20"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memoffset"
version = "0.9.0"
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "num-traits"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [

@@ -290,17 +285,17 @@ "autocfg",

name = "once_cell"
version = "1.18.0"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "oorandom"
version = "11.1.3"
version = "11.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
[[package]]
name = "plotters"
version = "0.3.5"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [

@@ -316,11 +311,11 @@ "num-traits",

name = "plotters-backend"
version = "0.3.5"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.5"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [

@@ -332,11 +327,14 @@ "plotters-backend",

name = "ppv-lite86"
version = "0.2.17"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.82"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [

@@ -348,5 +346,5 @@ "unicode-ident",

name = "quote"
version = "1.0.35"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [

@@ -388,5 +386,5 @@ "proc-macro2",

name = "rayon"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [

@@ -399,5 +397,5 @@ "either",

name = "rayon-core"
version = "1.12.0"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [

@@ -410,6 +408,9 @@ "crossbeam-deque",

name = "regex"
version = "1.8.4"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",

@@ -419,25 +420,23 @@ ]

[[package]]
name = "regex-syntax"
version = "0.7.5"
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "rustix"
version = "0.38.31"
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
dependencies = [
"bitflags 2.4.2",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "ryu"
version = "1.0.15"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"

@@ -454,12 +453,6 @@ [[package]]

[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.188"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [

@@ -471,5 +464,5 @@ "serde_derive",

name = "serde_derive"
version = "1.0.188"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [

@@ -483,7 +476,8 @@ "proc-macro2",

name = "serde_json"
version = "1.0.107"
version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [
"itoa",
"memchr",
"ryu",

@@ -495,5 +489,5 @@ "serde",

name = "syn"
version = "2.0.58"
version = "2.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
dependencies = [

@@ -517,11 +511,11 @@ "proc-macro2",

name = "unicode-ident"
version = "1.0.12"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "walkdir"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [

@@ -540,7 +534,8 @@ "same-file",

name = "wasm-bindgen"
version = "0.2.87"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",

@@ -551,5 +546,5 @@ ]

name = "wasm-bindgen-backend"
version = "0.2.87"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
dependencies = [

@@ -567,5 +562,5 @@ "bumpalo",

name = "wasm-bindgen-macro"
version = "0.2.87"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
dependencies = [

@@ -578,5 +573,5 @@ "quote",

name = "wasm-bindgen-macro-support"
version = "0.2.87"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [

@@ -592,11 +587,11 @@ "proc-macro2",

name = "wasm-bindgen-shared"
version = "0.2.87"
version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
[[package]]
name = "web-sys"
version = "0.3.64"
version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
dependencies = [

@@ -608,43 +603,12 @@ "js-sys",

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"winapi",
"windows-sys 0.59.0",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"

@@ -654,18 +618,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

dependencies = [
"windows-targets 0.52.0",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
"windows-targets",
]

@@ -675,13 +633,14 @@

name = "windows-targets"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]

@@ -691,87 +650,51 @@

name = "windows_aarch64_gnullvm"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "writeable"
version = "0.5.5"
version = "0.6.0"
dependencies = [

@@ -782,1 +705,22 @@ "criterion",

]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

@@ -14,6 +14,7 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

edition = "2021"
rust-version = "1.67"
rust-version = "1.71.1"
name = "writeable"
version = "0.5.5"
version = "0.6.0"
authors = ["The ICU4X Project Developers"]
build = false
include = [

@@ -29,2 +30,6 @@ "data/**/*",

]
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "A more efficient alternative to fmt::Display"

@@ -45,6 +50,17 @@ readme = "README.md"

[lib]
name = "writeable"
path = "src/lib.rs"
bench = false
[[example]]
name = "writeable_message"
path = "examples/writeable_message.rs"
[[test]]
name = "writeable"
path = "tests/writeable.rs"
[[bench]]
name = "writeable"
path = "benches/writeable.rs"
harness = false

@@ -65,3 +81,3 @@

[target."cfg(not(target_arch = \"wasm32\"))".dev-dependencies.criterion]
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion]
version = "0.5.0"

@@ -6,4 +6,6 @@ // This file is part of ICU4X. For terms of use, please see the file

// This example illustrates a very simple type implementing Writeable.
icu_benchmark_macros::static_setup!();
#![no_main] // https://github.com/unicode-org/icu4x/issues/395
icu_benchmark_macros::instrument!();
use std::fmt;

@@ -49,4 +51,2 @@ use writeable::*;

fn main() {
icu_benchmark_macros::main_setup!();
let (string, parts) =

@@ -53,0 +53,0 @@ writeable::_internal::writeable_to_parts_for_test(&WriteableMessage("world"));

@@ -48,2 +48,3 @@ # writeable [![crates.io](https://img.shields.io/crates/v/writeable)](https://crates.io/crates/writeable)

writeable::impl_display_with_writeable!(WelcomeMessage<'_>);
assert_eq!(message.to_string(), "Hello, Alice!");
```

@@ -50,0 +51,0 @@

@@ -5,7 +5,8 @@ // This file is part of ICU4X. For terms of use, please see the file

use crate::Writeable;
use core::cmp::Ordering;
use core::fmt;
pub(crate) struct WriteComparator<'a> {
string: &'a [u8],
struct WriteComparator<'a> {
code_units: &'a [u8],
result: Ordering,

@@ -15,3 +16,3 @@ }

/// This is an infallible impl. Functions always return Ok, not Err.
impl<'a> fmt::Write for WriteComparator<'a> {
impl fmt::Write for WriteComparator<'_> {
#[inline]

@@ -22,5 +23,5 @@ fn write_str(&mut self, other: &str) -> fmt::Result {

}
let cmp_len = core::cmp::min(other.len(), self.string.len());
let (this, remainder) = self.string.split_at(cmp_len);
self.string = remainder;
let cmp_len = core::cmp::min(other.len(), self.code_units.len());
let (this, remainder) = self.code_units.split_at(cmp_len);
self.code_units = remainder;
self.result = this.cmp(other.as_bytes());

@@ -33,5 +34,5 @@ Ok(())

#[inline]
pub fn new(string: &'a (impl AsRef<[u8]> + ?Sized)) -> Self {
fn new(code_units: &'a [u8]) -> Self {
Self {
string: string.as_ref(),
code_units,
result: Ordering::Equal,

@@ -42,4 +43,4 @@ }

#[inline]
pub fn finish(self) -> Ordering {
if matches!(self.result, Ordering::Equal) && !self.string.is_empty() {
fn finish(self) -> Ordering {
if matches!(self.result, Ordering::Equal) && !self.code_units.is_empty() {
// Self is longer than Other

@@ -53,2 +54,56 @@ Ordering::Greater

/// Compares the contents of a [`Writeable`] to the given UTF-8 bytes without allocating memory.
///
/// For more details, see: [`cmp_str`]
pub fn cmp_utf8(writeable: &impl Writeable, other: &[u8]) -> Ordering {
let mut wc = WriteComparator::new(other);
let _ = writeable.write_to(&mut wc);
wc.finish().reverse()
}
/// Compares the contents of a `Writeable` to the given bytes
/// without allocating a String to hold the `Writeable` contents.
///
/// This returns a lexicographical comparison, the same as if the Writeable
/// were first converted to a String and then compared with `Ord`. For a
/// string ordering suitable for display to end users, use a localized
/// collation crate, such as `icu_collator`.
///
/// # Examples
///
/// ```
/// use core::cmp::Ordering;
/// use core::fmt;
/// use writeable::Writeable;
///
/// struct WelcomeMessage<'s> {
/// pub name: &'s str,
/// }
///
/// impl<'s> Writeable for WelcomeMessage<'s> {
/// // see impl in Writeable docs
/// # fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
/// # sink.write_str("Hello, ")?;
/// # sink.write_str(self.name)?;
/// # sink.write_char('!')?;
/// # Ok(())
/// # }
/// }
///
/// let message = WelcomeMessage { name: "Alice" };
/// let message_str = message.write_to_string();
///
/// assert_eq!(Ordering::Equal, writeable::cmp_str(&message, "Hello, Alice!"));
///
/// assert_eq!(Ordering::Greater, writeable::cmp_str(&message, "Alice!"));
/// assert_eq!(Ordering::Greater, (*message_str).cmp("Alice!"));
///
/// assert_eq!(Ordering::Less, writeable::cmp_str(&message, "Hello, Bob!"));
/// assert_eq!(Ordering::Less, (*message_str).cmp("Hello, Bob!"));
/// ```
#[inline]
pub fn cmp_str(writeable: &impl Writeable, other: &str) -> Ordering {
cmp_utf8(writeable, other.as_bytes())
}
#[cfg(test)]

@@ -67,3 +122,3 @@ mod tests {

for b in data::KEBAB_CASE_STRINGS {
let mut wc = WriteComparator::new(a);
let mut wc = WriteComparator::new(a.as_bytes());
for ch in b.chars() {

@@ -81,3 +136,3 @@ wc.write_char(ch).unwrap();

for b in data::KEBAB_CASE_STRINGS {
let mut wc = WriteComparator::new(a);
let mut wc = WriteComparator::new(a.as_bytes());
wc.write_str(b).unwrap();

@@ -93,3 +148,3 @@ assert_eq!(a.cmp(b), wc.finish(), "{a} <=> {b}");

for b in data::KEBAB_CASE_STRINGS {
let mut wc = WriteComparator::new(a);
let mut wc = WriteComparator::new(a.as_bytes());
let mut first = true;

@@ -96,0 +151,0 @@ for substr in b.split('-') {

@@ -41,9 +41,2 @@ // This file is part of ICU4X. For terms of use, please see the file

}
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
match self {
Either::Left(w) => w.writeable_cmp_bytes(other),
Either::Right(w) => w.writeable_cmp_bytes(other),
}
}
}

@@ -118,7 +118,2 @@ // This file is part of ICU4X. For terms of use, please see the file

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
self.as_bytes().cmp(other)
}
}

@@ -141,7 +136,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
self.as_bytes().cmp(other)
}
}

@@ -166,7 +156,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
self.encode_utf8(&mut [0u8; 4]).as_bytes().cmp(other)
}
}

@@ -194,7 +179,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
(*self).writeable_cmp_bytes(other)
}
}

@@ -221,6 +201,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
core::borrow::Borrow::<T>::borrow(self).writeable_cmp_bytes(other)
}
}

@@ -263,3 +239,3 @@ };

assert_eq!(
chars[j].writeable_cmp_bytes(s.as_bytes()),
crate::cmp_str(&chars[j], &s),
chars[j].cmp(&chars[i]),

@@ -266,0 +242,0 @@ "{:?} vs {:?}",

@@ -63,2 +63,3 @@ // This file is part of ICU4X. For terms of use, please see the file

//! writeable::impl_display_with_writeable!(WelcomeMessage<'_>);
//! assert_eq!(message.to_string(), "Hello, Alice!");
//! ```

@@ -77,2 +78,3 @@ //!

mod testing;
mod to_string_or_borrow;
mod try_writeable;

@@ -84,2 +86,4 @@

pub use cmp::{cmp_str, cmp_utf8};
pub use to_string_or_borrow::to_string_or_borrow;
pub use try_writeable::TryWriteable;

@@ -92,10 +96,34 @@

pub use parts_write_adapter::CoreWriteAsPartsWrite;
pub use parts_write_adapter::WithPart;
pub use try_writeable::TryWriteableInfallibleAsWriteable;
pub use try_writeable::WriteableAsTryWriteableInfallible;
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)] // newtype
pub struct LossyWrap<T>(pub T);
impl<T: TryWriteable> Writeable for LossyWrap<T> {
fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
let _ = self.0.try_write_to(sink)?;
Ok(())
}
fn writeable_length_hint(&self) -> LengthHint {
self.0.writeable_length_hint()
}
}
impl<T: TryWriteable> fmt::Display for LossyWrap<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let _ = self.0.try_write_to(f)?;
Ok(())
}
}
}
#[doc(hidden)]
#[doc(hidden)] // for testing and macros
pub mod _internal {
pub use super::testing::try_writeable_to_parts_for_test;
pub use super::testing::writeable_to_parts_for_test;
pub use alloc::string::String;
}

@@ -165,6 +193,8 @@

/// [`Part`]s are used as annotations for formatted strings. For example, a string like
/// `Alice, Bob` could assign a `NAME` part to the substrings `Alice` and `Bob`, and a
/// `PUNCTUATION` part to `, `. This allows for example to apply styling only to names.
/// [`Part`]s are used as annotations for formatted strings.
///
/// For example, a string like `Alice, Bob` could assign a `NAME` part to the
/// substrings `Alice` and `Bob`, and a `PUNCTUATION` part to `, `. This allows
/// for example to apply styling only to names.
///
/// `Part` contains two fields, whose usage is left up to the producer of the [`Writeable`].

@@ -287,47 +317,2 @@ /// Conventionally, the `category` field will identify the formatting logic that produces

}
/// Compares the contents of this `Writeable` to the given bytes
/// without allocating a String to hold the `Writeable` contents.
///
/// This returns a lexicographical comparison, the same as if the Writeable
/// were first converted to a String and then compared with `Ord`. For a
/// locale-sensitive string ordering, use an ICU4X Collator.
///
/// # Examples
///
/// ```
/// use core::cmp::Ordering;
/// use core::fmt;
/// use writeable::Writeable;
///
/// struct WelcomeMessage<'s> {
/// pub name: &'s str,
/// }
///
/// impl<'s> Writeable for WelcomeMessage<'s> {
/// // see impl in Writeable docs
/// # fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
/// # sink.write_str("Hello, ")?;
/// # sink.write_str(self.name)?;
/// # sink.write_char('!')?;
/// # Ok(())
/// # }
/// }
///
/// let message = WelcomeMessage { name: "Alice" };
/// let message_str = message.write_to_string();
///
/// assert_eq!(Ordering::Equal, message.writeable_cmp_bytes(b"Hello, Alice!"));
///
/// assert_eq!(Ordering::Greater, message.writeable_cmp_bytes(b"Alice!"));
/// assert_eq!(Ordering::Greater, (*message_str).cmp("Alice!"));
///
/// assert_eq!(Ordering::Less, message.writeable_cmp_bytes(b"Hello, Bob!"));
/// assert_eq!(Ordering::Less, (*message_str).cmp("Hello, Bob!"));
/// ```
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
let mut wc = cmp::WriteComparator::new(other);
let _ = self.write_to(&mut wc);
wc.finish().reverse()
}
}

@@ -340,5 +325,9 @@

/// [`print!`](std::print), [`write!`](std::write), etc.
///
/// This macro also adds a concrete `to_string` function. This function will shadow the
/// standard library `ToString`, using the more efficient writeable-based code path.
/// To add only `Display`, use the `@display` macro variant.
#[macro_export]
macro_rules! impl_display_with_writeable {
($type:ty) => {
(@display, $type:ty) => {
/// This trait is implemented for compatibility with [`fmt!`](alloc::fmt).

@@ -353,2 +342,15 @@ /// To create a string, [`Writeable::write_to_string`] is usually more efficient.

};
($type:ty) => {
$crate::impl_display_with_writeable!(@display, $type);
impl $type {
/// Converts the given value to a `String`.
///
/// Under the hood, this uses an efficient [`Writeable`] implementation.
/// However, in order to avoid allocating a string, it is more efficient
/// to use [`Writeable`] directly.
pub fn to_string(&self) -> $crate::_internal::String {
$crate::Writeable::write_to_string(self).into_owned()
}
}
};
}

@@ -371,3 +373,2 @@

/// - Validity of size hint
/// - Reflexivity of `cmp_bytes` and order against largest and smallest strings
///

@@ -447,10 +448,2 @@ /// # Examples

assert_eq!(actual_writeable.to_string(), $expected_str);
let ordering = $crate::Writeable::writeable_cmp_bytes(actual_writeable, $expected_str.as_bytes());
assert_eq!(ordering, core::cmp::Ordering::Equal, $($arg)*);
let ordering = $crate::Writeable::writeable_cmp_bytes(actual_writeable, "\u{10FFFF}".as_bytes());
assert_eq!(ordering, core::cmp::Ordering::Less, $($arg)*);
if $expected_str != "" {
let ordering = $crate::Writeable::writeable_cmp_bytes(actual_writeable, "".as_bytes());
assert_eq!(ordering, core::cmp::Ordering::Greater, $($arg)*);
}
actual_parts // return for assert_writeable_parts_eq

@@ -457,0 +450,0 @@ }};

@@ -7,2 +7,3 @@ // This file is part of ICU4X. For terms of use, please see the file

/// A wrapper around a type implementing [`fmt::Write`] that implements [`PartsWrite`].
#[derive(Debug)]

@@ -36,1 +37,81 @@ #[allow(clippy::exhaustive_structs)] // newtype

}
/// A [`Writeable`] that writes out the given part.
///
/// # Examples
///
/// ```
/// use writeable::adapters::WithPart;
/// use writeable::assert_writeable_parts_eq;
/// use writeable::Part;
///
/// // Simple usage:
///
/// const PART: Part = Part {
/// category: "foo",
/// value: "bar",
/// };
///
/// assert_writeable_parts_eq!(
/// WithPart {
/// writeable: "Hello World",
/// part: PART
/// },
/// "Hello World",
/// [(0, 11, PART)],
/// );
///
/// // Can be nested:
///
/// const PART2: Part = Part {
/// category: "foo2",
/// value: "bar2",
/// };
///
/// assert_writeable_parts_eq!(
/// WithPart {
/// writeable: WithPart {
/// writeable: "Hello World",
/// part: PART
/// },
/// part: PART2
/// },
/// "Hello World",
/// [(0, 11, PART), (0, 11, PART2)],
/// );
/// ```
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)] // public adapter
pub struct WithPart<T: ?Sized> {
pub part: Part,
pub writeable: T,
}
impl<T: Writeable + ?Sized> Writeable for WithPart<T> {
#[inline]
fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
self.writeable.write_to(sink)
}
#[inline]
fn write_to_parts<W: PartsWrite + ?Sized>(&self, sink: &mut W) -> fmt::Result {
sink.with_part(self.part, |w| self.writeable.write_to_parts(w))
}
#[inline]
fn writeable_length_hint(&self) -> LengthHint {
self.writeable.writeable_length_hint()
}
#[inline]
fn write_to_string(&self) -> Cow<str> {
self.writeable.write_to_string()
}
}
impl<T: Writeable + ?Sized> fmt::Display for WithPart<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Writeable::write_to(&self, f)
}
}

@@ -7,3 +7,3 @@ // This file is part of ICU4X. For terms of use, please see the file

use crate::parts_write_adapter::CoreWriteAsPartsWrite;
use core::{cmp::Ordering, convert::Infallible};
use core::convert::Infallible;

@@ -210,83 +210,2 @@ /// A writeable object that can fail while writing.

}
/// Compares the content of this writeable to a byte slice.
///
/// This function compares the "lossy mode" string; for more information,
/// see [`TryWriteable::try_write_to()`].
///
/// For more information, see [`Writeable::writeable_cmp_bytes()`].
///
/// # Examples
///
/// ```
/// use core::cmp::Ordering;
/// use core::fmt;
/// use writeable::TryWriteable;
/// # use writeable::PartsWrite;
/// # use writeable::LengthHint;
///
/// #[derive(Debug, PartialEq, Eq)]
/// enum HelloWorldWriteableError {
/// MissingName
/// }
///
/// #[derive(Debug, PartialEq, Eq)]
/// struct HelloWorldWriteable {
/// pub name: Option<&'static str>
/// }
///
/// impl TryWriteable for HelloWorldWriteable {
/// type Error = HelloWorldWriteableError;
/// // see impl in TryWriteable docs
/// # fn try_write_to_parts<S: PartsWrite + ?Sized>(
/// # &self,
/// # sink: &mut S,
/// # ) -> Result<Result<(), Self::Error>, fmt::Error> {
/// # sink.write_str("Hello, ")?;
/// # // Use `impl TryWriteable for Result` to generate the error part:
/// # let _ = self.name.ok_or("nobody").try_write_to_parts(sink)?;
/// # sink.write_char('!')?;
/// # // Return a doubly-wrapped Result.
/// # // The outer Result is for fmt::Error, handled by the `?`s above.
/// # // The inner Result is for our own Self::Error.
/// # if self.name.is_some() {
/// # Ok(Ok(()))
/// # } else {
/// # Ok(Err(HelloWorldWriteableError::MissingName))
/// # }
/// # }
/// }
///
/// // Success case:
/// let writeable = HelloWorldWriteable { name: Some("Alice") };
/// let writeable_str = writeable.try_write_to_string().expect("name is Some");
///
/// assert_eq!(Ordering::Equal, writeable.writeable_cmp_bytes(b"Hello, Alice!"));
///
/// assert_eq!(Ordering::Greater, writeable.writeable_cmp_bytes(b"Alice!"));
/// assert_eq!(Ordering::Greater, (*writeable_str).cmp("Alice!"));
///
/// assert_eq!(Ordering::Less, writeable.writeable_cmp_bytes(b"Hello, Bob!"));
/// assert_eq!(Ordering::Less, (*writeable_str).cmp("Hello, Bob!"));
///
/// // Failure case:
/// let writeable = HelloWorldWriteable { name: None };
/// let mut writeable_str = String::new();
/// let _ = writeable.try_write_to(&mut writeable_str).expect("write to String is infallible");
///
/// assert_eq!(Ordering::Equal, writeable.writeable_cmp_bytes(b"Hello, nobody!"));
///
/// assert_eq!(Ordering::Greater, writeable.writeable_cmp_bytes(b"Hello, alice!"));
/// assert_eq!(Ordering::Greater, (*writeable_str).cmp("Hello, alice!"));
///
/// assert_eq!(Ordering::Less, writeable.writeable_cmp_bytes(b"Hello, zero!"));
/// assert_eq!(Ordering::Less, (*writeable_str).cmp("Hello, zero!"));
/// ```
fn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering {
let mut wc = cmp::WriteComparator::new(other);
let _ = self
.try_write_to(&mut wc)
.unwrap_or_else(|fmt::Error| Ok(()));
wc.finish().reverse()
}
}

@@ -340,10 +259,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> Ordering {
match self {
Ok(t) => t.writeable_cmp_bytes(other),
Err(e) => e.writeable_cmp_bytes(other),
}
}
}

@@ -392,7 +303,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
self.0.writeable_cmp_bytes(other)
}
}

@@ -448,7 +354,2 @@

}
#[inline]
fn writeable_cmp_bytes(&self, other: &[u8]) -> core::cmp::Ordering {
self.0.writeable_cmp_bytes(other)
}
}

@@ -472,3 +373,2 @@

/// - Validity of size hint
/// - Reflexivity of `cmp_bytes` and order against largest and smallest strings
///

@@ -519,10 +419,2 @@ /// For a usage example, see [`TryWriteable`].

}
let ordering = actual_writeable.writeable_cmp_bytes($expected_str.as_bytes());
assert_eq!(ordering, core::cmp::Ordering::Equal, $($arg)*);
let ordering = actual_writeable.writeable_cmp_bytes("\u{10FFFF}".as_bytes());
assert_eq!(ordering, core::cmp::Ordering::Less, $($arg)*);
if $expected_str != "" {
let ordering = actual_writeable.writeable_cmp_bytes("".as_bytes());
assert_eq!(ordering, core::cmp::Ordering::Greater, $($arg)*);
}
actual_parts // return for assert_try_writeable_parts_eq

@@ -529,0 +421,0 @@ }};

Sorry, the diff of this file is not supported yet