/rust/registry/src/index.crates.io-1949cf8c6b5b557f/writeable-0.6.3/src/cmp.rs
Line | Count | Source |
1 | | // This file is part of ICU4X. For terms of use, please see the file |
2 | | // called LICENSE at the top level of the ICU4X source tree |
3 | | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | | |
5 | | use crate::Writeable; |
6 | | use core::cmp::Ordering; |
7 | | use core::fmt; |
8 | | |
9 | | struct WriteComparator<'a> { |
10 | | code_units: &'a [u8], |
11 | | result: Ordering, |
12 | | } |
13 | | |
14 | | /// This is an infallible impl. Functions always return Ok, not Err. |
15 | | impl fmt::Write for WriteComparator<'_> { |
16 | | #[inline] |
17 | 0 | fn write_str(&mut self, other: &str) -> fmt::Result { |
18 | 0 | if self.result != Ordering::Equal { |
19 | 0 | return Ok(()); |
20 | 0 | } |
21 | 0 | let (this, remainder) = self |
22 | 0 | .code_units |
23 | 0 | .split_at_checked(other.len()) |
24 | 0 | .unwrap_or((self.code_units, &[])); |
25 | 0 | self.code_units = remainder; |
26 | 0 | self.result = this.cmp(other.as_bytes()); |
27 | 0 | Ok(()) |
28 | 0 | } Unexecuted instantiation: <writeable::cmp::WriteComparator as core::fmt::Write>::write_str Unexecuted instantiation: <writeable::cmp::WriteComparator as core::fmt::Write>::write_str |
29 | | } |
30 | | |
31 | | impl<'a> WriteComparator<'a> { |
32 | | #[inline] |
33 | 0 | fn new(code_units: &'a [u8]) -> Self { |
34 | 0 | Self { |
35 | 0 | code_units, |
36 | 0 | result: Ordering::Equal, |
37 | 0 | } |
38 | 0 | } Unexecuted instantiation: <writeable::cmp::WriteComparator>::new Unexecuted instantiation: <writeable::cmp::WriteComparator>::new |
39 | | |
40 | | #[inline] |
41 | 0 | fn finish(self) -> Ordering { |
42 | 0 | if matches!(self.result, Ordering::Equal) && !self.code_units.is_empty() { |
43 | | // Self is longer than Other |
44 | 0 | Ordering::Greater |
45 | | } else { |
46 | 0 | self.result |
47 | | } |
48 | 0 | } Unexecuted instantiation: <writeable::cmp::WriteComparator>::finish Unexecuted instantiation: <writeable::cmp::WriteComparator>::finish |
49 | | } |
50 | | |
51 | | /// Compares the contents of a [`Writeable`] to the given UTF-8 bytes without allocating memory. |
52 | | /// |
53 | | /// For more details, see: [`cmp_str`] |
54 | 0 | pub fn cmp_utf8(writeable: &impl Writeable, other: &[u8]) -> Ordering { |
55 | 0 | let mut wc = WriteComparator::new(other); |
56 | 0 | let _ = writeable.write_to(&mut wc); |
57 | 0 | wc.finish().reverse() |
58 | 0 | } Unexecuted instantiation: writeable::cmp::cmp_utf8::<icu_locale_core::data::DataLocale> Unexecuted instantiation: writeable::cmp::cmp_utf8::<icu_locale_core::langid::LanguageIdentifier> Unexecuted instantiation: writeable::cmp::cmp_utf8::<icu_locale_core::locale::Locale> Unexecuted instantiation: writeable::cmp::cmp_utf8::<icu_locale_core::extensions::unicode::value::Value> Unexecuted instantiation: writeable::cmp::cmp_utf8::<icu_locale_core::extensions::unicode::keywords::Keywords> Unexecuted instantiation: writeable::cmp::cmp_utf8::<_> |
59 | | |
60 | | /// Compares the contents of a `Writeable` to the given bytes |
61 | | /// without allocating a String to hold the `Writeable` contents. |
62 | | /// |
63 | | /// This returns a lexicographical comparison, the same as if the Writeable |
64 | | /// were first converted to a String and then compared with `Ord`. For a |
65 | | /// string ordering suitable for display to end users, use a localized |
66 | | /// collation crate, such as `icu_collator`. |
67 | | /// |
68 | | /// # Examples |
69 | | /// |
70 | | /// ``` |
71 | | /// use core::cmp::Ordering; |
72 | | /// use core::fmt; |
73 | | /// use writeable::Writeable; |
74 | | /// |
75 | | /// struct WelcomeMessage<'s> { |
76 | | /// pub name: &'s str, |
77 | | /// } |
78 | | /// |
79 | | /// impl<'s> Writeable for WelcomeMessage<'s> { |
80 | | /// // see impl in Writeable docs |
81 | | /// # fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result { |
82 | | /// # sink.write_str("Hello, ")?; |
83 | | /// # sink.write_str(self.name)?; |
84 | | /// # sink.write_char('!')?; |
85 | | /// # Ok(()) |
86 | | /// # } |
87 | | /// } |
88 | | /// |
89 | | /// let message = WelcomeMessage { name: "Alice" }; |
90 | | /// let message_str = message.write_to_string(); |
91 | | /// |
92 | | /// assert_eq!(Ordering::Equal, writeable::cmp_str(&message, "Hello, Alice!")); |
93 | | /// |
94 | | /// assert_eq!(Ordering::Greater, writeable::cmp_str(&message, "Alice!")); |
95 | | /// assert_eq!(Ordering::Greater, (*message_str).cmp("Alice!")); |
96 | | /// |
97 | | /// assert_eq!(Ordering::Less, writeable::cmp_str(&message, "Hello, Bob!")); |
98 | | /// assert_eq!(Ordering::Less, (*message_str).cmp("Hello, Bob!")); |
99 | | /// ``` |
100 | | /// |
101 | | /// This function can be combined with `writeable::concat_writeable!` to make an efficient |
102 | | /// comparison between a string and a sequence of substrings: |
103 | | /// |
104 | | /// ``` |
105 | | /// use core::cmp::Ordering; |
106 | | /// |
107 | | /// assert_eq!( |
108 | | /// Ordering::Less, |
109 | | /// writeable::cmp_str(&writeable::concat_writeable!("loop", 1), "loop12") |
110 | | /// ); |
111 | | /// assert_eq!( |
112 | | /// Ordering::Equal, |
113 | | /// writeable::cmp_str(&writeable::concat_writeable!("loop", 12), "loop12") |
114 | | /// ); |
115 | | /// assert_eq!( |
116 | | /// Ordering::Greater, |
117 | | /// writeable::cmp_str(&writeable::concat_writeable!("loop", 2), "loop12") |
118 | | /// ); |
119 | | /// ``` |
120 | | #[inline] |
121 | 0 | pub fn cmp_str(writeable: &impl Writeable, other: &str) -> Ordering { |
122 | 0 | cmp_utf8(writeable, other.as_bytes()) |
123 | 0 | } |
124 | | |
125 | | #[cfg(test)] |
126 | | mod tests { |
127 | | use super::*; |
128 | | use core::fmt::Write; |
129 | | |
130 | | mod data { |
131 | | include!("../tests/data/data.rs"); |
132 | | } |
133 | | |
134 | | #[test] |
135 | | fn test_write_char() { |
136 | | for a in data::KEBAB_CASE_STRINGS { |
137 | | for b in data::KEBAB_CASE_STRINGS { |
138 | | let mut wc = WriteComparator::new(a.as_bytes()); |
139 | | for ch in b.chars() { |
140 | | wc.write_char(ch).unwrap(); |
141 | | } |
142 | | assert_eq!(a.cmp(b), wc.finish(), "{a} <=> {b}"); |
143 | | } |
144 | | } |
145 | | } |
146 | | |
147 | | #[test] |
148 | | fn test_write_str() { |
149 | | for a in data::KEBAB_CASE_STRINGS { |
150 | | for b in data::KEBAB_CASE_STRINGS { |
151 | | let mut wc = WriteComparator::new(a.as_bytes()); |
152 | | wc.write_str(b).unwrap(); |
153 | | assert_eq!(a.cmp(b), wc.finish(), "{a} <=> {b}"); |
154 | | } |
155 | | } |
156 | | } |
157 | | |
158 | | #[test] |
159 | | fn test_mixed() { |
160 | | for a in data::KEBAB_CASE_STRINGS { |
161 | | for b in data::KEBAB_CASE_STRINGS { |
162 | | let mut wc = WriteComparator::new(a.as_bytes()); |
163 | | let mut first = true; |
164 | | for substr in b.split('-') { |
165 | | if first { |
166 | | first = false; |
167 | | } else { |
168 | | wc.write_char('-').unwrap(); |
169 | | } |
170 | | wc.write_str(substr).unwrap(); |
171 | | } |
172 | | assert_eq!(a.cmp(b), wc.finish(), "{a} <=> {b}"); |
173 | | } |
174 | | } |
175 | | } |
176 | | } |