use std::collections::HashSet; pub trait CharacterSet: Sized { fn contains(&self, ch: char) -> bool; fn union(self, other: Other) -> CharacterSetUnion { CharacterSetUnion { first: self, second: other, } } fn intersection( self, other: Other, ) -> CharacterSetIntersection { CharacterSetIntersection { first: self, second: other, } } fn difference(self, other: Other) -> CharacterSetDifference { CharacterSetDifference { first: self, second: other, } } fn complement(self) -> CharacterSetComplement { CharacterSetComplement { inner: self } } } #[derive(Debug, Clone, Copy)] pub struct AnyCharacter; impl CharacterSet for AnyCharacter { fn contains(&self, _: char) -> bool { true } } #[derive(Debug, Clone, Copy)] pub struct Ascii; impl CharacterSet for Ascii { fn contains(&self, ch: char) -> bool { ch.is_ascii() } } #[derive(Debug, Clone, Copy)] pub struct AsciiDigits; impl CharacterSet for AsciiDigits { fn contains(&self, ch: char) -> bool { ch.is_ascii_digit() } } #[derive(Debug, Clone, Copy)] pub struct AsciiLowercase; impl CharacterSet for AsciiLowercase { fn contains(&self, ch: char) -> bool { ch.is_ascii_lowercase() } } #[derive(Debug, Clone, Copy)] pub struct AsciiUppercase; impl CharacterSet for AsciiUppercase { fn contains(&self, ch: char) -> bool { ch.is_ascii_uppercase() } } #[derive(Debug, Clone, Copy)] pub struct AsciiLetters; impl CharacterSet for AsciiLetters { fn contains(&self, ch: char) -> bool { ch.is_ascii_alphabetic() } } impl CharacterSet for char { fn contains(&self, ch: char) -> bool { *self == ch } } impl CharacterSet for &[char] { fn contains(&self, ch: char) -> bool { (self as &[char]).contains(&ch) } } impl CharacterSet for &str { fn contains(&self, ch: char) -> bool { self.chars().any(|c| c == ch) } } impl CharacterSet for HashSet { fn contains(&self, ch: char) -> bool { self.contains(&ch) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct CharacterSetUnion { first: A, second: B, } impl CharacterSet for CharacterSetUnion { fn contains(&self, ch: char) -> bool { self.first.contains(ch) || self.second.contains(ch) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct CharacterSetIntersection { first: A, second: B, } impl CharacterSet for CharacterSetIntersection { fn contains(&self, ch: char) -> bool { self.first.contains(ch) && self.second.contains(ch) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct CharacterSetDifference { first: A, second: B, } impl CharacterSet for CharacterSetDifference { fn contains(&self, ch: char) -> bool { self.first.contains(ch) && !self.second.contains(ch) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct CharacterSetComplement { inner: Inner, } impl CharacterSet for CharacterSetComplement { fn contains(&self, ch: char) -> bool { !self.inner.contains(ch) } }