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
use core::fmt;
use core::str;

/// Box of two strings.
/// Store two strings efficiently in an immutable way.
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct TwoStrs(Box<[u8]>);

impl From<(&str, &str)> for TwoStrs {
    fn from((s1, s2): (&str, &str)) -> Self {
        Self::new(s1, s2)
    }
}

impl TwoStrs {
    /// * `s1` - must not contain null byte.
    /// * `s2` - must not contain null byte.
    pub fn new(s1: &str, s2: &str) -> Self {
        let mut bytes = Vec::with_capacity(s1.len() + 1 + s2.len());
        bytes.extend_from_slice(s1.as_bytes());
        bytes.push(0);
        bytes.extend_from_slice(s2.as_bytes());

        Self(bytes.into_boxed_slice())
    }

    pub fn get(&self) -> (&str, &str) {
        let pos = self.0.iter().position(|byte| *byte == 0).unwrap();

        (
            unsafe { str::from_utf8_unchecked(&self.0[..pos]) },
            unsafe { str::from_utf8_unchecked(&self.0[pos + 1..]) },
        )
    }
}

impl fmt::Display for TwoStrs {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        let (s1, s2) = self.get();
        write!(f, "({}, {})", s1, s2)
    }
}

#[cfg(test)]
mod tests {
    use super::TwoStrs;

    fn assert(s1: &str, s2: &str) {
        let two_strs = TwoStrs::new(s1, s2);
        assert_eq!(two_strs.get(), (s1, s2));
    }

    #[test]
    fn test() {
        assert("", "");
        assert("12", "");
        assert("", "12");
        assert("12", "12");
        assert("12", "2333");
        assert("acdbd3", "2333");
    }
}