use std::prelude::v1::*;
use std::borrow::Cow;
use std::ops::Index;
use std::ops::RangeInclusive;
use std::slice::Iter;
#[cfg(feature = "bruteforce-macros")]
#[macro_export]
macro_rules! charset {
($string:expr) => {{
charset_string!($string);
Charset::new(slice)
}};
}
#[derive(Debug, Clone)]
pub struct Charset<'a> {
chars: Cow<'a, [char]>,
}
impl<'a> Charset<'a> {
pub const fn new(charset: &[char]) -> Charset {
assert!(
!charset.is_empty(),
"The &[char] must contain at least one character"
);
Charset {
chars: Cow::Borrowed(charset),
}
}
pub fn by_char_range(range: RangeInclusive<char>) -> Charset<'a> {
let range_as_u32 = (*range.start() as u32)..=(*range.end() as u32);
let vec = range_as_u32.filter_map(std::char::from_u32).collect();
Charset {
chars: Cow::Owned(vec),
}
}
pub unsafe fn by_char_range_unchecked(range: RangeInclusive<char>) -> Charset<'a> {
let range_as_u32 = (*range.start() as u32)..=(*range.end() as u32);
let vec = range_as_u32
.map(|c| std::char::from_u32_unchecked(c))
.collect();
Charset {
chars: Cow::Owned(vec),
}
}
pub fn new_by_str(s: &str) -> Charset<'a> {
assert!(
!s.is_empty(),
"The string must contain at least one character"
);
let vec = s.chars().collect::<Vec<char>>();
Charset {
chars: Cow::Owned(vec),
}
}
pub fn concat(&self, other: &Charset) -> Charset<'a> {
let mut s = self.clone();
for &ch in other.iter() {
if !s.chars.contains(&ch) {
s.chars.to_mut().push(ch);
}
}
s
}
#[inline]
pub fn len(&self) -> usize {
self.chars.len()
}
#[inline]
#[cold]
pub fn is_empty(&self) -> bool {
self.chars.is_empty()
}
#[inline]
pub fn iter(&self) -> Iter<'_, char> {
self.chars.iter()
}
}
impl Index<usize> for Charset<'_> {
type Output = char;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.chars[index]
}
}
impl<'a> From<&'a str> for Charset<'_> {
fn from(input: &'a str) -> Self {
Self::new_by_str(input)
}
}
impl From<String> for Charset<'_> {
fn from(s: String) -> Self {
s.as_str().into()
}
}
impl std::fmt::Display for Charset<'_> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.chars.iter().try_for_each(|&c| write!(fmt, "{}", c))
}
}