steel_core/command/brigadier/
string_range.rs1use std::ops::Range;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
7pub(crate) struct StringRange {
8 start: usize,
9 end: usize,
10}
11
12impl StringRange {
13 pub(crate) const fn at(position: usize) -> Self {
15 Self {
16 start: position,
17 end: position,
18 }
19 }
20
21 pub(crate) const fn between(start: usize, end: usize) -> Self {
23 assert!(start <= end, "command range start must not exceed its end");
24 Self { start, end }
25 }
26
27 pub(crate) const fn encompassing(first: Self, second: Self) -> Self {
29 Self {
30 start: if first.start < second.start {
31 first.start
32 } else {
33 second.start
34 },
35 end: if first.end > second.end {
36 first.end
37 } else {
38 second.end
39 },
40 }
41 }
42
43 pub(crate) const fn start(self) -> usize {
45 self.start
46 }
47
48 pub(crate) const fn end(self) -> usize {
50 self.end
51 }
52
53 pub(crate) const fn is_empty(self) -> bool {
55 self.start == self.end
56 }
57
58 pub(crate) const fn len(self) -> usize {
60 self.end - self.start
61 }
62
63 pub(super) fn byte_range(self, input: &str) -> Option<Range<usize>> {
64 let start = Self::byte_index(input, self.start)?;
65 let end = Self::byte_index(input, self.end)?;
66 Some(start..end)
67 }
68
69 fn byte_index(input: &str, position: usize) -> Option<usize> {
70 let mut utf16_index = 0;
71 for (byte_index, character) in input.char_indices() {
72 if utf16_index == position {
73 return Some(byte_index);
74 }
75 utf16_index += character.len_utf16();
76 if utf16_index > position {
77 return None;
78 }
79 }
80 (utf16_index == position).then_some(input.len())
81 }
82}