Skip to content

Commit d38fddd

Browse files
committed
Refactor camel_case util functions for new StrIndex
1 parent 1b91d98 commit d38fddd

File tree

3 files changed

+103
-59
lines changed

3 files changed

+103
-59
lines changed

clippy_lints/src/enum_variants.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! lint on enum variants that are prefixed or suffixed by the same characters
22
3-
use clippy_utils::str_utils;
43
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
54
use clippy_utils::source::is_present_in_source;
5+
use clippy_utils::str_utils;
66
use rustc_hir::{EnumDef, Item, ItemKind};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -171,23 +171,23 @@ fn check_variant(
171171
}
172172
}
173173
let first = &def.variants[0].ident.name.as_str();
174-
let mut pre = &first[..str_utils::until(&*first)];
175-
let mut post = &first[str_utils::from(&*first)..];
174+
let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
175+
let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
176176
for var in def.variants {
177177
let name = var.ident.name.as_str();
178178

179179
let pre_match = partial_match(pre, &name);
180180
pre = &pre[..pre_match];
181-
let pre_camel = str_utils::until(pre);
181+
let pre_camel = str_utils::camel_case_until(pre).byte_index;
182182
pre = &pre[..pre_camel];
183183
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
184184
if next.is_numeric() {
185185
return;
186186
}
187187
if next.is_lowercase() {
188188
let last = pre.len() - last.len_utf8();
189-
let last_camel = str_utils::until(&pre[..last]);
190-
pre = &pre[..last_camel];
189+
let last_camel = str_utils::camel_case_until(&pre[..last]);
190+
pre = &pre[..last_camel.byte_index];
191191
} else {
192192
break;
193193
}
@@ -196,8 +196,8 @@ fn check_variant(
196196
let post_match = partial_rmatch(post, &name);
197197
let post_end = post.len() - post_match;
198198
post = &post[post_end..];
199-
let post_camel = str_utils::from(post);
200-
post = &post[post_camel..];
199+
let post_camel = str_utils::camel_case_start(post);
200+
post = &post[post_camel.byte_index..];
201201
}
202202
let (what, value) = match (pre.is_empty(), post.is_empty()) {
203203
(true, true) => return,

clippy_utils/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ pub mod sym_helper;
3737
#[allow(clippy::module_name_repetitions)]
3838
pub mod ast_utils;
3939
pub mod attrs;
40-
pub mod str_utils;
4140
pub mod comparisons;
4241
pub mod consts;
4342
pub mod diagnostics;
@@ -50,6 +49,7 @@ pub mod paths;
5049
pub mod ptr;
5150
pub mod qualify_min_const_fn;
5251
pub mod source;
52+
pub mod str_utils;
5353
pub mod sugg;
5454
pub mod ty;
5555
pub mod usage;

clippy_utils/src/str_utils.rs

Lines changed: 94 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,161 @@
1+
/// Dealing with sting indices can be hard, this struct ensures that both the
2+
/// character and byte index are provided for correct indexing.
3+
#[derive(Debug, Default, PartialEq, Eq)]
4+
pub struct StrIndex {
5+
pub char_index: usize,
6+
pub byte_index: usize,
7+
}
8+
9+
impl StrIndex {
10+
pub fn new(char_index: usize, byte_index: usize) -> Self {
11+
Self { char_index, byte_index }
12+
}
13+
}
14+
115
/// Returns the index of the character after the first camel-case component of `s`.
16+
///
17+
/// ```
18+
/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
19+
/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
20+
/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
21+
/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
22+
/// ```
223
#[must_use]
3-
pub fn until(s: &str) -> usize {
4-
let mut iter = s.char_indices();
5-
if let Some((_, first)) = iter.next() {
24+
pub fn camel_case_until(s: &str) -> StrIndex {
25+
let mut iter = s.char_indices().enumerate();
26+
if let Some((_char_index, (_, first))) = iter.next() {
627
if !first.is_uppercase() {
7-
return 0;
28+
return StrIndex::new(0, 0);
829
}
930
} else {
10-
return 0;
31+
return StrIndex::new(0, 0);
1132
}
1233
let mut up = true;
13-
let mut last_i = 0;
14-
for (i, c) in iter {
34+
let mut last_index = StrIndex::new(0, 0);
35+
for (char_index, (byte_index, c)) in iter {
1536
if up {
1637
if c.is_lowercase() {
1738
up = false;
1839
} else {
19-
return last_i;
40+
return last_index;
2041
}
2142
} else if c.is_uppercase() {
2243
up = true;
23-
last_i = i;
44+
last_index.byte_index = byte_index;
45+
last_index.char_index = char_index;
2446
} else if !c.is_lowercase() {
25-
return i;
47+
return StrIndex::new(char_index, byte_index);
2648
}
2749
}
28-
if up { last_i } else { s.len() }
50+
51+
if up {
52+
last_index
53+
} else {
54+
StrIndex::new(s.chars().count(), s.len())
55+
}
2956
}
3057

3158
/// Returns index of the last camel-case component of `s`.
59+
///
60+
/// ```
61+
/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
62+
/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
63+
/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
64+
/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
65+
/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
66+
/// ```
3267
#[must_use]
33-
pub fn from(s: &str) -> usize {
34-
let mut iter = s.char_indices().rev();
35-
if let Some((_, first)) = iter.next() {
68+
pub fn camel_case_start(s: &str) -> StrIndex {
69+
let char_count = s.chars().count();
70+
let range = 0..char_count;
71+
let mut iter = range.rev().zip(s.char_indices().rev());
72+
if let Some((char_index, (_, first))) = iter.next() {
3673
if !first.is_lowercase() {
37-
return s.len();
74+
return StrIndex::new(char_index, s.len());
3875
}
3976
} else {
40-
return s.len();
77+
return StrIndex::new(char_count, s.len());
4178
}
4279
let mut down = true;
43-
let mut last_i = s.len();
44-
for (i, c) in iter {
80+
let mut last_index = StrIndex::new(char_count, s.len());
81+
for (char_index, (byte_index, c)) in iter {
4582
if down {
4683
if c.is_uppercase() {
4784
down = false;
48-
last_i = i;
85+
last_index.byte_index = byte_index;
86+
last_index.char_index = char_index;
4987
} else if !c.is_lowercase() {
50-
return last_i;
88+
return last_index;
5189
}
5290
} else if c.is_lowercase() {
5391
down = true;
5492
} else if c.is_uppercase() {
55-
last_i = i;
93+
last_index.byte_index = byte_index;
94+
last_index.char_index = char_index;
5695
} else {
57-
return last_i;
96+
return last_index;
5897
}
5998
}
60-
last_i
99+
last_index
61100
}
62101

63102
#[cfg(test)]
64103
mod test {
65-
use super::{from, until};
104+
use super::*;
66105

67106
#[test]
68-
fn from_full() {
69-
assert_eq!(from("AbcDef"), 0);
70-
assert_eq!(from("Abc"), 0);
71-
assert_eq!(from("ABcd"), 0);
72-
assert_eq!(from("ABcdEf"), 0);
73-
assert_eq!(from("AabABcd"), 0);
107+
fn camel_case_start_full() {
108+
assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
109+
assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
110+
assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
111+
assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
112+
assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
74113
}
75114

76115
#[test]
77-
fn from_partial() {
78-
assert_eq!(from("abcDef"), 3);
79-
assert_eq!(from("aDbc"), 1);
80-
assert_eq!(from("aabABcd"), 3);
116+
fn camel_case_start_partial() {
117+
assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
118+
assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
119+
assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
120+
assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
81121
}
82122

83123
#[test]
84-
fn from_not() {
85-
assert_eq!(from("AbcDef_"), 7);
86-
assert_eq!(from("AbcDD"), 5);
124+
fn camel_case_start_not() {
125+
assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
126+
assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
127+
assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
128+
assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
87129
}
88130

89131
#[test]
90-
fn from_caps() {
91-
assert_eq!(from("ABCD"), 4);
132+
fn camel_case_start_caps() {
133+
assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
92134
}
93135

94136
#[test]
95-
fn until_full() {
96-
assert_eq!(until("AbcDef"), 6);
97-
assert_eq!(until("Abc"), 3);
137+
fn camel_case_until_full() {
138+
assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
139+
assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
140+
assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
98141
}
99142

100143
#[test]
101-
fn until_not() {
102-
assert_eq!(until("abcDef"), 0);
103-
assert_eq!(until("aDbc"), 0);
144+
fn camel_case_until_not() {
145+
assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
146+
assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
104147
}
105148

106149
#[test]
107-
fn until_partial() {
108-
assert_eq!(until("AbcDef_"), 6);
109-
assert_eq!(until("CallTypeC"), 8);
110-
assert_eq!(until("AbcDD"), 3);
150+
fn camel_case_until_partial() {
151+
assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
152+
assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
153+
assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
154+
assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
111155
}
112156

113157
#[test]
114158
fn until_caps() {
115-
assert_eq!(until("ABCD"), 0);
159+
assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
116160
}
117161
}

0 commit comments

Comments
 (0)