tina-core 0.0.2

Tina platform
Documentation
//! 字串拼接器
use once_cell::sync::Lazy;
use std::ops::AddAssign;

static EMPTY_DATA: Lazy<Vec<u8>> = Lazy::new(Vec::new);

/// 字符串拼接器
#[derive(Clone, Debug)]
pub struct StringJoiner {
    prefix: Option<Vec<u8>>,
    suffix: Option<Vec<u8>>,
    delimiter: Option<Vec<u8>>,
    data: Vec<u8>,
}

impl StringJoiner {
    /// 构建字符串拼接器
    pub fn new(prefix: Option<&str>, suffix: Option<&str>, delimiter: Option<&str>) -> Self {
        Self {
            prefix: prefix.map(|s| Vec::from(s.as_bytes())),
            suffix: suffix.map(|s| Vec::from(s.as_bytes())),
            delimiter: delimiter.map(|s| Vec::from(s.as_bytes())),
            data: match prefix {
                None => Vec::new(),
                Some(prefix) => Vec::from(prefix.as_bytes()),
            },
        }
    }
    /// 构建字符串拼接器
    pub fn with_capacity(capacity: usize, prefix: Option<&str>, suffix: Option<&str>, delimiter: Option<&str>) -> Self {
        Self {
            prefix: prefix.map(|s| Vec::from(s.as_bytes())),
            suffix: suffix.map(|s| Vec::from(s.as_bytes())),
            delimiter: delimiter.map(|s| Vec::from(s.as_bytes())),
            data: match prefix {
                None => Vec::with_capacity(capacity),
                Some(prefix) => {
                    let mut data = Vec::with_capacity(capacity);
                    data.extend_from_slice(prefix.as_bytes());
                    data
                }
            },
        }
    }
    /// 添加字符(每次push, 最终生成字符串时, 都会添加分隔符)
    pub fn push(&mut self, c: char) -> &mut Self {
        *self += String::from(c);
        self
    }
    /// 添加字符串(每次push, 最终生成字符串时, 都会添加分隔符)
    pub fn push_str(&mut self, str: &str) -> &mut Self {
        *self += str;
        self
    }
    /// 添加字符串(每次push, 最终生成字符串时, 都会添加分隔符)
    pub fn push_string(&mut self, s: String) -> &mut Self {
        *self += s;
        self
    }
    /// 添加字符串拼接器(每次push, 最终生成字符串时, 都会添加分隔符)
    pub fn push_string_joiner(&mut self, other: StringJoiner) -> &mut Self {
        *self += other.into_string();
        self
    }
    /// 转为String
    pub fn into_string(self) -> String {
        let buf = self.into_vec();
        String::from_utf8_lossy(buf.as_slice()).to_string()
    }
    /// 判断是否有无内容
    pub fn is_empty(&self) -> bool {
        self.data.is_empty() || Some(&self.data) == self.prefix.as_ref()
    }
    /// 转为二进制
    pub fn into_vec(self) -> Vec<u8> {
        let empty_flag = self.is_empty();
        let Self {
            prefix: _,
            suffix,
            delimiter: _,
            mut data,
        } = self;
        match empty_flag {
            true => Vec::new(),
            false => match suffix {
                None => data,
                Some(mut suffix) => {
                    data.append(&mut suffix);
                    data
                }
            },
        }
    }
    /// 转为二进制
    pub fn to_vec(&self) -> Vec<u8> {
        let prefix = self.prefix.as_ref().unwrap_or_else(|| EMPTY_DATA.as_ref());
        match self.data.is_empty() || self.data == *prefix {
            true => Vec::new(),
            false => match self.suffix {
                None => self.data.clone(),
                Some(ref suffix) => {
                    let mut len = suffix.len();
                    len += self.data.len();
                    let mut tmp = Vec::with_capacity(len);
                    tmp.extend_from_slice(self.data.as_ref());
                    tmp.extend_from_slice(suffix.as_slice());
                    tmp
                }
            },
        }
    }
}

impl<S: AsRef<str>> AddAssign<S> for StringJoiner {
    fn add_assign(&mut self, rhs: S) {
        if let Some(delimiter) = self.delimiter.as_ref() {
            let prefix = self.prefix.as_ref().unwrap_or_else(|| EMPTY_DATA.as_ref());
            if !self.data.is_empty() && *self.data != *prefix {
                self.data.extend_from_slice(delimiter.as_ref());
            }
        }
        self.data.extend_from_slice(rhs.as_ref().as_bytes());
    }
}

impl AddAssign<StringJoiner> for StringJoiner {
    fn add_assign(&mut self, rhs: StringJoiner) {
        *self += rhs.into_string();
    }
}

impl ToString for StringJoiner {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.to_vec().as_slice()).to_string()
    }
}

#[cfg(test)]
mod test {
    use crate::tina::util::string_joiner::StringJoiner;

    #[test]
    fn test_string_joiner() {
        let sj = StringJoiner::new(Some("("), Some(")"), Some(","));
        assert_eq!(sj.to_string(), String::new());
        assert_eq!(sj.into_string(), String::new());
        let mut sj = StringJoiner::new(None, None, None);
        sj += "A";
        assert_eq!(sj.to_string(), String::from("A"));
        assert_eq!(sj.into_string(), String::from("A"));
        let mut sj = StringJoiner::new(None, None, None);
        sj += "A";
        assert_eq!(sj.to_string(), String::from("A"));
        sj += "B";
        assert_eq!(sj.into_string(), String::from("AB"));
        let mut sj = StringJoiner::new(None, None, Some(","));
        sj += "A";
        assert_eq!(sj.to_string(), String::from("A"));
        sj += "B";
        assert_eq!(sj.into_string(), String::from("A,B"));
        let mut sj = StringJoiner::new(Some("("), None, Some(","));
        sj += "A";
        assert_eq!(sj.to_string(), String::from("(A"));
        assert_eq!(sj.into_string(), String::from("(A"));
        let mut sj = StringJoiner::new(None, Some(")"), Some(","));
        sj += "A";
        assert_eq!(sj.to_string(), String::from("A)"));
        assert_eq!(sj.into_string(), String::from("A)"));
        let mut sj = StringJoiner::new(Some("("), Some(")"), Some(","));
        sj += "A";
        assert_eq!(sj.to_string(), String::from("(A)"));
        assert_eq!(sj.into_string(), String::from("(A)"));
        let mut sj = StringJoiner::new(Some("("), Some(")"), Some(","));
        sj += "A";
        sj += "B";
        assert_eq!(sj.to_string(), String::from("(A,B)"));
        assert_eq!(sj.into_string(), String::from("(A,B)"));
    }
}