Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-renderer/src/windowing/winit/fonts/str_index_map.rs
StratoSDK / crates / strato-ui-renderer / src / windowing / winit / fonts / str_index_map.rs
1//! Module containing the definition of [`StrIndexMap`], allowing for repeated, efficient conversion
2//! between a byte and/or char index from a backing `str`.
3 
4use std::collections::HashMap;
5 
6/// Map that provides efficient conversion from byte <-> char index from a backing `str`.
7/// See [`StrIndexMap::byte_index`] and [`StrIndexMap::char_index`] for conversion functions to
8/// convert from/to a byte index to a char index.
9pub(super) struct StrIndexMap {
10 byte_to_char_index: HashMap<usize, usize>,
11 char_to_byte_index: Vec<usize>,
12}
13 
14impl StrIndexMap {
15 /// Constructs a new [`StrIndexMap`] with byte <-> char indices based on the input `str`.
16 /// NOTE this runs in O(n) time as it requires walking through each char index in the `str`.
17 pub(super) fn new(str: impl AsRef<str>) -> Self {
18 let char_indices = str.as_ref().char_indices();
19 let (_, upper_bound) = char_indices.size_hint();
20 
21 let (mut byte_to_char_index, mut char_to_byte_index) = match upper_bound {
22 None => (HashMap::new(), Vec::new()),
23 Some(size) => (HashMap::with_capacity(size), Vec::with_capacity(size)),
24 };
25 
26 for (char_index, (byte_index, _)) in char_indices.enumerate() {
27 byte_to_char_index.insert(byte_index, char_index);
28 char_to_byte_index.push(byte_index);
29 }
30 
31 Self {
32 byte_to_char_index,
33 char_to_byte_index,
34 }
35 }
36 
37 /// Returns the _byte_ index of the string at the given `char_index`. If the `char_index` does
38 /// not exist in the string, `None` is returned.
39 pub(super) fn byte_index(&self, char_index: usize) -> Option<usize> {
40 self.char_to_byte_index.get(char_index).copied()
41 }
42 
43 /// Returns the _char_ index of the string at the given byte index. If the `byte_index` does not
44 /// exist in the string or if it does not lie at a char boundary, `None` is returned.
45 pub(super) fn char_index(&self, byte_index: usize) -> Option<usize> {
46 self.byte_to_char_index.get(&byte_index).copied()
47 }
48 
49 /// Returns the total number of characters in the string.
50 pub(super) fn num_chars(&self) -> usize {
51 self.char_to_byte_index.len()
52 }
53}
54 
55#[cfg(test)]
56#[path = "str_index_map_tests.rs"]
57mod tests;
58