ct_regex_internal/codegen/convert_hir/
into_matcher.rs

1use std::any;
2
3use proc_macro2::{Ident, TokenStream};
4use quote::{format_ident, quote};
5use regex_syntax::hir::{Capture, Class, ClassBytesRange, ClassUnicodeRange, Hir, HirKind, Literal, Look, Repetition};
6
7use crate::{codegen::{CodegenItem, Group, Groups}, matcher::{Always as A, Or, Then}};
8
9pub fn type_name<T>() -> &'static str {
10    any::type_name::<T>()
11        .split('<').next().unwrap()
12        .rsplit("::").next().unwrap()
13}
14
15pub fn type_ident<T>() -> Ident {
16    match ::quote::__private::IdentFragmentAdapter(&type_name::<T>()) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}", type_name::<T>())
17}
18
19pub trait HirExtension {
20    fn into_matcher<I: CodegenItem>(self) -> (TokenStream, Vec<Group>);
21}
22
23impl HirExtension for Hir {
24    fn into_matcher<I: CodegenItem>(self) -> (TokenStream, Vec<Group>) {
25        let mut caps = Groups::new();
26        let tokens = self.into_matcher_expr::<I>(&mut caps);
27        (tokens, caps.into_vec())
28    }
29}
30
31pub trait IntoMatcherExpr {
32    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream;
33}
34
35impl IntoMatcherExpr for Hir {
36    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
37        match self.into_kind() {
38            HirKind::Empty              => Empty.into_matcher_expr::<I>(caps),
39            HirKind::Literal(lit)       => lit.into_matcher_expr::<I>(caps),
40            HirKind::Class(class)       => class.into_matcher_expr::<I>(caps),
41            HirKind::Look(look)         => look.into_matcher_expr::<I>(caps),
42            HirKind::Repetition(rep)    => rep.into_matcher_expr::<I>(caps),
43            HirKind::Capture(cap)       => cap.into_matcher_expr::<I>(caps),
44            HirKind::Concat(hirs)       => Concat(hirs).into_matcher_expr::<I>(caps),
45            HirKind::Alternation(hirs)  => Alternation(hirs).into_matcher_expr::<I>(caps),
46        }
47    }
48}
49
50#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Empty {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Empty")
    }
}Debug)]
51struct Empty;
52
53#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Concat {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Concat",
            &&self.0)
    }
}Debug)]
54struct Concat(pub Vec<Hir>);
55
56#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Alternation {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Alternation",
            &&self.0)
    }
}Debug)]
57struct Alternation(pub Vec<Hir>);
58
59#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Backtrack {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Backtrack",
            "rep", &self.rep, "then", &&self.then)
    }
}Debug)]
60struct Backtrack {
61    rep: Repetition,
62    then: Vec<Hir>,
63}
64
65impl IntoMatcherExpr for u8 {
66    fn into_matcher_expr<I: CodegenItem>(self, _caps: &mut Groups) -> TokenStream {
67        match (&type_name::<I>(), &type_name::<u8>()) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(type_name::<I>(), type_name::<u8>());
68        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Byte");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&self, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::Byte<#self>)
69    }
70}
71
72impl IntoMatcherExpr for &ClassBytesRange {
73    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
74        match (&type_name::<I>(), &type_name::<u8>()) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(type_name::<I>(), type_name::<u8>());
75        if self.start() == self.end() {
76            self.start().into_matcher_expr::<I>(caps)
77        } else {
78            let start = self.start();
79            let end = self.end();
80            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ByteRange");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&start, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&end, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::ByteRange<#start, #end>)
81        }
82    }
83}
84
85impl IntoMatcherExpr for char {
86    fn into_matcher_expr<I: CodegenItem>(self, _caps: &mut Groups) -> TokenStream {
87        match (&type_name::<I>(), &type_name::<char>()) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(type_name::<I>(), type_name::<char>());
88        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Scalar");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&self, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::Scalar<#self>)
89    }
90}
91
92impl IntoMatcherExpr for &ClassUnicodeRange {
93    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
94        match (&type_name::<I>(), &type_name::<char>()) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::Some(format_args!("{0:?}", self)));
        }
    }
};assert_eq!(type_name::<I>(), type_name::<char>(), "{:?}", self);
95        if self.start() == self.end() {
96            self.start().into_matcher_expr::<I>(caps)
97        } else {
98            let start = self.start();
99            let end = self.end();
100            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ScalarRange");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&start, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&end, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::ScalarRange<#start, #end>)
101        }
102    }
103}
104
105impl IntoMatcherExpr for Empty {
106    fn into_matcher_expr<I: CodegenItem>(self, _caps: &mut Groups) -> TokenStream {
107        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Always");
    _s
}quote!(::ct_regex::internal::matcher::Always)
108    }
109}
110
111impl IntoMatcherExpr for Literal {
112    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
113        write_chunked::<Then<u8, A, A>, I, _>(
114            caps,
115            I::vec_from_str(
116                str::from_utf8(&self.0)
117                    .expect("failed to convert bytes to valid unicode")
118            )
119        )
120    }
121}
122
123impl IntoMatcherExpr for Class {
124    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
125        match I::normalize_class(self) {
126            Class::Unicode(unicode) => write_chunked::<Or<u8, A, A>, I, _>(
127                caps,
128                unicode.ranges().iter().collect()
129            ),
130            Class::Bytes(bytes) => write_chunked::<Or<u8, A, A>, I, _>(
131                caps,
132                bytes.ranges().iter().collect()
133            ),
134        }
135    }
136}
137
138impl IntoMatcherExpr for Look {
139    fn into_matcher_expr<I: CodegenItem>(self, _caps: &mut Groups) -> TokenStream {
140        match self {
141            Look::Start => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Beginning");
    _s
}quote!(::ct_regex::internal::matcher::Beginning),
142            Look::End => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "End");
    _s
}quote!(::ct_regex::internal::matcher::End),
143            Look::StartLF => {
    ::core::panicking::panic_fmt(format_args!("not yet implemented: {0}",
            format_args!("complex looking")));
}todo!("complex looking"),
144            Look::EndLF => {
    ::core::panicking::panic_fmt(format_args!("not yet implemented: {0}",
            format_args!("complex looking")));
}todo!("complex looking"),
145            Look::StartCRLF => {
    ::core::panicking::panic_fmt(format_args!("not yet implemented: {0}",
            format_args!("complex looking")));
}todo!("complex looking"),
146            Look::EndCRLF => {
    ::core::panicking::panic_fmt(format_args!("not yet implemented: {0}",
            format_args!("complex looking")));
}todo!("complex looking"),
147            _ => {
    ::core::panicking::panic_fmt(format_args!("not implemented: {0}",
            format_args!("complex look arounds")));
}unimplemented!("complex look arounds"),
148        }
149    }
150}
151
152impl IntoMatcherExpr for Repetition {
153    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
154        let Repetition { min, max, greedy, sub } = self;
155        if !greedy {
156            {
    ::core::panicking::panic_fmt(format_args!("not yet implemented: {0}",
            format_args!("lazy repetition")));
}todo!("lazy repetition")
157        }
158
159        let required = caps.required;
160        if min == 0 {
161            caps.required = false;
162        }
163
164        let item_type = type_ident::<I>();
165        let sub_matcher = sub.into_matcher_expr::<I>(caps);
166        // I need to document this somewhere, might as well be here: usize is used for all generic
167        // parameters, even though Hir types use u32, because it is used for arrasy indexing during
168        // the conversion process.
169        let (min, max) = (min as usize, max.map(|m| m as usize));
170
171        let tokens = match max {
172            None => {
173                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierNOrMore");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&min, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierNOrMore<#item_type, #sub_matcher, #min>)
174            },
175            Some(max) if min == max => {
176                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierN");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&min, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierN<#item_type, #sub_matcher, #min>)
177            },
178            Some(max) => {
179                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierNToM");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&min, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&max, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierNToM<#item_type, #sub_matcher, #min, #max>)
180            },
181        };
182
183        if min == 0 {
184            caps.required = required;
185        }
186
187        tokens
188    }
189}
190
191impl IntoMatcherExpr for Capture {
192    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
193        caps.insert(self.index, self.name);
194        let item_type = type_ident::<I>();
195        let sub_matcher = self.sub.into_matcher_expr::<I>(caps);
196        let index = self.index as usize;
197
198        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "CaptureGroup");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sub_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&index, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::CaptureGroup<#item_type, #sub_matcher, #index>)
199    }
200}
201
202impl IntoMatcherExpr for Alternation {
203    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
204        let required = caps.required;
205        caps.required = false;
206        let tokens = write_chunked::<Or<u8, A, A>, I, _>(caps, self.0);
207        caps.required = required;
208        tokens
209    }
210}
211
212impl IntoMatcherExpr for Concat {
213    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
214        let mut iter = self.0.into_iter();
215        let mut rep_item = None;
216        let concat = Concat(
217            iter.by_ref()
218                .take_while(|i| if let HirKind::Repetition(rep) = i.kind() {
219                    rep_item = Some(rep.clone());
220                    false
221                } else {
222                    true
223                })
224                .collect()
225        );
226        if let Some(rep) = rep_item {
227            let backtrack = Backtrack {
228                rep,
229                then: iter.collect(),
230            };
231
232            match (concat.0.len(), backtrack.then.len()) {
233                (0, 0) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
234                (0, _) => backtrack.into_matcher_expr::<I>(caps),
235                (_, _) => {
236                    let item_type = type_ident::<I>();
237                    let concat_matcher = concat.write_type_basic::<I>(caps);
238                    let backtrack_matcher = backtrack.into_matcher_expr::<I>(caps);
239
240                    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Then");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&concat_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&backtrack_matcher, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::Then<#item_type, #concat_matcher, #backtrack_matcher>)
241                },
242            }
243        } else {
244            concat.write_type_basic::<I>(caps)
245        }
246    }
247}
248
249impl IntoMatcherExpr for Backtrack {
250    fn into_matcher_expr<I: CodegenItem>(mut self, caps: &mut Groups) -> TokenStream {
251        let item_type = type_ident::<I>();
252        let rep_matcher = self.rep.into_matcher_expr::<I>(caps);
253        let then_matcher = match self.then.len() {
254            0 => return rep_matcher,
255            1 => self.then.pop().unwrap().into_matcher_expr::<I>(caps),
256            _ => Concat(self.then).into_matcher_expr::<I>(caps)
257        };
258
259        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QuantifierThen");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&rep_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&then_matcher, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::QuantifierThen<#item_type, #rep_matcher, #then_matcher>)
260    }
261}
262
263impl Concat {
264    fn write_type_basic<I: CodegenItem>(self, caps: &mut Groups) -> TokenStream {
265        write_chunked::<Then<u8, A, A>, I, _>(caps, self.0)
266    }
267}
268
269fn write_chunked<T, I: CodegenItem, W: IntoMatcherExpr>(
270    caps: &mut Groups,
271    mut items: Vec<W>,
272) -> TokenStream {
273    let n = items.len();
274    let base = match ::quote::__private::IdentFragmentAdapter(&type_name::<T>()) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("{0}", arg))
                    }), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("{}", type_name::<T>());
275    let item_type = type_ident::<I>();
276
277    match n {
278        0 => { ::core::panicking::panic_fmt(format_args!("literal contains no items")); }panic!("literal contains no items"),
279        1 => items.pop().unwrap().into_matcher_expr::<I>(caps),
280        2 => {
281            let mut iter = items.into_iter();
282            let first = iter.next().unwrap().into_matcher_expr::<I>(caps);
283            let second = iter.next().unwrap().into_matcher_expr::<I>(caps);
284
285            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&base, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&first, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&second, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#base<#item_type, #first, #second>)
286        }
287        3 => {
288            let mut iter = items.into_iter();
289            let first = iter.next().unwrap().into_matcher_expr::<I>(caps);
290            let chunked = write_chunked::<T, I, W>(caps, iter.collect());
291
292            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&base, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&first, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&chunked, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#base<#item_type, #first, #chunked>)
293        }
294        4 | 8 | 16 => write_n_items::<T, I, W>(caps, items, n),
295        _ => {
296            // Take largest chunk that fits, combine with remainder
297            let chunk_size = if n > 16 { 16 } else if n > 8 { 8 } else { 4 };
298            let remainder = items.split_off(chunk_size);
299            let n_matcher = write_n_items::<T, I, W>(caps, items, chunk_size);
300            let chunked = write_chunked::<T, I, W>(caps, remainder);
301
302            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&base, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&n_matcher, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&chunked, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#base<#item_type, #n_matcher, #chunked>)
303        }
304    }
305}
306
307fn write_n_items<T, I: CodegenItem, W: IntoMatcherExpr>(
308    caps: &mut Groups,
309    items: Vec<W>,
310    n: usize,
311) -> TokenStream {
312    let name = match ::quote::__private::IdentFragmentAdapter(&type_name::<T>()) {
    arg =>
        match ::quote::__private::IdentFragmentAdapter(&n) {
            arg =>
                ::quote::__private::mk_ident(&::alloc::__export::must_use({
                                ::alloc::fmt::format(format_args!("{0}{1}", arg, arg))
                            }),
                    ::quote::__private::Option::None.or(arg.span()).or(arg.span())),
        },
}format_ident!("{}{}", type_name::<T>(), n);
313    let item_type = type_ident::<I>();
314
315    let mut tokens = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ct_regex");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "matcher");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    _s
}quote!(::ct_regex::internal::matcher::#name<#item_type);
316
317    for item in items {
318        tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_comma(&mut _s);
    _s
}quote!(,));
319        tokens.extend(item.into_matcher_expr::<I>(caps));
320    }
321
322    tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(>));
323    tokens
324}