|
1 | 1 | use core::cell::Cell;
|
2 | 2 | use core::convert::Infallible;
|
3 | 3 | use core::fmt::{self, Write};
|
| 4 | +use core::num::{Saturating, Wrapping}; |
4 | 5 | use core::ops::Deref;
|
5 | 6 | use core::pin::Pin;
|
6 | 7 |
|
7 | 8 | use super::MAX_LEN;
|
8 |
| -use crate::{Error, FastWritable, Result, Values}; |
| 9 | +use crate::{Error, FastWritable, Result, Values, impl_for_ref}; |
9 | 10 |
|
10 | 11 | /// Limit string length, appends '...' if truncated
|
11 | 12 | ///
|
@@ -330,13 +331,13 @@ impl<T: fmt::Display> fmt::Display for Center<T> {
|
330 | 331 | /// # }
|
331 | 332 | /// ```
|
332 | 333 | #[inline]
|
333 |
| -pub fn pluralize<C, S, P>(count: C, singular: S, plural: P) -> Result<Pluralize<S, P>, C::Error> |
| 334 | +pub fn pluralize<C, S, P>(count: C, singular: S, plural: P) -> Result<Either<S, P>, C::Error> |
334 | 335 | where
|
335 | 336 | C: PluralizeCount,
|
336 | 337 | {
|
337 | 338 | match count.is_singular()? {
|
338 |
| - true => Ok(Pluralize::Singular(singular)), |
339 |
| - false => Ok(Pluralize::Plural(plural)), |
| 339 | + true => Ok(Either::Left(singular)), |
| 340 | + false => Ok(Either::Right(plural)), |
340 | 341 | }
|
341 | 342 | }
|
342 | 343 |
|
@@ -426,31 +427,267 @@ const _: () = {
|
426 | 427 | }
|
427 | 428 | };
|
428 | 429 |
|
429 |
| -pub enum Pluralize<S, P> { |
430 |
| - Singular(S), |
431 |
| - Plural(P), |
| 430 | +/// Render `default` if `value` is not the default value, see [`DefaultFilterable`]. |
| 431 | +/// |
| 432 | +/// This function is only used if the optional `boolean` argument to `|default` was true. |
| 433 | +/// Otherwise `value` is used directly. |
| 434 | +#[inline] |
| 435 | +pub fn default<L: DefaultFilterable, R>( |
| 436 | + value: &L, |
| 437 | + default: R, |
| 438 | +) -> Result<Either<L::Filtered<'_>, R>, L::Error> { |
| 439 | + match value.as_filtered()? { |
| 440 | + Some(value) => Ok(Either::Left(value)), |
| 441 | + None => Ok(Either::Right(default)), |
| 442 | + } |
| 443 | +} |
| 444 | + |
| 445 | +/// A type (or a reference to it) that can be used in [`|default`](default). |
| 446 | +/// |
| 447 | +/// The type is either a monad such as [`Option`] or [`Result`], or a type that has a well defined, |
| 448 | +/// trivial default value, e.g. an [empty](str::is_empty) [`str`] or `0` for integer types. |
| 449 | +#[diagnostic::on_unimplemented( |
| 450 | + label = "`{Self}` is not `|default` filterable", |
| 451 | + message = "`{Self}` is not `|default` filterable" |
| 452 | +)] |
| 453 | +pub trait DefaultFilterable { |
| 454 | + /// The contained value |
| 455 | + type Filtered<'a> |
| 456 | + where |
| 457 | + Self: 'a; |
| 458 | + |
| 459 | + /// An error that prevented [`as_filtered()`](DefaultFilterable::as_filtered) to succeed, |
| 460 | + /// e.g. a poisoned state or an unacquirable lock. |
| 461 | + type Error: Into<crate::Error>; |
| 462 | + |
| 463 | + /// Return the contained value, if a value was contained, and it's not the default value. |
| 464 | + /// |
| 465 | + /// Returns `Ok(None)` if the value could not be unwrapped. |
| 466 | + fn as_filtered(&self) -> Result<Option<Self::Filtered<'_>>, Self::Error>; |
| 467 | +} |
| 468 | + |
| 469 | +const _: () = { |
| 470 | + impl_for_ref! { |
| 471 | + impl DefaultFilterable for T { |
| 472 | + type Filtered<'a> = T::Filtered<'a> |
| 473 | + where |
| 474 | + Self: 'a; |
| 475 | + |
| 476 | + type Error = T::Error; |
| 477 | + |
| 478 | + #[inline] |
| 479 | + fn as_filtered(&self) -> Result<Option<Self::Filtered<'_>>, Self::Error> { |
| 480 | + <T>::as_filtered(self) |
| 481 | + } |
| 482 | + } |
| 483 | + } |
| 484 | + |
| 485 | + impl<T> DefaultFilterable for Pin<T> |
| 486 | + where |
| 487 | + T: Deref, |
| 488 | + <T as Deref>::Target: DefaultFilterable, |
| 489 | + { |
| 490 | + type Filtered<'a> |
| 491 | + = <<T as Deref>::Target as DefaultFilterable>::Filtered<'a> |
| 492 | + where |
| 493 | + Self: 'a; |
| 494 | + |
| 495 | + type Error = <<T as Deref>::Target as DefaultFilterable>::Error; |
| 496 | + |
| 497 | + #[inline] |
| 498 | + fn as_filtered(&self) -> Result<Option<Self::Filtered<'_>>, Self::Error> { |
| 499 | + self.as_ref().get_ref().as_filtered() |
| 500 | + } |
| 501 | + } |
| 502 | + |
| 503 | + impl<T> DefaultFilterable for Option<T> { |
| 504 | + type Filtered<'a> |
| 505 | + = &'a T |
| 506 | + where |
| 507 | + Self: 'a; |
| 508 | + |
| 509 | + type Error = Infallible; |
| 510 | + |
| 511 | + #[inline] |
| 512 | + fn as_filtered(&self) -> Result<Option<&T>, Infallible> { |
| 513 | + Ok(self.as_ref()) |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + impl<T, E> DefaultFilterable for Result<T, E> { |
| 518 | + type Filtered<'a> |
| 519 | + = &'a T |
| 520 | + where |
| 521 | + Self: 'a; |
| 522 | + |
| 523 | + type Error = Infallible; |
| 524 | + |
| 525 | + #[inline] |
| 526 | + fn as_filtered(&self) -> Result<Option<&T>, Infallible> { |
| 527 | + Ok(self.as_ref().ok()) |
| 528 | + } |
| 529 | + } |
| 530 | + |
| 531 | + impl DefaultFilterable for str { |
| 532 | + type Filtered<'a> |
| 533 | + = &'a str |
| 534 | + where |
| 535 | + Self: 'a; |
| 536 | + |
| 537 | + type Error = Infallible; |
| 538 | + |
| 539 | + #[inline] |
| 540 | + fn as_filtered(&self) -> Result<Option<&str>, Infallible> { |
| 541 | + match self.is_empty() { |
| 542 | + false => Ok(Some(self)), |
| 543 | + true => Ok(None), |
| 544 | + } |
| 545 | + } |
| 546 | + } |
| 547 | + |
| 548 | + #[cfg(feature = "alloc")] |
| 549 | + impl DefaultFilterable for alloc::string::String { |
| 550 | + type Filtered<'a> |
| 551 | + = &'a str |
| 552 | + where |
| 553 | + Self: 'a; |
| 554 | + |
| 555 | + type Error = Infallible; |
| 556 | + |
| 557 | + #[inline] |
| 558 | + fn as_filtered(&self) -> Result<Option<&str>, Infallible> { |
| 559 | + self.as_str().as_filtered() |
| 560 | + } |
| 561 | + } |
| 562 | + |
| 563 | + #[cfg(feature = "alloc")] |
| 564 | + impl<T: DefaultFilterable + alloc::borrow::ToOwned + ?Sized> DefaultFilterable |
| 565 | + for alloc::borrow::Cow<'_, T> |
| 566 | + { |
| 567 | + type Filtered<'a> |
| 568 | + = T::Filtered<'a> |
| 569 | + where |
| 570 | + Self: 'a; |
| 571 | + |
| 572 | + type Error = T::Error; |
| 573 | + |
| 574 | + #[inline] |
| 575 | + fn as_filtered(&self) -> Result<Option<Self::Filtered<'_>>, Self::Error> { |
| 576 | + self.as_ref().as_filtered() |
| 577 | + } |
| 578 | + } |
| 579 | + |
| 580 | + impl<T: DefaultFilterable> DefaultFilterable for Wrapping<T> { |
| 581 | + type Filtered<'a> |
| 582 | + = T::Filtered<'a> |
| 583 | + where |
| 584 | + Self: 'a; |
| 585 | + |
| 586 | + type Error = T::Error; |
| 587 | + |
| 588 | + #[inline] |
| 589 | + fn as_filtered(&self) -> Result<Option<Self::Filtered<'_>>, Self::Error> { |
| 590 | + self.0.as_filtered() |
| 591 | + } |
| 592 | + } |
| 593 | + |
| 594 | + impl<T: DefaultFilterable> DefaultFilterable for Saturating<T> { |
| 595 | + type Filtered<'a> |
| 596 | + = T::Filtered<'a> |
| 597 | + where |
| 598 | + Self: 'a; |
| 599 | + |
| 600 | + type Error = T::Error; |
| 601 | + |
| 602 | + #[inline] |
| 603 | + fn as_filtered(&self) -> Result<Option<Self::Filtered<'_>>, Self::Error> { |
| 604 | + self.0.as_filtered() |
| 605 | + } |
| 606 | + } |
| 607 | + |
| 608 | + macro_rules! impl_for_int { |
| 609 | + ($($ty:ty)*) => { $( |
| 610 | + impl DefaultFilterable for $ty { |
| 611 | + type Filtered<'a> = $ty; |
| 612 | + type Error = Infallible; |
| 613 | + |
| 614 | + #[inline] |
| 615 | + fn as_filtered(&self) -> Result<Option<$ty>, Infallible> { |
| 616 | + match *self { |
| 617 | + 0 => Ok(None), |
| 618 | + value => Ok(Some(value)), |
| 619 | + } |
| 620 | + } |
| 621 | + } |
| 622 | + )* }; |
| 623 | + } |
| 624 | + |
| 625 | + impl_for_int!( |
| 626 | + u8 u16 u32 u64 u128 usize |
| 627 | + i8 i16 i32 i64 i128 isize |
| 628 | + ); |
| 629 | + |
| 630 | + macro_rules! impl_for_non_zero { |
| 631 | + ($($name:ident : $ty:ty)*) => { $( |
| 632 | + impl DefaultFilterable for core::num::$name { |
| 633 | + type Filtered<'a> = $ty; |
| 634 | + type Error = Infallible; |
| 635 | + |
| 636 | + #[inline] |
| 637 | + fn as_filtered(&self) -> Result<Option<$ty>, Infallible> { |
| 638 | + Ok(Some(self.get())) |
| 639 | + } |
| 640 | + } |
| 641 | + )* }; |
| 642 | + } |
| 643 | + |
| 644 | + impl_for_non_zero!( |
| 645 | + NonZeroU8:u8 NonZeroU16:u16 NonZeroU32:u32 NonZeroU64:u64 NonZeroU128:u128 NonZeroUsize:usize |
| 646 | + NonZeroI8:i8 NonZeroI16:i16 NonZeroI32:i32 NonZeroI64:i64 NonZeroI128:i128 NonZeroIsize:isize |
| 647 | + ); |
| 648 | + |
| 649 | + impl DefaultFilterable for bool { |
| 650 | + type Filtered<'a> = bool; |
| 651 | + type Error = Infallible; |
| 652 | + |
| 653 | + #[inline] |
| 654 | + fn as_filtered(&self) -> Result<Option<bool>, Infallible> { |
| 655 | + match *self { |
| 656 | + true => Ok(Some(true)), |
| 657 | + false => Ok(None), |
| 658 | + } |
| 659 | + } |
| 660 | + } |
| 661 | +}; |
| 662 | + |
| 663 | +/// Render either `L` or `R` |
| 664 | +pub enum Either<L, R> { |
| 665 | + /// First variant |
| 666 | + Left(L), |
| 667 | + /// Second variant |
| 668 | + Right(R), |
432 | 669 | }
|
433 | 670 |
|
434 |
| -impl<S: fmt::Display, P: fmt::Display> fmt::Display for Pluralize<S, P> { |
| 671 | +impl<L: fmt::Display, R: fmt::Display> fmt::Display for Either<L, R> { |
435 | 672 | #[inline]
|
436 | 673 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
437 | 674 | match self {
|
438 |
| - Pluralize::Singular(value) => write!(f, "{value}"), |
439 |
| - Pluralize::Plural(value) => write!(f, "{value}"), |
| 675 | + Either::Left(value) => write!(f, "{value}"), |
| 676 | + Either::Right(value) => write!(f, "{value}"), |
440 | 677 | }
|
441 | 678 | }
|
442 | 679 | }
|
443 | 680 |
|
444 |
| -impl<S: FastWritable, P: FastWritable> FastWritable for Pluralize<S, P> { |
| 681 | +impl<L: FastWritable, R: FastWritable> FastWritable for Either<L, R> { |
445 | 682 | #[inline]
|
446 | 683 | fn write_into<W: fmt::Write + ?Sized>(
|
447 | 684 | &self,
|
448 | 685 | dest: &mut W,
|
449 | 686 | values: &dyn Values,
|
450 | 687 | ) -> crate::Result<()> {
|
451 | 688 | match self {
|
452 |
| - Pluralize::Singular(value) => value.write_into(dest, values), |
453 |
| - Pluralize::Plural(value) => value.write_into(dest, values), |
| 689 | + Either::Left(value) => value.write_into(dest, values), |
| 690 | + Either::Right(value) => value.write_into(dest, values), |
454 | 691 | }
|
455 | 692 | }
|
456 | 693 | }
|
|
0 commit comments