use std::ptr;
fn swap_endian(value: u16) -> u16 {
value.rotate_right(8)
}
pub fn to_utf8(utf16: &[u16], is_little_endian: bool) -> Result<Vec<u8>, String> {
let mut utf8_bytes: Vec<u8> = Vec::with_capacity(utf16.len() * 3);
let ptr = utf8_bytes.as_mut_ptr();
let mut offset = 0;
let mut iter = utf16.iter();
while let Some(&wc) = iter.next() {
let wc = if is_little_endian {
swap_endian(wc)
} else {
wc
};
match wc {
code_point if code_point < 0x80 => {
unsafe {
ptr.add(offset).write(code_point as u8);
}
offset += 1;
}
code_point if code_point < 0x800 => {
let bytes = [
((code_point >> 6) & 0b1_1111) as u8 | 0b1100_0000,
(code_point & 0b11_1111) as u8 | 0b1000_0000,
];
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(offset), 2);
}
offset += 2;
}
wc1 if (0xd800..=0xdbff).contains(&wc1) => {
if let Some(&wc2) = iter.next() {
let wc2 = if is_little_endian {
swap_endian(wc2)
} else {
wc2
};
if !(0xdc00..=0xdfff).contains(&wc2) {
return Err("Invalid UTF-16 string: wrong surrogate pair".to_string());
}
let code_point =
((((wc1 as u32) - 0xd800) << 10) | ((wc2 as u32) - 0xdc00)) + 0x10000;
let bytes = [
((code_point >> 18) & 0b111) as u8 | 0b1111_0000,
((code_point >> 12) & 0b11_1111) as u8 | 0b1000_0000,
((code_point >> 6) & 0b11_1111) as u8 | 0b1000_0000,
(code_point & 0b11_1111) as u8 | 0b1000_0000,
];
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(offset), 4);
}
offset += 4;
} else {
return Err("Invalid UTF-16 string: missing surrogate pair".to_string());
}
}
_ => {
let bytes = [
((wc >> 12) | 0b1110_0000) as u8,
((wc >> 6) & 0b11_1111) as u8 | 0b1000_0000,
(wc & 0b11_1111) as u8 | 0b1000_0000,
];
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(offset), 3);
}
offset += 3;
}
}
}
unsafe {
utf8_bytes.set_len(offset);
}
Ok(utf8_bytes)
}
pub fn to_snake_case(name: &str) -> String {
let mut result = String::with_capacity(name.len() + 4);
let chars: Vec<char> = name.chars().collect();
for (i, &c) in chars.iter().enumerate() {
if c.is_ascii_uppercase() {
if i > 0 {
let prev_upper = chars.get(i - 1).is_some_and(|c| c.is_ascii_uppercase());
let next_upper_or_end = chars.get(i + 1).map_or(true, |c| c.is_ascii_uppercase());
if !prev_upper || !next_upper_or_end {
result.push('_');
}
}
result.push(c.to_ascii_lowercase());
} else {
result.push(c);
}
}
result
}
pub fn to_camel_case(name: &str) -> String {
let mut result = String::with_capacity(name.len());
let mut capitalize_next = false;
for c in name.chars() {
if c == '_' {
capitalize_next = true;
} else if capitalize_next {
result.push(c.to_ascii_uppercase());
capitalize_next = false;
} else {
result.push(c);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_snake_case() {
assert_eq!(to_snake_case("camelCase"), "camel_case");
assert_eq!(to_snake_case("PascalCase"), "pascal_case");
assert_eq!(to_snake_case("HTTPRequest"), "http_request");
assert_eq!(to_snake_case("simpleTest"), "simple_test");
assert_eq!(to_snake_case("already_snake"), "already_snake");
assert_eq!(to_snake_case("ABC"), "abc");
}
#[test]
fn test_to_camel_case() {
assert_eq!(to_camel_case("snake_case"), "snakeCase");
assert_eq!(to_camel_case("simple_test"), "simpleTest");
assert_eq!(to_camel_case("already"), "already");
assert_eq!(to_camel_case("a_b_c"), "aBC");
}
}