1use core::cell::Cell;
2use core::convert::Infallible;
3use core::fmt::{self, Write};
4use core::ops::Deref;
5use core::pin::Pin;
6
7use super::MAX_LEN;
8use crate::{Error, FastWritable, Result, Values};
9
10#[inline]
31pub fn truncate<S: fmt::Display>(
32 source: S,
33 remaining: usize,
34) -> Result<TruncateFilter<S>, Infallible> {
35 Ok(TruncateFilter { source, remaining })
36}
37
38pub struct TruncateFilter<S> {
39 source: S,
40 remaining: usize,
41}
42
43impl<S: fmt::Display> fmt::Display for TruncateFilter<S> {
44 #[inline]
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 write!(TruncateWriter::new(f, self.remaining), "{}", self.source)
47 }
48}
49
50impl<S: FastWritable> FastWritable for TruncateFilter<S> {
51 #[inline]
52 fn write_into<W: fmt::Write + ?Sized>(
53 &self,
54 dest: &mut W,
55 values: &dyn Values,
56 ) -> crate::Result<()> {
57 self.source
58 .write_into(&mut TruncateWriter::new(dest, self.remaining), values)
59 }
60}
61
62struct TruncateWriter<W> {
63 dest: Option<W>,
64 remaining: usize,
65}
66
67impl<W> TruncateWriter<W> {
68 fn new(dest: W, remaining: usize) -> Self {
69 TruncateWriter {
70 dest: Some(dest),
71 remaining,
72 }
73 }
74}
75
76impl<W: fmt::Write> fmt::Write for TruncateWriter<W> {
77 fn write_str(&mut self, s: &str) -> fmt::Result {
78 let Some(dest) = &mut self.dest else {
79 return Ok(());
80 };
81 let mut rem = self.remaining;
82 if rem >= s.len() {
83 dest.write_str(s)?;
84 self.remaining -= s.len();
85 } else {
86 if rem > 0 {
87 while !s.is_char_boundary(rem) {
88 rem += 1;
89 }
90 if rem == s.len() {
91 self.remaining = 0;
93 return dest.write_str(s);
94 }
95 dest.write_str(&s[..rem])?;
96 }
97 dest.write_str("...")?;
98 self.dest = None;
99 }
100 Ok(())
101 }
102
103 #[inline]
104 fn write_char(&mut self, c: char) -> fmt::Result {
105 match self.dest.is_some() {
106 true => self.write_str(c.encode_utf8(&mut [0; 4])),
107 false => Ok(()),
108 }
109 }
110
111 #[inline]
112 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
113 match self.dest.is_some() {
114 true => fmt::write(self, args),
115 false => Ok(()),
116 }
117 }
118}
119
120#[inline]
141pub fn join<I, S>(input: I, separator: S) -> Result<JoinFilter<I, S>, Infallible>
142where
143 I: IntoIterator,
144 I::Item: fmt::Display,
145 S: fmt::Display,
146{
147 Ok(JoinFilter(Cell::new(Some((input, separator)))))
148}
149
150pub struct JoinFilter<I, S>(Cell<Option<(I, S)>>);
163
164impl<I, S> fmt::Display for JoinFilter<I, S>
165where
166 I: IntoIterator,
167 I::Item: fmt::Display,
168 S: fmt::Display,
169{
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 let Some((iter, separator)) = self.0.take() else {
172 return Ok(());
173 };
174 for (idx, token) in iter.into_iter().enumerate() {
175 match idx {
176 0 => f.write_fmt(format_args!("{token}"))?,
177 _ => f.write_fmt(format_args!("{separator}{token}"))?,
178 }
179 }
180 Ok(())
181 }
182}
183
184#[inline]
205pub fn center<T: fmt::Display>(src: T, width: usize) -> Result<Center<T>, Infallible> {
206 Ok(Center { src, width })
207}
208
209pub struct Center<T> {
210 src: T,
211 width: usize,
212}
213
214impl<T: fmt::Display> fmt::Display for Center<T> {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 if self.width < MAX_LEN {
217 write!(f, "{: ^1$}", self.src, self.width)
218 } else {
219 write!(f, "{}", self.src)
220 }
221 }
222}
223
224#[inline]
333pub fn pluralize<C, S, P>(count: C, singular: S, plural: P) -> Result<Pluralize<S, P>, C::Error>
334where
335 C: PluralizeCount,
336{
337 match count.is_singular()? {
338 true => Ok(Pluralize::Singular(singular)),
339 false => Ok(Pluralize::Plural(plural)),
340 }
341}
342
343pub trait PluralizeCount {
345 type Error: Into<Error>;
347
348 fn is_singular(&self) -> Result<bool, Self::Error>;
350}
351
352const _: () = {
353 crate::impl_for_ref! {
354 impl PluralizeCount for T {
355 type Error = T::Error;
356
357 #[inline]
358 fn is_singular(&self) -> Result<bool, Self::Error> {
359 <T>::is_singular(self)
360 }
361 }
362 }
363
364 impl<T> PluralizeCount for Pin<T>
365 where
366 T: Deref,
367 <T as Deref>::Target: PluralizeCount,
368 {
369 type Error = <<T as Deref>::Target as PluralizeCount>::Error;
370
371 #[inline]
372 fn is_singular(&self) -> Result<bool, Self::Error> {
373 self.as_ref().get_ref().is_singular()
374 }
375 }
376
377 macro_rules! impl_pluralize_for_unsigned_int {
379 ($($ty:ty)*) => { $(
380 impl PluralizeCount for $ty {
381 type Error = Infallible;
382
383 #[inline]
384 fn is_singular(&self) -> Result<bool, Self::Error> {
385 Ok(*self == 1)
386 }
387 }
388 )* };
389 }
390
391 impl_pluralize_for_unsigned_int!(u8 u16 u32 u64 u128 usize);
392
393 macro_rules! impl_pluralize_for_signed_int {
395 ($($ty:ty)*) => { $(
396 impl PluralizeCount for $ty {
397 type Error = Infallible;
398
399 #[inline]
400 fn is_singular(&self) -> Result<bool, Self::Error> {
401 Ok(*self == 1 || *self == -1)
402 }
403 }
404 )* };
405 }
406
407 impl_pluralize_for_signed_int!(i8 i16 i32 i64 i128 isize);
408
409 macro_rules! impl_pluralize_for_non_zero {
411 ($($ty:ident)*) => { $(
412 impl PluralizeCount for core::num::$ty {
413 type Error = Infallible;
414
415 #[inline]
416 fn is_singular(&self) -> Result<bool, Self::Error> {
417 self.get().is_singular()
418 }
419 }
420 )* };
421 }
422
423 impl_pluralize_for_non_zero! {
424 NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize
425 NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
426 }
427};
428
429pub enum Pluralize<S, P> {
430 Singular(S),
431 Plural(P),
432}
433
434impl<S: fmt::Display, P: fmt::Display> fmt::Display for Pluralize<S, P> {
435 #[inline]
436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 match self {
438 Pluralize::Singular(value) => write!(f, "{value}"),
439 Pluralize::Plural(value) => write!(f, "{value}"),
440 }
441 }
442}
443
444impl<S: FastWritable, P: FastWritable> FastWritable for Pluralize<S, P> {
445 #[inline]
446 fn write_into<W: fmt::Write + ?Sized>(
447 &self,
448 dest: &mut W,
449 values: &dyn Values,
450 ) -> crate::Result<()> {
451 match self {
452 Pluralize::Singular(value) => value.write_into(dest, values),
453 Pluralize::Plural(value) => value.write_into(dest, values),
454 }
455 }
456}
457
458#[cfg(all(test, feature = "alloc"))]
459mod tests {
460 use alloc::string::{String, ToString};
461 use alloc::vec::Vec;
462
463 use super::*;
464
465 #[allow(clippy::needless_borrow)]
466 #[test]
467 fn test_join() {
468 assert_eq!(
469 join((&["hello", "world"]).iter(), ", ")
470 .unwrap()
471 .to_string(),
472 "hello, world"
473 );
474 assert_eq!(
475 join((&["hello"]).iter(), ", ").unwrap().to_string(),
476 "hello"
477 );
478
479 let empty: &[&str] = &[];
480 assert_eq!(join(empty.iter(), ", ").unwrap().to_string(), "");
481
482 let input: Vec<String> = alloc::vec!["foo".into(), "bar".into(), "bazz".into()];
483 assert_eq!(join(input.iter(), ":").unwrap().to_string(), "foo:bar:bazz");
484
485 let input: &[String] = &["foo".into(), "bar".into()];
486 assert_eq!(join(input.iter(), ":").unwrap().to_string(), "foo:bar");
487
488 let real: String = "blah".into();
489 let input: Vec<&str> = alloc::vec![&real];
490 assert_eq!(join(input.iter(), ";").unwrap().to_string(), "blah");
491
492 assert_eq!(
493 join((&&&&&["foo", "bar"]).iter(), ", ")
494 .unwrap()
495 .to_string(),
496 "foo, bar"
497 );
498 }
499
500 #[test]
501 fn test_center() {
502 assert_eq!(center("f", 3).unwrap().to_string(), " f ".to_string());
503 assert_eq!(center("f", 4).unwrap().to_string(), " f ".to_string());
504 assert_eq!(center("foo", 1).unwrap().to_string(), "foo".to_string());
505 assert_eq!(
506 center("foo bar", 8).unwrap().to_string(),
507 "foo bar ".to_string()
508 );
509 assert_eq!(
510 center("foo", 111_669_149_696).unwrap().to_string(),
511 "foo".to_string()
512 );
513 }
514}