1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Convenience syntax for compactly writing literal regular expression.

use crate::Builder;
use crate::Regex;

pub trait IntoRegex<B: Builder> {
    fn r(self) -> Regex<B>;
}

pub trait IntoSymbol<B: Builder> {
    fn s(self) -> Regex<B>;
}

pub trait IntoClosure<B: Builder> {
    fn c(self) -> Regex<B>;
}

impl<B: Builder> IntoRegex<B> for () {
    #[inline]
    fn r(self) -> Regex<B> {
        B::empty_set()
    }
}

// empty string is a special case of concat

impl<B: Builder> IntoSymbol<B> for B::Symbol {
    #[inline]
    fn s(self) -> Regex<B> {
        B::symbol(self)
    }
}

impl<B: Builder> IntoClosure<B> for Regex<B> {
    #[inline]
    fn c(self) -> Regex<B> {
        B::closure(self)
    }
}

impl<B: Builder> std::ops::Add for Regex<B> {
    type Output = Self;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        B::concat(self, rhs)
    }
}

impl<B: Builder, const X: usize> IntoRegex<B> for [Regex<B>; X] {
    fn r(self) -> Regex<B> {
        match X {
            0 => B::empty_string(),
            1 => self.into_iter().next().expect("can get only item"),
            _ => self
                .into_iter()
                .reduce(B::concat)
                .expect("can reduce multiple items"),
        }
    }
}

impl<B: Builder> std::ops::BitOr for Regex<B> {
    type Output = Self;
    #[inline]
    fn bitor(self, rhs: Self) -> Self::Output {
        B::or(self, rhs)
    }
}

impl<B: Builder> std::ops::BitAnd for Regex<B> {
    type Output = Self;
    #[inline]
    fn bitand(self, rhs: Self) -> Self::Output {
        B::and(self, rhs)
    }
}

impl<B: Builder> std::ops::Not for Regex<B> {
    type Output = Self;
    #[inline]
    fn not(self) -> Self::Output {
        B::complement(self)
    }
}

#[cfg(test)]
mod tests {
    use crate::similarity::ApproximatelySimilarCanonical;
    use crate::Builder;
    use crate::Pure;

    use super::*;

    #[test]
    fn test_ops_pure() {
        test_ops::<Pure<_>>()
    }

    #[test]
    fn test_ops_asc() {
        test_ops::<ApproximatelySimilarCanonical<_>>()
    }

    fn test_ops<B: Builder<Symbol = usize> + Clone>() {
        let _: Vec<Regex<B>> = vec![
            42.s(),
            [1.s(), 2.s()].r(),
            [1.s(), 3.s()].r() & 7.s(),
            ().r() | 7.s(),
            !().r(),
            [].r(),
        ];
    }
}