Skip to main content

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::{
6    Capture, Class, ClassBytesRange, ClassUnicodeRange, Hir, HirKind, Literal, Look, Repetition,
7};
8
9use crate::codegen::{CodegenItem, ExprMetadata};
10use crate::matcher::{Always as A, Or, Then};
11
12pub(crate) fn type_name<T>() -> &'static str {
13    any::type_name::<T>()
14        .split('<').next().unwrap()
15        .rsplit("::").next().unwrap()
16}
17
18pub(crate) fn type_ident<T>() -> Ident {
19    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>())
20}
21
22pub(crate) trait IntoMatcherExpr {
23    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream;
24}
25
26impl IntoMatcherExpr for Hir {
27    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
28        match self.into_kind() {
29            HirKind::Empty              => Empty.into_matcher_expr::<I>(meta),
30            HirKind::Literal(lit)       => lit.into_matcher_expr::<I>(meta),
31            HirKind::Class(class)       => class.into_matcher_expr::<I>(meta),
32            HirKind::Look(look)         => look.into_matcher_expr::<I>(meta),
33            HirKind::Repetition(rep)    => rep.into_matcher_expr::<I>(meta),
34            HirKind::Capture(cap)       => cap.into_matcher_expr::<I>(meta),
35            HirKind::Concat(hirs)       => Concat(hirs).into_matcher_expr::<I>(meta),
36            HirKind::Alternation(hirs)  => Alternation(hirs).into_matcher_expr::<I>(meta),
37        }
38    }
39}
40
41#[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, #[automatically_derived]
impl ::core::clone::Clone for Empty {
    #[inline]
    fn clone(&self) -> Empty { Empty }
}Clone)]
42struct Empty;
43
44#[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, #[automatically_derived]
impl ::core::clone::Clone for Concat {
    #[inline]
    fn clone(&self) -> Concat { Concat(::core::clone::Clone::clone(&self.0)) }
}Clone)]
45struct Concat(pub Vec<Hir>);
46
47#[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, #[automatically_derived]
impl ::core::clone::Clone for Alternation {
    #[inline]
    fn clone(&self) -> Alternation {
        Alternation(::core::clone::Clone::clone(&self.0))
    }
}Clone)]
48struct Alternation(pub Vec<Hir>);
49
50impl IntoMatcherExpr for u8 {
51    fn into_matcher_expr<I: CodegenItem>(self, _meta: &mut ExprMetadata) -> TokenStream {
52        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>());
53        {
    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>)
54    }
55}
56
57impl IntoMatcherExpr for &ClassBytesRange {
58    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
59        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>());
60        if self.start() == self.end() {
61            self.start().into_matcher_expr::<I>(meta)
62        } else {
63            let start = self.start();
64            let end = self.end();
65            {
    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>)
66        }
67    }
68}
69
70impl IntoMatcherExpr for char {
71    fn into_matcher_expr<I: CodegenItem>(self, _meta: &mut ExprMetadata) -> TokenStream {
72        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>());
73        {
    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>)
74    }
75}
76
77impl IntoMatcherExpr for &ClassUnicodeRange {
78    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
79        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);
80        if self.start() == self.end() {
81            self.start().into_matcher_expr::<I>(meta)
82        } else {
83            let start = self.start();
84            let end = self.end();
85            {
    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>)
86        }
87    }
88}
89
90impl IntoMatcherExpr for Empty {
91    fn into_matcher_expr<I: CodegenItem>(self, _meta: &mut ExprMetadata) -> TokenStream {
92        {
    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)
93    }
94}
95
96impl IntoMatcherExpr for Literal {
97    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
98        #![allow(nonstandard_style)]
99        let LiteralTy = meta.insert_literal(self.0);
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, "LiteralMatcher");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&LiteralTy, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::LiteralMatcher<#LiteralTy>)
101    }
102}
103
104impl IntoMatcherExpr for Class {
105    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
106        match I::normalize_class(self) {
107            Class::Unicode(unicode) => write_chunked::<Or<u8, A, A>, I, _>(
108                meta,
109                unicode.ranges().iter().collect()
110            ),
111            Class::Bytes(bytes) => write_chunked::<Or<u8, A, A>, I, _>(
112                meta,
113                bytes.ranges().iter().collect()
114            ),
115        }
116    }
117}
118
119impl IntoMatcherExpr for Look {
120    fn into_matcher_expr<I: CodegenItem>(self, _meta: &mut ExprMetadata) -> TokenStream {
121        match self {
122            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, "Start");
    _s
}quote!(::ct_regex::internal::matcher::Start),
123            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),
124            Look::StartLF => {
    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, "LineStart");
    _s
}quote!(::ct_regex::internal::matcher::LineStart),
125            Look::EndLF => {
    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, "LineEnd");
    _s
}quote!(::ct_regex::internal::matcher::LineEnd),
126            Look::StartCRLF => {
    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, "CRLFStart");
    _s
}quote!(::ct_regex::internal::matcher::CRLFStart),
127            Look::EndCRLF => {
    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, "CRLFEnd");
    _s
}quote!(::ct_regex::internal::matcher::CRLFEnd),
128            _ => {
    ::core::panicking::panic_fmt(format_args!("not implemented: {0}",
            format_args!("complex look arounds")));
}unimplemented!("complex look arounds"),
129        }
130    }
131}
132
133impl IntoMatcherExpr for Repetition {
134    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
135        let Repetition { min, max, greedy, sub } = self;
136
137        let required = meta.required;
138        if min == 0 {
139            meta.required = false;
140        }
141
142        let item_type = type_ident::<I>();
143        let sub_matcher = sub.into_matcher_expr::<I>(meta);
144        // I need to document this somewhere, might as well be here: usize is used for all generic
145        // parameters, even though Hir types use u32, because it is used for array indexing during
146        // the conversion process.
147        let (min, max) = (min as usize, max.map(|m| m as usize));
148
149        if min == 0 {
150            meta.required = required;
151        }
152
153        let tokens = match max {
154            None => {
155                {
    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>)
156            },
157            Some(max) if min == max => {
158                return {
    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>);
159            },
160            Some(max) => {
161                {
    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>)
162            },
163        };
164
165        if greedy {
166            tokens
167        } else {
168            {
    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, "Lazy");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&item_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&tokens, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(::ct_regex::internal::matcher::Lazy<#item_type, #tokens>)
169        }
170    }
171}
172
173impl IntoMatcherExpr for Capture {
174    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
175        meta.insert_group(self.index, self.name);
176        let item_type = type_ident::<I>();
177        let sub_matcher = self.sub.into_matcher_expr::<I>(meta);
178        let index = self.index as usize;
179
180        {
    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>)
181    }
182}
183
184impl IntoMatcherExpr for Alternation {
185    fn into_matcher_expr<I: CodegenItem>(self, caps: &mut ExprMetadata) -> TokenStream {
186        let required = caps.required;
187        caps.required = false;
188        let tokens = write_chunked::<Or<u8, A, A>, I, _>(caps, self.0);
189        caps.required = required;
190        tokens
191    }
192}
193
194impl IntoMatcherExpr for Concat {
195    fn into_matcher_expr<I: CodegenItem>(self, meta: &mut ExprMetadata) -> TokenStream {
196        write_chunked::<Then<u8, A, A>, I, _>(meta, self.0)
197    }
198}
199
200fn write_chunked<T, I: CodegenItem, W: IntoMatcherExpr>(
201    meta: &mut ExprMetadata,
202    mut items: Vec<W>,
203) -> TokenStream {
204    let n = items.len();
205    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>());
206    let item_type = type_ident::<I>();
207
208    match n {
209        0 => { ::core::panicking::panic_fmt(format_args!("literal contains no items")); }panic!("literal contains no items"),
210        1 => items.pop().unwrap().into_matcher_expr::<I>(meta),
211        2 => {
212            let mut iter = items.into_iter();
213            let first = iter.next().unwrap().into_matcher_expr::<I>(meta);
214            let second = iter.next().unwrap().into_matcher_expr::<I>(meta);
215
216            {
    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>)
217        },
218        3 => {
219            let mut iter = items.into_iter();
220            let first = iter.next().unwrap().into_matcher_expr::<I>(meta);
221            let chunked = write_chunked::<T, I, W>(meta, iter.collect());
222
223            {
    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>)
224        },
225        4 | 8 | 16 => write_n_items::<T, I, W>(meta, items, n),
226        _ => {
227            // Take largest chunk that fits, combine with remainder
228            let chunk_size = if n > 16 {
229                16
230            } else if n > 8 {
231                8
232            } else {
233                4
234            };
235            let remainder = items.split_off(chunk_size);
236            let n_matcher = write_n_items::<T, I, W>(meta, items, chunk_size);
237            let chunked = write_chunked::<T, I, W>(meta, remainder);
238
239            {
    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>)
240        },
241    }
242}
243
244fn write_n_items<T, I: CodegenItem, W: IntoMatcherExpr>(
245    meta: &mut ExprMetadata,
246    items: Vec<W>,
247    n: usize,
248) -> TokenStream {
249    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);
250    let item_type = type_ident::<I>();
251
252    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);
253
254    for item in items {
255        tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_comma(&mut _s);
    _s
}quote!(,));
256        tokens.extend(item.into_matcher_expr::<I>(meta));
257    }
258
259    tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_gt(&mut _s);
    _s
}quote!(>));
260    tokens
261}