mermaid_cli/utils/
ndjson.rs1pub fn drain_complete_lines(buf: &mut Vec<u8>) -> Vec<String> {
19 let mut lines = Vec::new();
20 while let Some(newline_pos) = buf.iter().position(|&b| b == b'\n') {
21 let line_bytes: Vec<u8> = buf.drain(..=newline_pos).collect();
23 let content = &line_bytes[..line_bytes.len() - 1];
24 lines.push(String::from_utf8_lossy(content).into_owned());
25 }
26 lines
27}
28
29#[cfg(test)]
30mod tests {
31 use super::drain_complete_lines;
32
33 #[test]
34 fn drain_empty_buf() {
35 let mut buf: Vec<u8> = Vec::new();
36 assert!(drain_complete_lines(&mut buf).is_empty());
37 assert!(buf.is_empty());
38 }
39
40 #[test]
41 fn drain_without_newline_keeps_buf_intact() {
42 let mut buf = b"partial".to_vec();
43 assert!(drain_complete_lines(&mut buf).is_empty());
44 assert_eq!(buf, b"partial");
45 }
46
47 #[test]
48 fn drain_yields_complete_lines_and_keeps_tail() {
49 let mut buf = b"first\nsecond\ntail".to_vec();
50 let lines = drain_complete_lines(&mut buf);
51 assert_eq!(lines, vec!["first".to_string(), "second".to_string()]);
52 assert_eq!(buf, b"tail");
53 }
54
55 #[test]
59 fn drain_preserves_codepoints_across_chunks() {
60 let mut buf: Vec<u8> = Vec::new();
61 buf.extend_from_slice(b"hello ");
62 buf.extend_from_slice(&[0xE4, 0xBD]);
63 assert!(drain_complete_lines(&mut buf).is_empty());
64
65 buf.extend_from_slice(&[0xA0]);
66 buf.extend_from_slice("好\n".as_bytes());
67
68 let lines = drain_complete_lines(&mut buf);
69 assert_eq!(lines, vec!["hello 你好".to_string()]);
70 assert!(buf.is_empty());
71 }
72}