mcfly/
fixed_length_grapheme_string.rs1use std::io::Write;
2use unicode_segmentation::UnicodeSegmentation;
3
4#[derive(Debug)]
5pub struct FixedLengthGraphemeString {
6 pub string: String,
7 pub grapheme_length: u16,
8 pub max_grapheme_length: u16,
9}
10
11impl Write for FixedLengthGraphemeString {
12 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
13 let s = String::from_utf8(buf.to_vec()).unwrap();
14 self.push_str(&s);
15 Ok(s.len())
16 }
17
18 fn flush(&mut self) -> std::io::Result<()> {
19 Ok(())
20 }
21}
22
23impl FixedLengthGraphemeString {
24 #[must_use]
25 pub fn empty(max_grapheme_length: u16) -> FixedLengthGraphemeString {
26 FixedLengthGraphemeString {
27 string: String::new(),
28 grapheme_length: 0,
29 max_grapheme_length,
30 }
31 }
32
33 pub fn new<S: Into<String>>(s: S, max_grapheme_length: u16) -> FixedLengthGraphemeString {
34 let mut fixed_length_grapheme_string =
35 FixedLengthGraphemeString::empty(max_grapheme_length);
36 fixed_length_grapheme_string.push_grapheme_str(s);
37 fixed_length_grapheme_string
38 }
39
40 pub fn push_grapheme_str<S: Into<String>>(&mut self, s: S) {
41 for grapheme in s.into().graphemes(true) {
42 if self.grapheme_length >= self.max_grapheme_length {
43 return;
44 }
45 self.string.push_str(grapheme);
46 self.grapheme_length += 1;
47 }
48 }
49
50 pub fn push_str(&mut self, s: &str) {
51 self.string.push_str(s);
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::FixedLengthGraphemeString;
58
59 #[test]
60 fn length_works() {
61 let input = FixedLengthGraphemeString::new("こんにちは世界", 20);
62 assert_eq!(input.grapheme_length, 7);
63 }
64
65 #[test]
66 fn max_length_works() {
67 let mut input = FixedLengthGraphemeString::new("こんにちは世界", 5);
68 assert_eq!(input.string, "こんにちは");
69 input.push_grapheme_str("世界");
70 assert_eq!(input.string, "こんにちは");
71 input.max_grapheme_length = 7;
72 input.push_grapheme_str("世界");
73 assert_eq!(input.string, "こんにちは世界");
74 }
75}