use crate::types::Span;
#[inline]
#[must_use]
pub fn utf16_len(s: &str) -> u32 {
u32::try_from(s.chars().map(char::len_utf16).sum::<usize>()).unwrap_or(0)
}
#[inline]
#[must_use]
pub fn byte_offset_to_utf16(s: &str, byte_offset: usize) -> u32 {
let mut utf16 = 0u32;
for (i, c) in s.char_indices() {
if i >= byte_offset {
break;
}
utf16 += u32::try_from(c.len_utf16()).unwrap_or(0);
}
utf16
}
#[inline]
#[must_use]
pub fn span_to_utf16_range(span: Span, source: &str) -> (u32, u32) {
let start = byte_offset_to_utf16(source, span.start as usize);
let end = byte_offset_to_utf16(source, span.end as usize);
(start, end)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn utf16_len_ascii() {
assert_eq!(utf16_len("abc"), 3);
}
#[test]
fn utf16_len_emoji() {
assert_eq!(utf16_len("a\u{1F600}b"), 4);
}
#[test]
fn byte_offset_to_utf16_ascii() {
let s = "hello";
assert_eq!(byte_offset_to_utf16(s, 0), 0);
assert_eq!(byte_offset_to_utf16(s, 5), 5);
}
#[test]
fn byte_offset_to_utf16_emoji() {
let s = "x\u{1F600}y";
assert_eq!(byte_offset_to_utf16(s, 0), 0);
assert_eq!(byte_offset_to_utf16(s, 1), 1);
assert_eq!(byte_offset_to_utf16(s, 5), 3); assert_eq!(byte_offset_to_utf16(s, 6), 4);
}
#[test]
fn span_to_utf16_range_() {
let s = "a\u{1F600}b";
let span = Span::new(1, 5);
assert_eq!(span_to_utf16_range(span, s), (1, 3));
}
}