1use once_cell::sync::Lazy;
4use std::{
5 collections::{HashMap, HashSet},
6 error::Error,
7 fmt::{self, Display},
8};
9
10use crate::{NewName, NewNameRule, ReturnsBool};
11
12pub static RESERVED: Lazy<HashSet<&'static str>> = Lazy::new(|| {
17 let mut reserved = HashSet::new();
18 reserved.insert("");
19 reserved.insert("as");
20 reserved.insert("const"); reserved.insert("else");
22 reserved.insert("false");
23 reserved.insert("for");
24 reserved.insert("if");
25 reserved.insert("in");
26 reserved.insert("mut"); reserved.insert("optional"); reserved.insert("or_init"); reserved.insert("owned"); reserved.insert("ref"); reserved.insert("some"); reserved.insert("true");
33 reserved.insert("unchecked");
34 reserved.insert("unchecked_mut");
35 reserved.insert("where");
36 reserved.insert("while");
37 reserved
38});
39
40pub static EXACT_SUFFIX_SUBSTITUTES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
47 let mut exact_subs = HashMap::new();
48 exact_subs.insert("async", "async_");
49 exact_subs.insert("await", "await_");
50 exact_subs.insert("break", "break_");
51 exact_subs.insert("crate", "crate_");
52 exact_subs.insert("continue", "continue_");
53 exact_subs.insert("dyn", "dyn_");
54 exact_subs.insert("enum", "enum_");
55 exact_subs.insert("extern", "extern_");
56 exact_subs.insert("fn", "fn_");
57 exact_subs.insert("impl", "impl_");
58 exact_subs.insert("loop", "loop_");
59 exact_subs.insert("match", "match_");
60 exact_subs.insert("mod", "mod_");
61 exact_subs.insert("move", "move_");
62 exact_subs.insert("pub", "pub_");
63 exact_subs.insert("return", "return_");
64 exact_subs.insert("self", "self_");
65 exact_subs.insert("static", "static_");
66 exact_subs.insert("struct", "struct_");
67 exact_subs.insert("super", "super_");
68 exact_subs.insert("trait", "trait_");
69 exact_subs.insert("type", "type_");
70 exact_subs.insert("union", "union_");
71 exact_subs.insert("unsafe", "unsafe_");
72 exact_subs.insert("use", "use_");
73 exact_subs
74});
75
76pub static BOOL_FIRST_TOKEN_SUBSTITUTES: Lazy<HashMap<&'static str, &'static str>> =
84 Lazy::new(|| {
85 let mut first_token_subs = HashMap::new();
86 first_token_subs.insert("activate", "activates");
87 first_token_subs.insert("accept", "accepts");
88 first_token_subs.insert("allow", "allows");
89 first_token_subs.insert("always", "must_always");
91 first_token_subs.insert("close", "closes");
92 first_token_subs.insert("create", "creates");
93 first_token_subs.insert("destroy", "must_destroy");
95 first_token_subs.insert("do", "does");
96 first_token_subs.insert("draw", "draws");
97 first_token_subs.insert("embed", "embeds");
98 first_token_subs.insert("emit", "emits");
99 first_token_subs.insert("enable", "enables");
100 first_token_subs.insert("exit", "exits");
101 first_token_subs.insert("expand", "expands");
102 first_token_subs.insert("fill", "fills");
103 first_token_subs.insert("fit", "fits");
104 first_token_subs.insert("focus", "gets_focus");
106 first_token_subs.insert("follow", "follows");
107 first_token_subs.insert("hide", "hides");
108 first_token_subs.insert("ignore", "ignores");
109 first_token_subs.insert("invert", "inverts");
110 first_token_subs.insert("mute", "is_muted");
111 first_token_subs.insert("need", "needs");
112 first_token_subs.insert("propagate", "propagates");
113 first_token_subs.insert("populate", "populates");
114 first_token_subs.insert("receive", "receives");
115 first_token_subs.insert("reset", "resets");
116 first_token_subs.insert("require", "requires");
117 first_token_subs.insert("reserve", "must_reserve");
119 first_token_subs.insert("resize", "resizes");
120 first_token_subs.insert("restrict", "restricts");
121 first_token_subs.insert("reveal", "reveals");
122 first_token_subs.insert("select", "selects");
123 first_token_subs.insert("show", "shows");
124 first_token_subs.insert("shrink", "shrinks");
125 first_token_subs.insert("skip", "skips");
126 first_token_subs.insert("snap", "snaps");
127 first_token_subs.insert("support", "supports");
128 first_token_subs.insert("take", "takes");
129 first_token_subs.insert("track", "tracks");
130 first_token_subs.insert("truncate", "must_truncate");
132 first_token_subs.insert("use", "uses");
133 first_token_subs.insert("wrap", "wraps");
134 first_token_subs
135 });
136
137pub static BOOL_FIRST_TOKEN_NO_PREFIX: Lazy<HashSet<&'static str>> = Lazy::new(|| {
144 let mut first_tokens = HashSet::new();
145 first_tokens.insert("can");
146 first_tokens.insert("has");
147 first_tokens.insert("must");
148 first_tokens.insert("should");
149 first_tokens.insert("state");
150 for bool_substitute in BOOL_FIRST_TOKEN_SUBSTITUTES.values() {
152 first_tokens.insert(bool_substitute);
153 }
154 first_tokens
155});
156
157pub static BOOL_EXACT_SUBSTITUTES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
166 let mut exact_subs = HashMap::new();
167 exact_subs.insert("result", "result");
168 exact_subs.insert("overwrite", "overwrites");
169 exact_subs.insert("visibility", "is_visible");
170 exact_subs
171});
172
173pub const BOOL_ABLE_PREFIX: &str = "able";
177
178pub static PREFIX_TO_POSTFIX: Lazy<HashSet<&'static str>> = Lazy::new(|| {
186 let mut prefix_to_postfix = HashSet::new();
187 prefix_to_postfix.insert("mut");
188 prefix_to_postfix
189});
190
191pub fn try_rename_would_be_getter(
197 name: &str,
198 returns_bool: impl Into<ReturnsBool>,
199) -> Result<NewName, RenameError> {
200 let suffix = match name.strip_prefix("get_") {
201 Some(suffix) => suffix,
202 None => return Err(RenameError::NotGetFn),
203 };
204
205 try_rename_getter_suffix(suffix, returns_bool)
206}
207
208pub fn try_rename_getter_suffix(
214 suffix: &str,
215 returns_bool: impl Into<ReturnsBool>,
216) -> Result<NewName, RenameError> {
217 use ReturnsBool::*;
218 let returns_bool = match returns_bool.into() {
219 False => ReturnsBool::False,
220 True => return Ok(rename_bool_getter(suffix)),
221 Maybe => {
222 if let Some(rename) = guesstimate_boolness_then_rename(suffix) {
223 return Ok(rename);
224 }
225 ReturnsBool::Maybe
226 }
227 };
228
229 if let Some(substitute) = EXACT_SUFFIX_SUBSTITUTES.get(suffix) {
230 return Ok(NewName {
231 new_name: substitute.to_string(),
232 returns_bool,
233 rule: NewNameRule::Substituted,
234 });
235 }
236
237 let splits: Vec<&str> = suffix.splitn(2, '_').collect();
238 if splits.len() > 1 && PREFIX_TO_POSTFIX.contains(splits[0]) {
239 Ok(NewName {
240 new_name: format!("{}_{}", splits[1], splits[0]),
241 returns_bool,
242 rule: NewNameRule::Fixed,
243 })
244 } else if RESERVED.contains(suffix) {
245 Err(RenameError::Reserved)
246 } else {
247 Ok(NewName {
248 new_name: suffix.to_string(),
249 returns_bool,
250 rule: NewNameRule::Regular,
251 })
252 }
253}
254
255#[inline]
257pub fn rename_bool_getter(suffix: &str) -> NewName {
258 if let Some(substitute) = BOOL_EXACT_SUBSTITUTES.get(suffix) {
259 return NewName {
260 new_name: substitute.to_string(),
261 returns_bool: true.into(),
262 rule: NewNameRule::Substituted,
263 };
264 }
265
266 if let Some(new_name) = try_rename_bool_getter(suffix) {
267 new_name
268 } else {
269 NewName {
270 new_name: format!("is_{}", suffix),
271 returns_bool: true.into(),
272 rule: NewNameRule::Regular,
273 }
274 }
275}
276
277#[inline]
282fn try_rename_bool_getter(suffix: &str) -> Option<NewName> {
283 let mut working_suffix = suffix;
284 let mut has_is_prefix = false;
285
286 if let Some(suffix_without_is) = suffix.strip_prefix("is_") {
287 working_suffix = suffix_without_is;
288 has_is_prefix = true;
289 }
290
291 let splits: Vec<&str> = working_suffix.splitn(2, '_').collect();
292 BOOL_FIRST_TOKEN_SUBSTITUTES
293 .get(splits[0])
294 .map(|substitute| {
295 if splits.len() == 1 {
296 NewName {
297 new_name: substitute.to_string(),
298 returns_bool: true.into(),
299 rule: NewNameRule::Substituted,
300 }
301 } else {
302 NewName {
303 new_name: format!("{}_{}", substitute, splits[1]),
304 returns_bool: true.into(),
305 rule: NewNameRule::Substituted,
306 }
307 }
308 })
309 .or_else(|| {
310 BOOL_FIRST_TOKEN_NO_PREFIX.get(splits[0]).map(|_| {
311 if splits.len() == 1 {
312 NewName {
313 new_name: splits[0].to_string(),
314 returns_bool: true.into(),
315 rule: NewNameRule::NoPrefix,
316 }
317 } else {
318 NewName {
319 new_name: format!("{}_{}", splits[0], splits[1]),
320 returns_bool: true.into(),
321 rule: NewNameRule::NoPrefix,
322 }
323 }
324 })
325 })
326 .or_else(|| {
327 if has_is_prefix {
329 Some(NewName {
331 new_name: suffix.to_string(),
332 returns_bool: true.into(),
333 rule: NewNameRule::Regular,
334 })
335 } else {
336 None
337 }
338 })
339}
340
341#[inline]
348pub fn guesstimate_boolness_then_rename(suffix: &str) -> Option<NewName> {
349 if let Some(new_name) = try_rename_bool_getter(suffix) {
350 return Some(new_name);
351 }
352
353 let splits: Vec<&str> = suffix.splitn(2, '_').collect();
354 if splits[0].ends_with(BOOL_ABLE_PREFIX) {
355 Some(NewName {
356 new_name: format!("is_{}", suffix),
357 returns_bool: true.into(),
358 rule: NewNameRule::Regular,
359 })
360 } else {
361 None
362 }
363}
364
365#[derive(Debug, Copy, Clone, PartialEq)]
369#[non_exhaustive]
370pub enum RenameError {
371 NotGetFn,
373 Reserved,
375}
376
377impl RenameError {
378 pub fn is_not_get_fn(&self) -> bool {
379 matches!(self, RenameError::NotGetFn)
380 }
381
382 pub fn is_reserved(&self) -> bool {
383 matches!(self, RenameError::Reserved)
384 }
385}
386
387impl Display for RenameError {
388 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
389 use RenameError::*;
390 match self {
391 NotGetFn => write!(f, "not a get function"),
392 Reserved => write!(f, "name is reserved"),
393 }
394 }
395}
396
397impl Error for RenameError {}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402
403 #[test]
404 fn bool_getter_rename_attempt() {
405 let new_name = try_rename_bool_getter(&"mute").unwrap();
406 assert!(new_name.is_substituted());
407 assert!(new_name.returns_bool().is_true());
408 assert_eq!(new_name, "is_muted");
409
410 let new_name = try_rename_bool_getter(&"emit_eos").unwrap();
411 assert!(new_name.is_substituted());
412 assert!(new_name.returns_bool().is_true());
413 assert_eq!(new_name, "emits_eos");
414
415 let new_name = try_rename_bool_getter(&"has_entry").unwrap();
416 assert!(new_name.is_no_prefix());
417 assert!(new_name.returns_bool().is_true());
418 assert_eq!(new_name, "has_entry");
419
420 let new_name = try_rename_bool_getter(&"is_emit_eos").unwrap();
421 assert!(new_name.is_substituted());
422 assert!(new_name.returns_bool().is_true());
423 assert_eq!(new_name, "emits_eos");
424
425 let new_name = try_rename_bool_getter(&"is_activated").unwrap();
426 assert!(new_name.is_regular());
427 assert!(new_name.returns_bool().is_true());
428 assert_eq!(new_name, "is_activated");
429
430 assert!(try_rename_bool_getter(&"name").is_none());
431 }
432
433 #[test]
434 fn bool_getter_suffix() {
435 let new_name = rename_bool_getter(&"result");
436 assert!(new_name.is_substituted());
437 assert!(new_name.returns_bool().is_true());
438 assert_eq!(new_name, "result");
439
440 let new_name = rename_bool_getter(&"activable");
441 assert!(new_name.is_regular());
442 assert!(new_name.returns_bool().is_true());
443 assert_eq!(new_name, "is_activable");
444
445 let new_name = rename_bool_getter(&"mute");
446 assert!(new_name.is_substituted());
447 assert!(new_name.returns_bool().is_true());
448 assert_eq!(new_name, "is_muted");
449
450 let new_name = rename_bool_getter(&"emit_eos");
451 assert!(new_name.is_substituted());
452 assert!(new_name.returns_bool().is_true());
453 assert_eq!(new_name, "emits_eos");
454
455 let new_name = rename_bool_getter(&"can_acquire");
456 assert!(new_name.is_no_prefix());
457 assert!(new_name.returns_bool().is_true());
458 assert_eq!(new_name, "can_acquire");
459 }
460
461 #[test]
462 fn boolness_guestimation() {
463 assert!(guesstimate_boolness_then_rename(&"result").is_none());
464 assert!(guesstimate_boolness_then_rename(&"name").is_none());
465
466 let new_name = guesstimate_boolness_then_rename(&"mute").unwrap();
467 assert!(new_name.returns_bool().is_true());
468 assert_eq!(new_name, "is_muted");
469
470 let new_name = guesstimate_boolness_then_rename(&"does_ts").unwrap();
471 assert!(new_name.returns_bool().is_true());
472 assert_eq!(new_name, "does_ts");
473
474 let new_name = guesstimate_boolness_then_rename(&"emit_eos").unwrap();
475 assert!(new_name.returns_bool().is_true());
476 assert_eq!(new_name, "emits_eos");
477
478 let new_name = guesstimate_boolness_then_rename(&"emits_eos").unwrap();
479 assert!(new_name.returns_bool().is_true());
480 assert_eq!(new_name, "emits_eos");
481
482 let new_name = guesstimate_boolness_then_rename(&"is_emits_eos").unwrap();
483 assert!(new_name.returns_bool().is_true());
484 assert_eq!(new_name, "emits_eos");
485
486 let new_name = guesstimate_boolness_then_rename(&"is_activated").unwrap();
487 assert!(new_name.returns_bool().is_true());
488 assert_eq!(new_name, "is_activated");
489
490 let new_name = guesstimate_boolness_then_rename(&"activable").unwrap();
491 assert!(new_name.returns_bool().is_true());
492 assert_eq!(new_name, "is_activable");
493 }
494
495 #[test]
496 fn rename_getter_non_bool() {
497 let new_name = try_rename_would_be_getter(&"get_structure", false).unwrap();
498 assert!(new_name.is_regular());
499 assert!(new_name.returns_bool().is_false());
500 assert_eq!(new_name, "structure");
501
502 let new_name = try_rename_would_be_getter(&"get_type", false).unwrap();
503 assert!(new_name.is_substituted());
504 assert!(new_name.returns_bool().is_false());
505 assert_eq!(new_name, "type_");
506
507 let new_name = try_rename_would_be_getter(&"get_activable", false).unwrap();
509 assert!(new_name.is_regular());
510 assert!(new_name.returns_bool().is_false());
511 assert_eq!(new_name, "activable");
512
513 let new_name = try_rename_would_be_getter(&"get_mut_structure", false).unwrap();
515 assert!(new_name.is_fixed());
516 assert!(new_name.returns_bool().is_false());
517 assert_eq!(new_name, "structure_mut");
518
519 assert!(try_rename_would_be_getter(&"get_mut", false)
520 .unwrap_err()
521 .is_reserved());
522 assert!(try_rename_would_be_getter(&"not_a_getter", false)
523 .unwrap_err()
524 .is_not_get_fn());
525 }
526
527 #[test]
528 fn rename_getter_bool() {
529 let new_name = try_rename_would_be_getter(&"get_structure", true).unwrap();
530 assert!(new_name.is_regular());
531 assert!(new_name.returns_bool().is_true());
532 assert_eq!(new_name, "is_structure");
533
534 let new_name = try_rename_would_be_getter(&"get_type", true).unwrap();
535 assert!(new_name.is_regular());
536 assert!(new_name.returns_bool().is_true());
537 assert_eq!(new_name, "is_type");
538
539 let new_name = try_rename_would_be_getter(&"get_mute", true).unwrap();
540 assert!(new_name.is_substituted());
541 assert!(new_name.returns_bool().is_true());
542 assert_eq!(new_name, "is_muted");
543
544 let new_name = try_rename_would_be_getter(&"get_emit_eos", true).unwrap();
545 assert!(new_name.is_substituted());
546 assert!(new_name.returns_bool().is_true());
547 assert_eq!(new_name, "emits_eos");
548
549 let new_name = try_rename_would_be_getter(&"get_emits_eos", true).unwrap();
550 assert!(new_name.is_no_prefix());
551 assert!(new_name.returns_bool().is_true());
552 assert_eq!(new_name, "emits_eos");
553
554 let new_name = try_rename_would_be_getter(&"get_is_emit_eos", true).unwrap();
555 assert!(new_name.is_substituted());
556 assert!(new_name.returns_bool().is_true());
557 assert_eq!(new_name, "emits_eos");
558
559 let new_name = try_rename_would_be_getter(&"get_is_activated", true).unwrap();
560 assert!(new_name.is_regular());
561 assert!(new_name.returns_bool().is_true());
562 assert_eq!(new_name, "is_activated");
563
564 let new_name = try_rename_would_be_getter(&"get_activable", true).unwrap();
565 assert!(new_name.is_regular());
566 assert!(new_name.returns_bool().is_true());
567 assert_eq!(new_name, "is_activable");
568
569 let new_name = try_rename_would_be_getter(&"get_mut", true).unwrap();
570 assert!(new_name.is_regular());
571 assert!(new_name.returns_bool().is_true());
572 assert_eq!(new_name, "is_mut");
573
574 let new_name = try_rename_would_be_getter(&"get_overwrite", true).unwrap();
575 assert!(new_name.is_substituted());
576 assert!(new_name.returns_bool().is_true());
577 assert_eq!(new_name, "overwrites");
578
579 let new_name = try_rename_would_be_getter(&"get_overwrite_mode", true).unwrap();
580 assert!(new_name.is_regular());
581 assert!(new_name.returns_bool().is_true());
582 assert_eq!(new_name, "is_overwrite_mode");
583
584 assert!(try_rename_would_be_getter(&"not_a_getter", true)
585 .unwrap_err()
586 .is_not_get_fn());
587 }
588
589 #[test]
590 fn rename_getter_maybe_bool() {
591 let new_name = try_rename_would_be_getter(&"get_structure", ReturnsBool::Maybe).unwrap();
592 assert!(new_name.is_regular());
593 assert!(new_name.returns_bool().is_maybe());
594 assert_eq!(new_name, "structure");
595
596 let new_name = try_rename_would_be_getter(&"get_type", ReturnsBool::Maybe).unwrap();
597 assert!(new_name.is_substituted());
598 assert!(new_name.returns_bool().is_maybe());
599 assert_eq!(new_name, "type_");
600
601 let new_name = try_rename_would_be_getter(&"get_mute", ReturnsBool::Maybe).unwrap();
602 assert!(new_name.is_substituted());
603 assert!(new_name.returns_bool().is_true());
604 assert_eq!(new_name, "is_muted");
605
606 let new_name = try_rename_would_be_getter(&"get_emit_eos", ReturnsBool::Maybe).unwrap();
607 assert!(new_name.is_substituted());
608 assert!(new_name.returns_bool().is_true());
609 assert_eq!(new_name, "emits_eos");
610
611 let new_name = try_rename_would_be_getter(&"get_emits_eos", ReturnsBool::Maybe).unwrap();
612 assert!(new_name.is_no_prefix());
613 assert!(new_name.returns_bool().is_true());
614 assert_eq!(new_name, "emits_eos");
615
616 let new_name = try_rename_would_be_getter(&"get_is_emit_eos", ReturnsBool::Maybe).unwrap();
617 assert!(new_name.is_substituted());
618 assert!(new_name.returns_bool().is_true());
619 assert_eq!(new_name, "emits_eos");
620
621 let new_name = try_rename_would_be_getter(&"get_is_activated", ReturnsBool::Maybe).unwrap();
622 assert!(new_name.is_regular());
623 assert!(new_name.returns_bool().is_true());
624 assert_eq!(new_name, "is_activated");
625
626 let new_name = try_rename_would_be_getter(&"get_activable", ReturnsBool::Maybe).unwrap();
627 assert!(new_name.is_regular());
628 assert!(new_name.returns_bool().is_true());
629 assert_eq!(new_name, "is_activable");
630
631 assert!(try_rename_would_be_getter(&"get_mut", ReturnsBool::Maybe)
632 .unwrap_err()
633 .is_reserved());
634 assert!(
635 try_rename_would_be_getter(&"not_a_getter", ReturnsBool::Maybe)
636 .unwrap_err()
637 .is_not_get_fn()
638 );
639 }
640}