use std::str::CharIndices;
#[inline]
pub fn char_width(ch: char) -> Option<usize> {
use unicode_width::UnicodeWidthChar;
ch.width()
}
#[inline]
pub fn is_combining_mark(ch: char) -> bool {
use unicode_normalization::char::is_combining_mark;
is_combining_mark(ch)
}
const CTRL_MASK: u8 = 0x1f;
const UNCTRL_BIT: u8 = 0x40;
#[inline]
pub fn ctrl(ch: char) -> char {
((ch as u8) & CTRL_MASK) as char
}
#[inline]
pub fn is_ctrl(ch: char) -> bool {
let ch = ch as u32;
ch & (CTRL_MASK as u32) == ch
}
#[inline]
pub fn unctrl_upper(ch: char) -> char {
((ch as u8) | UNCTRL_BIT) as char
}
#[inline]
pub fn unctrl_lower(ch: char) -> char {
unctrl_upper(ch).to_ascii_lowercase()
}
pub struct Prefixes<'a> {
s: &'a str,
iter: CharIndices<'a>,
}
#[inline]
pub fn prefixes(s: &str) -> Prefixes {
Prefixes{
s,
iter: s.char_indices(),
}
}
impl<'a> Iterator for Prefixes<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
self.iter.next().map(|(idx, ch)| &self.s[..idx + ch.len_utf8()])
}
}
#[cfg(test)]
mod test {
use super::{ctrl, is_ctrl, unctrl_lower, unctrl_upper, prefixes};
#[test]
fn test_unctrl() {
for ch in 0u8..255 {
let ch = ch as char;
if is_ctrl(ch) {
assert_eq!(ch, ctrl(unctrl_lower(ch)));
assert_eq!(ch, ctrl(unctrl_upper(ch)));
}
}
}
#[test]
fn test_prefix_iter() {
let mut pfxs = prefixes("foobar");
assert_eq!(pfxs.next(), Some("f"));
assert_eq!(pfxs.next(), Some("fo"));
assert_eq!(pfxs.next(), Some("foo"));
assert_eq!(pfxs.next(), Some("foob"));
assert_eq!(pfxs.next(), Some("fooba"));
assert_eq!(pfxs.next(), Some("foobar"));
assert_eq!(pfxs.next(), None);
let mut pfxs = prefixes("a");
assert_eq!(pfxs.next(), Some("a"));
assert_eq!(pfxs.next(), None);
let mut pfxs = prefixes("");
assert_eq!(pfxs.next(), None);
}
}