diff --git a/Cargo.toml b/Cargo.toml index 747ecdb8..bf4b6174 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ or_fun_call = "warn" redundant_type_annotations = "warn" rest_pat_in_fully_bound_structs = "warn" string_lit_chars_any = "warn" +string_slice = "warn" string_to_string = "warn" use_self = "warn" diff --git a/src/style/color.rs b/src/style/color.rs index 106dafee..44f54b9f 100644 --- a/src/style/color.rs +++ b/src/style/color.rs @@ -313,16 +313,7 @@ impl FromStr for Color { _ => { if let Ok(index) = s.parse::() { Self::Indexed(index) - } else if let (Ok(r), Ok(g), Ok(b)) = { - if !s.starts_with('#') || s.len() != 7 { - return Err(ParseColorError); - } - ( - u8::from_str_radix(&s[1..3], 16), - u8::from_str_radix(&s[3..5], 16), - u8::from_str_radix(&s[5..7], 16), - ) - } { + } else if let Some((r, g, b)) = parse_hex_color(s) { Self::Rgb(r, g, b) } else { return Err(ParseColorError); @@ -333,6 +324,16 @@ impl FromStr for Color { } } +fn parse_hex_color(input: &str) -> Option<(u8, u8, u8)> { + if !input.starts_with('#') || input.len() != 7 { + return None; + } + let r = u8::from_str_radix(input.get(1..3)?, 16).ok()?; + let g = u8::from_str_radix(input.get(3..5)?, 16).ok()?; + let b = u8::from_str_radix(input.get(5..7)?, 16).ok()?; + Some((r, g, b)) +} + impl fmt::Display for Color { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -587,6 +588,7 @@ mod tests { "abcdef0", // 7 chars is not a color " bcdefa", // doesn't start with a '#' "#abcdef00", // too many chars + "#1🦀2", // len 7 but on char boundaries shouldnt panic "resett", // typo "lightblackk", // typo ]; diff --git a/src/widgets/reflow.rs b/src/widgets/reflow.rs index 99c8317a..18fc9933 100644 --- a/src/widgets/reflow.rs +++ b/src/widgets/reflow.rs @@ -336,6 +336,7 @@ fn trim_offset(src: &str, mut offset: usize) -> &str { break; } } + #[allow(clippy::string_slice)] // Is safe as it comes from UnicodeSegmentation &src[start..] } @@ -431,17 +432,17 @@ mod test { let (line_truncator, _, _) = run_composer(Composer::LineTruncator, text, width as u16); let wrapped = vec![ - &text[..width], - &text[width..width * 2], - &text[width * 2..width * 3], - &text[width * 3..], + text.get(..width).unwrap(), + text.get(width..width * 2).unwrap(), + text.get(width * 2..width * 3).unwrap(), + text.get(width * 3..).unwrap(), ]; assert_eq!( word_wrapper, wrapped, "WordWrapper should detect the line cannot be broken on word boundary and \ break it at line width limit." ); - assert_eq!(line_truncator, vec![&text[..width]]); + assert_eq!(line_truncator, [text.get(..width).unwrap()]); } #[test] @@ -471,7 +472,7 @@ mod test { assert_eq!(word_wrapper_single_space, word_wrapped); assert_eq!(word_wrapper_multi_space, word_wrapped); - assert_eq!(line_truncator, vec![&text[..width]]); + assert_eq!(line_truncator, [text.get(..width).unwrap()]); } #[test]