1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
pub use unicode_width::{UnicodeWidthChar, UnicodeWidthStr, UNICODE_VERSION};

use core::fmt::{Display, Error, Formatter};
use derive_more::{AsMut, AsRef, Deref, DerefMut, From};

/// Value that has width.
pub trait Width: Display {
    /// Get width of the value.
    fn width(&self) -> usize;
}

impl Width for str {
    fn width(&self) -> usize {
        UnicodeWidthStr::width(self)
    }
}

impl Width for &str {
    fn width(&self) -> usize {
        UnicodeWidthStr::width(*self)
    }
}

#[cfg(feature = "std")]
impl Width for String {
    fn width(&self) -> usize {
        UnicodeWidthStr::width(self.as_str())
    }
}

impl<X: Width + Sized> Width for &X {
    fn width(&self) -> usize {
        X::width(*self)
    }
}

macro_rules! wrapper {
    (
        $(#[$attributes:meta])*
        $name:ident = $get_width:expr
    ) => {
        $(#[$attributes])*
        #[derive(Debug, Clone, Copy, PartialEq, Eq, AsMut, AsRef, Deref, DerefMut, From)]
        pub struct $name<Inner: AsRef<str>>(Inner);

        impl<Inner: AsRef<str>> $name<Inner> {
            #[doc = "Extract the inner value."]
            pub fn into_inner(self) -> Inner {
                self.0
            }

            #[doc = "Get reference to inner value."]
            pub fn as_inner(&self) -> &'_ Inner {
                self.as_ref()
            }

            #[doc = "Get reference to inner `str`."]
            pub fn as_str(&self) -> &'_ str {
                self.as_ref()
            }
        }

        impl<Inner: AsRef<str>> Width for $name<Inner> {
            fn width(&self) -> usize {
                $get_width(self.as_str())
            }
        }

        impl<Inner: AsRef<str>> AsRef<str> for $name<Inner> {
            fn as_ref(&self) -> &'_ str {
                self.as_inner().as_ref()
            }
        }

        impl<Inner: AsRef<str>> Display for $name<Inner> {
            fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), Error> {
                write!(formatter, "{}", self.as_str())
            }
        }
    };
}

wrapper! {
    #[doc = "Treat [`UnicodeWidthStr::width`] as width."]
    UnicodeWidth = UnicodeWidthStr::width
}

wrapper! {
    #[doc = "Treat [`UnicodeWidthStr::width_cjk`] as width."]
    UnicodeWidthCjk = UnicodeWidthStr::width_cjk
}

wrapper! {
    #[doc = "Treat character count as width."]
    CharCount = |x: &str| x.chars().count()
}

wrapper! {
    #[doc = "Treat `str::len` as width."]
    Len = str::len
}