diff --git a/src/style.rs b/src/style.rs index 1d87688df..97bbafc05 100644 --- a/src/style.rs +++ b/src/style.rs @@ -18,15 +18,22 @@ pub enum BackgroundColor { Light, } -/// Slice `s` from `start` to `end` by codepoint. This is safer than +/// Slice `s` from `start` inclusive to `end` exclusive by codepoint. This is safer than /// slicing by bytes, which panics if the byte isn't on a codepoint /// boundary. fn substring_by_codepoint(s: &str, start: usize, end: usize) -> &str { + if start == end { + return &s[0..0]; + } + assert!(end > start); let mut char_idx_iter = s.char_indices(); - let byte_start = char_idx_iter.nth(start).expect("Expected a codepoint index inside `s`.").0; - match char_idx_iter.nth(end - 1 - start) { + let byte_start = char_idx_iter + .nth(start) + .expect("Expected a codepoint index inside `s`.") + .0; + match char_idx_iter.nth(end - start - 1) { Some(byte_end) => &s[byte_start..byte_end.0], None => &s[byte_start..], } @@ -308,6 +315,16 @@ mod tests { use super::*; use pretty_assertions::assert_eq; + #[test] + fn test_substring_by_codepoint() { + assert_eq!(substring_by_codepoint("abcd", 0, 2), "ab"); + } + + #[test] + fn test_substring_by_codepoint_empty() { + assert_eq!(substring_by_codepoint("abcd", 0, 0), ""); + } + #[test] fn split_string_simple() { assert_eq!(split_string("fooba", 3), vec!["foo", "ba "]);