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
use std::string::FromUtf16Error;
use unicode_width::UnicodeWidthStr;


#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub enum TextAlignment {
    Left,
    Right,
}

pub trait PadString {
    fn pad_left(&self, width: usize) -> String {
        self.pad(width, ' ', TextAlignment::Right)
    }

    fn pad_right(&self, width: usize) -> String {
        self.pad(width, ' ', TextAlignment::Left)
    }

    fn pad_left_with(&self, width: usize, character: char) -> String {
        self.pad(width, character, TextAlignment::Right)
    }

    fn pad_right_with(&self, width: usize, character: char) -> String {
        self.pad(width, character, TextAlignment::Left)
    }

    fn pad_to_width_with_alignment(&self, width: usize, alignment: TextAlignment) -> String {
        self.pad(width, ' ', alignment)
    }

    fn pad(&self, width: usize, character: char, alignment: TextAlignment) -> String;
}

impl PadString for str {
    fn pad(&self, width: usize, character: char, alignment: TextAlignment) -> String {
        let display_columns = UnicodeWidthStr::width(self);

        if display_columns >= width {
            self.to_string()
        } else {
            let required = width - display_columns;
            let mut string = String::with_capacity(self.len() + required);
            let (left, right) = match alignment {
                TextAlignment::Left => (0, required),
                TextAlignment::Right => (required, 0),
            };

            (0..left).for_each(|_| string.push(character));
            string.push_str(self);
            (0..right).for_each(|_| string.push(character));

            string
        }
    }
}


pub fn to_utf16(string: &str) -> Vec<u16> {
    string.encode_utf16().collect()
}

pub fn to_utf16_null(string: &str) -> Vec<u16> {
    string.encode_utf16().chain(Some(0)).collect()
}


pub fn from_utf16(data: &[u16]) -> Result<String, FromUtf16Error> {
    String::from_utf16(data)
}

pub fn from_utf16_null(data: &[u16]) -> Result<String, FromUtf16Error> {
    let data = utf16_extent(data);

    String::from_utf16(data)
}


pub fn from_utf16_lossy(data: &[u16]) -> String {
    String::from_utf16_lossy(data)
}

pub fn from_utf16_lossy_null(data: &[u16]) -> String {
    let data = utf16_extent(data);

    String::from_utf16_lossy(data)
}


fn utf16_extent(data: &[u16]) -> &[u16] {
    let length = data.iter().position(|x| *x == 0).unwrap_or(data.len());

    &data[..length]
}