use alloc::{borrow::Cow, string::String, vec::Vec};
pub(crate) fn newline_sequence_len(bytes: &[u8], p: usize, length: usize) -> Option<usize> {
if p == length {
return None;
}
match bytes[p] {
b'\n' | 0x0B | 0x0C => Some(1),
b'\r' => {
if p < length - 1 && bytes[p + 1] == b'\n' {
Some(2)
} else {
Some(1)
}
},
0xC2 if p < length - 1 && bytes[p + 1] == 0x85 => Some(2),
0xE2 if p < length - 2 && bytes[p + 1] == 0x80 && matches!(bytes[p + 2], 0xA8 | 0xA9) => {
Some(3)
},
_ => None,
}
}
pub(crate) fn replace_newlines_with<'a>(s: &'a str, replacement: u8) -> Cow<'a, str> {
let bytes = s.as_bytes();
let length = bytes.len();
let mut p = 0;
let first_len = loop {
if p == length {
return Cow::Borrowed(s);
}
if let Some(len) = newline_sequence_len(bytes, p, length) {
if len == 1 && bytes[p] == replacement {
p += 1;
continue;
}
break len;
}
p += 1;
};
let mut new_v = Vec::with_capacity(bytes.len());
new_v.extend_from_slice(&bytes[..p]);
new_v.push(replacement);
p += first_len;
let mut start = p;
loop {
if p == length {
break;
}
if let Some(len) = newline_sequence_len(bytes, p, length) {
if len == 1 && bytes[p] == replacement {
p += 1;
continue;
}
new_v.extend_from_slice(&bytes[start..p]);
new_v.push(replacement);
p += len;
start = p;
} else {
p += 1;
}
}
new_v.extend_from_slice(&bytes[start..p]);
Cow::Owned(unsafe { String::from_utf8_unchecked(new_v) })
}