<commit_before>use crate::ast::{Enum, Field, Input, Struct};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{DeriveInput, Member, PathArguments, Result, Type};

pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
    let input = Input::from_syn(node)?;
    input.validate()?;
    Ok(match input {
        Input::Struct(input) => impl_struct(input),
        Input::Enum(input) => impl_enum(input),
    })
}

fn impl_struct(input: Struct) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::error::Error::source(self.#only_field.as_dyn_error())
        })
    } else if let Some(source_field) = input.source_field() {
        let source = &source_field.member;
        let asref = if type_is_option(source_field.ty) {
            Some(quote_spanned!(source.span()=> .as_ref()?))
        } else {
            None
        };
        let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error());
        Some(quote! {
            std::option::Option::Some(#dyn_error)
        })
    } else {
        None
    };
    let source_method = source_body.map(|body| {
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #body
            }
        }
    });

    let backtrace_method = input.backtrace_field().map(|backtrace_field| {
        let backtrace = &backtrace_field.member;
        let body = if let Some(source_field) = input.source_field() {
            let source = &source_field.member;
            let source_backtrace = if type_is_option(source_field.ty) {
                quote_spanned! {source.span()=>
                    self.#source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                }
            } else {
                quote_spanned! {source.span()=>
                    self.#source.as_dyn_error().backtrace()
                }
            };
            let combinator = if type_is_option(backtrace_field.ty) {
                quote! {
                    #source_backtrace.or(self.#backtrace.as_ref())
                }
            } else {
                quote! {
                    std::option::Option::Some(#source_backtrace.unwrap_or(&self.#backtrace))
                }
            };
            quote! {
                use thiserror::private::AsDynError;
                #combinator
            }
        } else if type_is_option(backtrace_field.ty) {
            quote! {
                self.#backtrace.as_ref()
            }
        } else {
            quote! {
                std::option::Option::Some(&self.#backtrace)
            }
        };
        quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #body
            }
        }
    });

    let display_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::fmt::Display::fmt(&self.#only_field, __formatter)
        })
    } else if let Some(display) = &input.attrs.display {
        let use_as_display = if display.has_bonus_display {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let pat = fields_pat(&input.fields);
        Some(quote! {
            #use_as_display
            #[allow(unused_variables)]
            let Self #pat = self;
            #display
        })
    } else {
        None
    };
    let display_impl = display_body.map(|body| {
        quote! {
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #body
                }
            }
        }
    });

    let from_impl = input.from_field().map(|from_field| {
        let backtrace_field = input.backtrace_field();
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        quote! {
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                fn from(source: #from) -> Self {
                    #ty #body
                }
            }
        }
    });

    quote! {
        impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #from_impl
    }
}

fn impl_enum(input: Enum) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_method = if input.has_source() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            if variant.attrs.transparent.is_some() {
                let only_field = &variant.fields[0].member;
                let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
                quote! {
                    #ty::#ident {#only_field: transparent} => #source,
                }
            } else if let Some(source_field) = variant.source_field() {
                let source = &source_field.member;
                let asref = if type_is_option(source_field.ty) {
                    Some(quote_spanned!(source.span()=> .as_ref()?))
                } else {
                    None
                };
                let dyn_error = quote_spanned!(source.span()=> source #asref.as_dyn_error());
                quote! {
                    #ty::#ident {#source: source, ..} => std::option::Option::Some(#dyn_error),
                }
            } else {
                quote! {
                    #ty::#ident {..} => std::option::Option::None,
                }
            }
        });
        Some(quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let backtrace_method = if input.has_backtrace() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            match (variant.backtrace_field(), variant.source_field()) {
                (Some(backtrace_field), Some(source_field))
                    if backtrace_field.attrs.backtrace.is_none() =>
                {
                    let backtrace = &backtrace_field.member;
                    let source = &source_field.member;
                    let source_backtrace = if type_is_option(source_field.ty) {
                        quote_spanned! {source.span()=>
                            source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                        }
                    } else {
                        quote_spanned! {source.span()=>
                            source.as_dyn_error().backtrace()
                        }
                    };
                    let combinator = if type_is_option(backtrace_field.ty) {
                        quote! {
                            #source_backtrace.or(backtrace.as_ref())
                        }
                    } else {
                        quote! {
                            std::option::Option::Some(#source_backtrace.unwrap_or(backtrace))
                        }
                    };
                    quote! {
                        #ty::#ident {
                            #backtrace: backtrace,
                            #source: source,
                            ..
                        } => {
                            use thiserror::private::AsDynError;
                            #combinator
                        }
                    }
                }
                (Some(backtrace_field), _) => {
                    let backtrace = &backtrace_field.member;
                    let body = if type_is_option(backtrace_field.ty) {
                        quote!(backtrace.as_ref())
                    } else {
                        quote!(std::option::Option::Some(backtrace))
                    };
                    quote! {
                        #ty::#ident {#backtrace: backtrace, ..} => #body,
                    }
                }
                (None, _) => quote! {
                    #ty::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let display_impl = if input.has_display() {
        let use_as_display = if input.variants.iter().any(|v| {
            v.attrs
                .display
                .as_ref()
                .map_or(false, |display| display.has_bonus_display)
        }) {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let void_deref = if input.variants.is_empty() {
            Some(quote!(*))
        } else {
            None
        };
        let arms = input.variants.iter().map(|variant| {
            let display = match &variant.attrs.display {
                Some(display) => display.to_token_stream(),
                None => {
                    let only_field = match &variant.fields[0].member {
                        Member::Named(ident) => ident.clone(),
                        Member::Unnamed(index) => format_ident!("_{}", index),
                    };
                    quote!(std::fmt::Display::fmt(#only_field, __formatter))
                }
            };
            let ident = &variant.ident;
            let pat = fields_pat(&variant.fields);
            quote! {
                #ty::#ident #pat => #display
            }
        });
        Some(quote! {
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #use_as_display
                    #[allow(unused_variables)]
                    match #void_deref self {
                        #(#arms,)*
                    }
                }
            }
        })
    } else {
        None
    };

    let from_impls = input.variants.iter().filter_map(|variant| {
        let from_field = variant.from_field()?;
        let backtrace_field = variant.backtrace_field();
        let variant = &variant.ident;
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        Some(quote! {
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                fn from(source: #from) -> Self {
                    #ty::#variant #body
                }
            }
        })
    });

    quote! {
        impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #(#from_impls)*
    }
}

fn fields_pat(fields: &[Field]) -> TokenStream {
    let mut members = fields.iter().map(|field| &field.member).peekable();
    match members.peek() {
        Some(Member::Named(_)) => quote!({ #(#members),* }),
        Some(Member::Unnamed(_)) => {
            let vars = members.map(|member| match member {
                Member::Unnamed(member) => format_ident!("_{}", member),
                Member::Named(_) => unreachable!(),
            });
            quote!((#(#vars),*))
        }
        None => quote!({}),
    }
}

fn from_initializer(from_field: &Field, backtrace_field: Option<&Field>) -> TokenStream {
    let from_member = &from_field.member;
    let backtrace = backtrace_field.map(|backtrace_field| {
        let backtrace_member = &backtrace_field.member;
        if type_is_option(backtrace_field.ty) {
            quote! {
                #backtrace_member: std::option::Option::Some(std::backtrace::Backtrace::capture()),
            }
        } else {
            quote! {
                #backtrace_member: std::backtrace::Backtrace::capture(),
            }
        }
    });
    quote!({
        #from_member: source,
        #backtrace
    })
}

fn type_is_option(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    if last.ident != "Option" {
        return false;
    }

    match &last.arguments {
        PathArguments::AngleBracketed(bracketed) => bracketed.args.len() == 1,
        _ => false,
    }
}
<commit_msg>Allow matches to refer to deprecated variants<commit_after>use crate::ast::{Enum, Field, Input, Struct};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{DeriveInput, Member, PathArguments, Result, Type};

pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
    let input = Input::from_syn(node)?;
    input.validate()?;
    Ok(match input {
        Input::Struct(input) => impl_struct(input),
        Input::Enum(input) => impl_enum(input),
    })
}

fn impl_struct(input: Struct) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::error::Error::source(self.#only_field.as_dyn_error())
        })
    } else if let Some(source_field) = input.source_field() {
        let source = &source_field.member;
        let asref = if type_is_option(source_field.ty) {
            Some(quote_spanned!(source.span()=> .as_ref()?))
        } else {
            None
        };
        let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error());
        Some(quote! {
            std::option::Option::Some(#dyn_error)
        })
    } else {
        None
    };
    let source_method = source_body.map(|body| {
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #body
            }
        }
    });

    let backtrace_method = input.backtrace_field().map(|backtrace_field| {
        let backtrace = &backtrace_field.member;
        let body = if let Some(source_field) = input.source_field() {
            let source = &source_field.member;
            let source_backtrace = if type_is_option(source_field.ty) {
                quote_spanned! {source.span()=>
                    self.#source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                }
            } else {
                quote_spanned! {source.span()=>
                    self.#source.as_dyn_error().backtrace()
                }
            };
            let combinator = if type_is_option(backtrace_field.ty) {
                quote! {
                    #source_backtrace.or(self.#backtrace.as_ref())
                }
            } else {
                quote! {
                    std::option::Option::Some(#source_backtrace.unwrap_or(&self.#backtrace))
                }
            };
            quote! {
                use thiserror::private::AsDynError;
                #combinator
            }
        } else if type_is_option(backtrace_field.ty) {
            quote! {
                self.#backtrace.as_ref()
            }
        } else {
            quote! {
                std::option::Option::Some(&self.#backtrace)
            }
        };
        quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #body
            }
        }
    });

    let display_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::fmt::Display::fmt(&self.#only_field, __formatter)
        })
    } else if let Some(display) = &input.attrs.display {
        let use_as_display = if display.has_bonus_display {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let pat = fields_pat(&input.fields);
        Some(quote! {
            #use_as_display
            #[allow(unused_variables, deprecated)]
            let Self #pat = self;
            #display
        })
    } else {
        None
    };
    let display_impl = display_body.map(|body| {
        quote! {
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #body
                }
            }
        }
    });

    let from_impl = input.from_field().map(|from_field| {
        let backtrace_field = input.backtrace_field();
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        quote! {
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                #[allow(deprecated)]
                fn from(source: #from) -> Self {
                    #ty #body
                }
            }
        }
    });

    quote! {
        impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #from_impl
    }
}

fn impl_enum(input: Enum) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_method = if input.has_source() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            if variant.attrs.transparent.is_some() {
                let only_field = &variant.fields[0].member;
                let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
                quote! {
                    #ty::#ident {#only_field: transparent} => #source,
                }
            } else if let Some(source_field) = variant.source_field() {
                let source = &source_field.member;
                let asref = if type_is_option(source_field.ty) {
                    Some(quote_spanned!(source.span()=> .as_ref()?))
                } else {
                    None
                };
                let dyn_error = quote_spanned!(source.span()=> source #asref.as_dyn_error());
                quote! {
                    #ty::#ident {#source: source, ..} => std::option::Option::Some(#dyn_error),
                }
            } else {
                quote! {
                    #ty::#ident {..} => std::option::Option::None,
                }
            }
        });
        Some(quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #[allow(deprecated)]
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let backtrace_method = if input.has_backtrace() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            match (variant.backtrace_field(), variant.source_field()) {
                (Some(backtrace_field), Some(source_field))
                    if backtrace_field.attrs.backtrace.is_none() =>
                {
                    let backtrace = &backtrace_field.member;
                    let source = &source_field.member;
                    let source_backtrace = if type_is_option(source_field.ty) {
                        quote_spanned! {source.span()=>
                            source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                        }
                    } else {
                        quote_spanned! {source.span()=>
                            source.as_dyn_error().backtrace()
                        }
                    };
                    let combinator = if type_is_option(backtrace_field.ty) {
                        quote! {
                            #source_backtrace.or(backtrace.as_ref())
                        }
                    } else {
                        quote! {
                            std::option::Option::Some(#source_backtrace.unwrap_or(backtrace))
                        }
                    };
                    quote! {
                        #ty::#ident {
                            #backtrace: backtrace,
                            #source: source,
                            ..
                        } => {
                            use thiserror::private::AsDynError;
                            #combinator
                        }
                    }
                }
                (Some(backtrace_field), _) => {
                    let backtrace = &backtrace_field.member;
                    let body = if type_is_option(backtrace_field.ty) {
                        quote!(backtrace.as_ref())
                    } else {
                        quote!(std::option::Option::Some(backtrace))
                    };
                    quote! {
                        #ty::#ident {#backtrace: backtrace, ..} => #body,
                    }
                }
                (None, _) => quote! {
                    #ty::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #[allow(deprecated)]
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let display_impl = if input.has_display() {
        let use_as_display = if input.variants.iter().any(|v| {
            v.attrs
                .display
                .as_ref()
                .map_or(false, |display| display.has_bonus_display)
        }) {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let void_deref = if input.variants.is_empty() {
            Some(quote!(*))
        } else {
            None
        };
        let arms = input.variants.iter().map(|variant| {
            let display = match &variant.attrs.display {
                Some(display) => display.to_token_stream(),
                None => {
                    let only_field = match &variant.fields[0].member {
                        Member::Named(ident) => ident.clone(),
                        Member::Unnamed(index) => format_ident!("_{}", index),
                    };
                    quote!(std::fmt::Display::fmt(#only_field, __formatter))
                }
            };
            let ident = &variant.ident;
            let pat = fields_pat(&variant.fields);
            quote! {
                #ty::#ident #pat => #display
            }
        });
        Some(quote! {
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #use_as_display
                    #[allow(unused_variables, deprecated)]
                    match #void_deref self {
                        #(#arms,)*
                    }
                }
            }
        })
    } else {
        None
    };

    let from_impls = input.variants.iter().filter_map(|variant| {
        let from_field = variant.from_field()?;
        let backtrace_field = variant.backtrace_field();
        let variant = &variant.ident;
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        Some(quote! {
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                #[allow(deprecated)]
                fn from(source: #from) -> Self {
                    #ty::#variant #body
                }
            }
        })
    });

    quote! {
        impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #(#from_impls)*
    }
}

fn fields_pat(fields: &[Field]) -> TokenStream {
    let mut members = fields.iter().map(|field| &field.member).peekable();
    match members.peek() {
        Some(Member::Named(_)) => quote!({ #(#members),* }),
        Some(Member::Unnamed(_)) => {
            let vars = members.map(|member| match member {
                Member::Unnamed(member) => format_ident!("_{}", member),
                Member::Named(_) => unreachable!(),
            });
            quote!((#(#vars),*))
        }
        None => quote!({}),
    }
}

fn from_initializer(from_field: &Field, backtrace_field: Option<&Field>) -> TokenStream {
    let from_member = &from_field.member;
    let backtrace = backtrace_field.map(|backtrace_field| {
        let backtrace_member = &backtrace_field.member;
        if type_is_option(backtrace_field.ty) {
            quote! {
                #backtrace_member: std::option::Option::Some(std::backtrace::Backtrace::capture()),
            }
        } else {
            quote! {
                #backtrace_member: std::backtrace::Backtrace::capture(),
            }
        }
    });
    quote!({
        #from_member: source,
        #backtrace
    })
}

fn type_is_option(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    if last.ident != "Option" {
        return false;
    }

    match &last.arguments {
        PathArguments::AngleBracketed(bracketed) => bracketed.args.len() == 1,
        _ => false,
    }
}
<|endoftext|>


<commit_before>mat!(uni_literal, r"☃", "☃", Some((0, 3)));
mat!(uni_literal_plus, r"☃+", "☃", Some((0, 3)));
mat!(uni_literal_casei_plus, r"(?i)☃+", "☃", Some((0, 3)));
mat!(uni_class_plus, r"[☃Ⅰ]+", "☃", Some((0, 3)));
mat!(uni_one, r"\pN", "Ⅰ", Some((0, 3)));
mat!(uni_mixed, r"\pN+", "Ⅰ1Ⅱ2", Some((0, 8)));
mat!(uni_not, r"\PN+", "abⅠ", Some((0, 2)));
mat!(uni_not_class, r"[\PN]+", "abⅠ", Some((0, 2)));
mat!(uni_not_class_neg, r"[^\PN]+", "abⅠ", Some((2, 5)));
mat!(uni_case, r"(?i)Δ", "δ", Some((0, 2)));
mat!(uni_case_upper, r"\p{Lu}+", "ΛΘΓΔα", Some((0, 8)));
mat!(uni_case_upper_nocase_flag, r"(?i)\p{Lu}+", "ΛΘΓΔα", Some((0, 10)));
mat!(uni_case_upper_nocase, r"\p{L}+", "ΛΘΓΔα", Some((0, 10)));
mat!(uni_case_lower, r"\p{Ll}+", "ΛΘΓΔα", Some((8, 10)));

// Test the Unicode friendliness of Perl character classes.
mat!(uni_perl_w, r"\w+", "dδd", Some((0, 4)));
mat!(uni_perl_w_not, r"\w+", "⥡", None);
mat!(uni_perl_w_neg, r"\W+", "⥡", Some((0, 3)));
mat!(uni_perl_d, r"\d+", "1२३9", Some((0, 8)));
mat!(uni_perl_d_not, r"\d+", "Ⅱ", None);
mat!(uni_perl_d_neg, r"\D+", "Ⅱ", Some((0, 3)));
mat!(uni_perl_s, r"\s+", " ", Some((0, 3)));
mat!(uni_perl_s_not, r"\s+", "☃", None);
mat!(uni_perl_s_neg, r"\S+", "☃", Some((0, 3)));

// And do the same for word boundaries.
mat!(uni_boundary_none, r"\d\b", "6δ", None);
mat!(uni_boundary_ogham, r"\d\b", "6 ", Some((0, 1)));
mat!(uni_not_boundary_none, r"\d\B", "6δ", Some((0, 1)));
mat!(uni_not_boundary_ogham, r"\d\B", "6 ", None);

// Test general categories.
//
// We should test more, but there's a lot. Write a script to generate more of
// these tests.
mat!(uni_class_gencat_cased_letter, r"\p{Cased_Letter}", "Ａ", Some((0, 3)));
mat!(
    uni_class_gencat_close_punctuation,
    r"\p{Close_Punctuation}",
    "❯",
    Some((0, 3))
);
mat!(
    uni_class_gencat_connector_punctuation,
    r"\p{Connector_Punctuation}",
    "⁀",
    Some((0, 3))
);
mat!(uni_class_gencat_control, r"\p{Control}", "\u{9f}", Some((0, 2)));
mat!(
    uni_class_gencat_currency_symbol,
    r"\p{Currency_Symbol}",
    "￡",
    Some((0, 3))
);
mat!(
    uni_class_gencat_dash_punctuation,
    r"\p{Dash_Punctuation}",
    "〰",
    Some((0, 3))
);
mat!(uni_class_gencat_decimal_numer, r"\p{Decimal_Number}", "𑓙", Some((0, 4)));
mat!(
    uni_class_gencat_enclosing_mark,
    r"\p{Enclosing_Mark}",
    "\u{A672}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_final_punctuation,
    r"\p{Final_Punctuation}",
    "⸡",
    Some((0, 3))
);
mat!(uni_class_gencat_format, r"\p{Format}", "\u{E007F}", Some((0, 4)));
// See: https://github.com/rust-lang/regex/issues/719
mat!(uni_class_gencat_format_abbrev1, r"\p{cf}", "\u{E007F}", Some((0, 4)));
mat!(uni_class_gencat_format_abbrev2, r"\p{gc=cf}", "\u{E007F}", Some((0, 4)));
mat!(
    uni_class_gencat_initial_punctuation,
    r"\p{Initial_Punctuation}",
    "⸜",
    Some((0, 3))
);
mat!(uni_class_gencat_letter, r"\p{Letter}", "Έ", Some((0, 2)));
mat!(uni_class_gencat_letter_number, r"\p{Letter_Number}", "ↂ", Some((0, 3)));
mat!(
    uni_class_gencat_line_separator,
    r"\p{Line_Separator}",
    "\u{2028}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_lowercase_letter,
    r"\p{Lowercase_Letter}",
    "ϛ",
    Some((0, 2))
);
mat!(uni_class_gencat_mark, r"\p{Mark}", "\u{E01EF}", Some((0, 4)));
mat!(uni_class_gencat_math, r"\p{Math}", "⋿", Some((0, 3)));
mat!(
    uni_class_gencat_modifier_letter,
    r"\p{Modifier_Letter}",
    "𖭃",
    Some((0, 4))
);
mat!(
    uni_class_gencat_modifier_symbol,
    r"\p{Modifier_Symbol}",
    "🏿",
    Some((0, 4))
);
mat!(
    uni_class_gencat_nonspacing_mark,
    r"\p{Nonspacing_Mark}",
    "\u{1E94A}",
    Some((0, 4))
);
mat!(uni_class_gencat_number, r"\p{Number}", "⓿", Some((0, 3)));
mat!(
    uni_class_gencat_open_punctuation,
    r"\p{Open_Punctuation}",
    "｟",
    Some((0, 3))
);
mat!(uni_class_gencat_other, r"\p{Other}", "\u{bc9}", Some((0, 3)));
mat!(uni_class_gencat_other_letter, r"\p{Other_Letter}", "ꓷ", Some((0, 3)));
mat!(uni_class_gencat_other_number, r"\p{Other_Number}", "㉏", Some((0, 3)));
mat!(
    uni_class_gencat_other_punctuation,
    r"\p{Other_Punctuation}",
    "𞥞",
    Some((0, 4))
);
mat!(uni_class_gencat_other_symbol, r"\p{Other_Symbol}", "⅌", Some((0, 3)));
mat!(
    uni_class_gencat_paragraph_separator,
    r"\p{Paragraph_Separator}",
    "\u{2029}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_private_use,
    r"\p{Private_Use}",
    "\u{10FFFD}",
    Some((0, 4))
);
mat!(uni_class_gencat_punctuation, r"\p{Punctuation}", "𑁍", Some((0, 4)));
mat!(uni_class_gencat_separator, r"\p{Separator}", "\u{3000}", Some((0, 3)));
mat!(
    uni_class_gencat_space_separator,
    r"\p{Space_Separator}",
    "\u{205F}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_spacing_mark,
    r"\p{Spacing_Mark}",
    "\u{16F7E}",
    Some((0, 4))
);
mat!(uni_class_gencat_symbol, r"\p{Symbol}", "⯈", Some((0, 3)));
mat!(
    uni_class_gencat_titlecase_letter,
    r"\p{Titlecase_Letter}",
    "ῼ",
    Some((0, 3))
);
mat!(
    uni_class_gencat_unassigned,
    r"\p{Unassigned}",
    "\u{10FFFF}",
    Some((0, 4))
);
mat!(
    uni_class_gencat_uppercase_letter,
    r"\p{Uppercase_Letter}",
    "Ꝋ",
    Some((0, 3))
);

// Test a smattering of properties.
mat!(uni_class_prop_emoji1, r"\p{Emoji}", "\u{23E9}", Some((0, 3)));
mat!(uni_class_prop_emoji2, r"\p{emoji}", "\u{1F21A}", Some((0, 4)));
mat!(
    uni_class_prop_picto1,
    r"\p{extendedpictographic}",
    "\u{1FA6E}",
    Some((0, 4))
);
mat!(
    uni_class_prop_picto2,
    r"\p{extendedpictographic}",
    "\u{1FFFD}",
    Some((0, 4))
);

// grapheme_cluster_break
mat!(
    uni_class_gcb_prepend,
    r"\p{grapheme_cluster_break=prepend}",
    "\u{11D46}",
    Some((0, 4))
);
mat!(
    uni_class_gcb_ri1,
    r"\p{gcb=regional_indicator}",
    "\u{1F1E6}",
    Some((0, 4))
);
mat!(uni_class_gcb_ri2, r"\p{gcb=ri}", "\u{1F1E7}", Some((0, 4)));
mat!(
    uni_class_gcb_ri3,
    r"\p{gcb=regionalindicator}",
    "\u{1F1FF}",
    Some((0, 4))
);
mat!(uni_class_gcb_lvt, r"\p{gcb=lvt}", "\u{C989}", Some((0, 3)));
mat!(uni_class_gcb_zwj, r"\p{gcb=zwj}", "\u{200D}", Some((0, 3)));

// word_break
mat!(uni_class_wb1, r"\p{word_break=Hebrew_Letter}", "\u{FB46}", Some((0, 3)));
mat!(uni_class_wb2, r"\p{wb=hebrewletter}", "\u{FB46}", Some((0, 3)));
mat!(uni_class_wb3, r"\p{wb=ExtendNumLet}", "\u{FF3F}", Some((0, 3)));
mat!(uni_class_wb4, r"\p{wb=WSegSpace}", "\u{3000}", Some((0, 3)));
mat!(uni_class_wb5, r"\p{wb=numeric}", "\u{1E950}", Some((0, 4)));

// sentence_break
mat!(uni_class_sb1, r"\p{sentence_break=Lower}", "\u{0469}", Some((0, 2)));
mat!(uni_class_sb2, r"\p{sb=lower}", "\u{0469}", Some((0, 2)));
mat!(uni_class_sb3, r"\p{sb=Close}", "\u{FF60}", Some((0, 3)));
mat!(uni_class_sb4, r"\p{sb=Close}", "\u{1F677}", Some((0, 4)));
mat!(uni_class_sb5, r"\p{sb=SContinue}", "\u{FF64}", Some((0, 3)));
<commit_msg>tests: add Unicode tests for 'Vithkuqi'<commit_after>mat!(uni_literal, r"☃", "☃", Some((0, 3)));
mat!(uni_literal_plus, r"☃+", "☃", Some((0, 3)));
mat!(uni_literal_casei_plus, r"(?i)☃+", "☃", Some((0, 3)));
mat!(uni_class_plus, r"[☃Ⅰ]+", "☃", Some((0, 3)));
mat!(uni_one, r"\pN", "Ⅰ", Some((0, 3)));
mat!(uni_mixed, r"\pN+", "Ⅰ1Ⅱ2", Some((0, 8)));
mat!(uni_not, r"\PN+", "abⅠ", Some((0, 2)));
mat!(uni_not_class, r"[\PN]+", "abⅠ", Some((0, 2)));
mat!(uni_not_class_neg, r"[^\PN]+", "abⅠ", Some((2, 5)));
mat!(uni_case, r"(?i)Δ", "δ", Some((0, 2)));
mat!(uni_case_upper, r"\p{Lu}+", "ΛΘΓΔα", Some((0, 8)));
mat!(uni_case_upper_nocase_flag, r"(?i)\p{Lu}+", "ΛΘΓΔα", Some((0, 10)));
mat!(uni_case_upper_nocase, r"\p{L}+", "ΛΘΓΔα", Some((0, 10)));
mat!(uni_case_lower, r"\p{Ll}+", "ΛΘΓΔα", Some((8, 10)));

// Test the Unicode friendliness of Perl character classes.
mat!(uni_perl_w, r"\w+", "dδd", Some((0, 4)));
mat!(uni_perl_w_not, r"\w+", "⥡", None);
mat!(uni_perl_w_neg, r"\W+", "⥡", Some((0, 3)));
mat!(uni_perl_d, r"\d+", "1२३9", Some((0, 8)));
mat!(uni_perl_d_not, r"\d+", "Ⅱ", None);
mat!(uni_perl_d_neg, r"\D+", "Ⅱ", Some((0, 3)));
mat!(uni_perl_s, r"\s+", " ", Some((0, 3)));
mat!(uni_perl_s_not, r"\s+", "☃", None);
mat!(uni_perl_s_neg, r"\S+", "☃", Some((0, 3)));

// And do the same for word boundaries.
mat!(uni_boundary_none, r"\d\b", "6δ", None);
mat!(uni_boundary_ogham, r"\d\b", "6 ", Some((0, 1)));
mat!(uni_not_boundary_none, r"\d\B", "6δ", Some((0, 1)));
mat!(uni_not_boundary_ogham, r"\d\B", "6 ", None);

// Test general categories.
//
// We should test more, but there's a lot. Write a script to generate more of
// these tests.
mat!(uni_class_gencat_cased_letter, r"\p{Cased_Letter}", "Ａ", Some((0, 3)));
mat!(
    uni_class_gencat_close_punctuation,
    r"\p{Close_Punctuation}",
    "❯",
    Some((0, 3))
);
mat!(
    uni_class_gencat_connector_punctuation,
    r"\p{Connector_Punctuation}",
    "⁀",
    Some((0, 3))
);
mat!(uni_class_gencat_control, r"\p{Control}", "\u{9f}", Some((0, 2)));
mat!(
    uni_class_gencat_currency_symbol,
    r"\p{Currency_Symbol}",
    "￡",
    Some((0, 3))
);
mat!(
    uni_class_gencat_dash_punctuation,
    r"\p{Dash_Punctuation}",
    "〰",
    Some((0, 3))
);
mat!(uni_class_gencat_decimal_numer, r"\p{Decimal_Number}", "𑓙", Some((0, 4)));
mat!(
    uni_class_gencat_enclosing_mark,
    r"\p{Enclosing_Mark}",
    "\u{A672}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_final_punctuation,
    r"\p{Final_Punctuation}",
    "⸡",
    Some((0, 3))
);
mat!(uni_class_gencat_format, r"\p{Format}", "\u{E007F}", Some((0, 4)));
// See: https://github.com/rust-lang/regex/issues/719
mat!(uni_class_gencat_format_abbrev1, r"\p{cf}", "\u{E007F}", Some((0, 4)));
mat!(uni_class_gencat_format_abbrev2, r"\p{gc=cf}", "\u{E007F}", Some((0, 4)));
mat!(
    uni_class_gencat_initial_punctuation,
    r"\p{Initial_Punctuation}",
    "⸜",
    Some((0, 3))
);
mat!(uni_class_gencat_letter, r"\p{Letter}", "Έ", Some((0, 2)));
mat!(uni_class_gencat_letter_number, r"\p{Letter_Number}", "ↂ", Some((0, 3)));
mat!(
    uni_class_gencat_line_separator,
    r"\p{Line_Separator}",
    "\u{2028}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_lowercase_letter,
    r"\p{Lowercase_Letter}",
    "ϛ",
    Some((0, 2))
);
mat!(uni_class_gencat_mark, r"\p{Mark}", "\u{E01EF}", Some((0, 4)));
mat!(uni_class_gencat_math, r"\p{Math}", "⋿", Some((0, 3)));
mat!(
    uni_class_gencat_modifier_letter,
    r"\p{Modifier_Letter}",
    "𖭃",
    Some((0, 4))
);
mat!(
    uni_class_gencat_modifier_symbol,
    r"\p{Modifier_Symbol}",
    "🏿",
    Some((0, 4))
);
mat!(
    uni_class_gencat_nonspacing_mark,
    r"\p{Nonspacing_Mark}",
    "\u{1E94A}",
    Some((0, 4))
);
mat!(uni_class_gencat_number, r"\p{Number}", "⓿", Some((0, 3)));
mat!(
    uni_class_gencat_open_punctuation,
    r"\p{Open_Punctuation}",
    "｟",
    Some((0, 3))
);
mat!(uni_class_gencat_other, r"\p{Other}", "\u{bc9}", Some((0, 3)));
mat!(uni_class_gencat_other_letter, r"\p{Other_Letter}", "ꓷ", Some((0, 3)));
mat!(uni_class_gencat_other_number, r"\p{Other_Number}", "㉏", Some((0, 3)));
mat!(
    uni_class_gencat_other_punctuation,
    r"\p{Other_Punctuation}",
    "𞥞",
    Some((0, 4))
);
mat!(uni_class_gencat_other_symbol, r"\p{Other_Symbol}", "⅌", Some((0, 3)));
mat!(
    uni_class_gencat_paragraph_separator,
    r"\p{Paragraph_Separator}",
    "\u{2029}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_private_use,
    r"\p{Private_Use}",
    "\u{10FFFD}",
    Some((0, 4))
);
mat!(uni_class_gencat_punctuation, r"\p{Punctuation}", "𑁍", Some((0, 4)));
mat!(uni_class_gencat_separator, r"\p{Separator}", "\u{3000}", Some((0, 3)));
mat!(
    uni_class_gencat_space_separator,
    r"\p{Space_Separator}",
    "\u{205F}",
    Some((0, 3))
);
mat!(
    uni_class_gencat_spacing_mark,
    r"\p{Spacing_Mark}",
    "\u{16F7E}",
    Some((0, 4))
);
mat!(uni_class_gencat_symbol, r"\p{Symbol}", "⯈", Some((0, 3)));
mat!(
    uni_class_gencat_titlecase_letter,
    r"\p{Titlecase_Letter}",
    "ῼ",
    Some((0, 3))
);
mat!(
    uni_class_gencat_unassigned,
    r"\p{Unassigned}",
    "\u{10FFFF}",
    Some((0, 4))
);
mat!(
    uni_class_gencat_uppercase_letter,
    r"\p{Uppercase_Letter}",
    "Ꝋ",
    Some((0, 3))
);

// Test a smattering of properties.
mat!(uni_class_prop_emoji1, r"\p{Emoji}", "\u{23E9}", Some((0, 3)));
mat!(uni_class_prop_emoji2, r"\p{emoji}", "\u{1F21A}", Some((0, 4)));
mat!(
    uni_class_prop_picto1,
    r"\p{extendedpictographic}",
    "\u{1FA6E}",
    Some((0, 4))
);
mat!(
    uni_class_prop_picto2,
    r"\p{extendedpictographic}",
    "\u{1FFFD}",
    Some((0, 4))
);

// grapheme_cluster_break
mat!(
    uni_class_gcb_prepend,
    r"\p{grapheme_cluster_break=prepend}",
    "\u{11D46}",
    Some((0, 4))
);
mat!(
    uni_class_gcb_ri1,
    r"\p{gcb=regional_indicator}",
    "\u{1F1E6}",
    Some((0, 4))
);
mat!(uni_class_gcb_ri2, r"\p{gcb=ri}", "\u{1F1E7}", Some((0, 4)));
mat!(
    uni_class_gcb_ri3,
    r"\p{gcb=regionalindicator}",
    "\u{1F1FF}",
    Some((0, 4))
);
mat!(uni_class_gcb_lvt, r"\p{gcb=lvt}", "\u{C989}", Some((0, 3)));
mat!(uni_class_gcb_zwj, r"\p{gcb=zwj}", "\u{200D}", Some((0, 3)));

// word_break
mat!(uni_class_wb1, r"\p{word_break=Hebrew_Letter}", "\u{FB46}", Some((0, 3)));
mat!(uni_class_wb2, r"\p{wb=hebrewletter}", "\u{FB46}", Some((0, 3)));
mat!(uni_class_wb3, r"\p{wb=ExtendNumLet}", "\u{FF3F}", Some((0, 3)));
mat!(uni_class_wb4, r"\p{wb=WSegSpace}", "\u{3000}", Some((0, 3)));
mat!(uni_class_wb5, r"\p{wb=numeric}", "\u{1E950}", Some((0, 4)));

// sentence_break
mat!(uni_class_sb1, r"\p{sentence_break=Lower}", "\u{0469}", Some((0, 2)));
mat!(uni_class_sb2, r"\p{sb=lower}", "\u{0469}", Some((0, 2)));
mat!(uni_class_sb3, r"\p{sb=Close}", "\u{FF60}", Some((0, 3)));
mat!(uni_class_sb4, r"\p{sb=Close}", "\u{1F677}", Some((0, 4)));
mat!(uni_class_sb5, r"\p{sb=SContinue}", "\u{FF64}", Some((0, 3)));

// Test 'Vithkuqi' support, which was added in Unicode 14.
// See: https://github.com/rust-lang/regex/issues/877
mat!(
    uni_vithkuqi_literal_upper,
    r"(?i)^\u{10570}$",
    "\u{10570}",
    Some((0, 4))
);
mat!(
    uni_vithkuqi_literal_lower,
    r"(?i)^\u{10570}$",
    "\u{10597}",
    Some((0, 4))
);
mat!(uni_vithkuqi_word_upper, r"^\w$", "\u{10570}", Some((0, 4)));
mat!(uni_vithkuqi_word_lower, r"^\w$", "\u{10597}", Some((0, 4)));
<|endoftext|>


<commit_before>//! Tests for reverse-string
//!
//! Generated by [script][script] using [canonical data][canonical-data]
//!
//! [script]: https://github.com/exercism/rust/blob/master/bin/init_exercise.py
//! [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/reverse-string/canonical_data.json

extern crate reverse_string;
use reverse_string::*;

/// Process a single test case for the property `reverse`
fn process_reverse_case(input: &str, expected: &str) {
    assert_eq!(
        &reverse(input),
        expected
    )
}

#[test]
/// empty string
fn test_empty_string() {
    process_reverse_case("", "");
}

#[test]
#[ignore]
/// a word
fn test_a_word() {
    process_reverse_case("robot", "tobor");
}

#[test]
#[ignore]
/// a capitalized word
fn test_a_capitalized_word() {
    process_reverse_case("Ramen", "nemaR");
}

#[test]
#[ignore]
/// a sentence with punctuation
fn test_a_sentence_with_punctuation() {
    process_reverse_case("I'm hungry!", "!yrgnuh m'I");
}

#[test]
#[ignore]
/// a palindrome
fn test_a_palindrome() {
    process_reverse_case("racecar", "racecar");
}

#[test]
#[ignore]
/// wide characters
fn test_wide_characters() {
    process_reverse_case("子猫", "猫子");
}

#[test]
#[ignore]
#[cfg(feature="graphemes")]
/// grapheme clusters
fn test_grapheme_clusters() {
    process_reverse_case("uüu", "uüu");
}
<commit_msg>Fix consistency of reverse string feature flag<commit_after>//! Tests for reverse-string
//!
//! Generated by [script][script] using [canonical data][canonical-data]
//!
//! [script]: https://github.com/exercism/rust/blob/master/bin/init_exercise.py
//! [canonical-data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/reverse-string/canonical_data.json

extern crate reverse_string;
use reverse_string::*;

/// Process a single test case for the property `reverse`
fn process_reverse_case(input: &str, expected: &str) {
    assert_eq!(
        &reverse(input),
        expected
    )
}

#[test]
/// empty string
fn test_empty_string() {
    process_reverse_case("", "");
}

#[test]
#[ignore]
/// a word
fn test_a_word() {
    process_reverse_case("robot", "tobor");
}

#[test]
#[ignore]
/// a capitalized word
fn test_a_capitalized_word() {
    process_reverse_case("Ramen", "nemaR");
}

#[test]
#[ignore]
/// a sentence with punctuation
fn test_a_sentence_with_punctuation() {
    process_reverse_case("I'm hungry!", "!yrgnuh m'I");
}

#[test]
#[ignore]
/// a palindrome
fn test_a_palindrome() {
    process_reverse_case("racecar", "racecar");
}

#[test]
#[ignore]
/// wide characters
fn test_wide_characters() {
    process_reverse_case("子猫", "猫子");
}

#[test]
#[ignore]
#[cfg(feature="grapheme")]
/// grapheme clusters
fn test_grapheme_clusters() {
    process_reverse_case("uüu", "uüu");
}
<|endoftext|>


<commit_before>use color::PuyoColor;
use kumipuyo::Kumipuyo;
use rand::{thread_rng, Rng};
use std::vec::Vec;

pub struct KumipuyoSeq{
    seq: Vec<Kumipuyo>,
}

impl KumipuyoSeq {
    pub fn new(seq: Vec<Kumipuyo>) -> KumipuyoSeq {
        KumipuyoSeq {
            seq: seq
        }
    }

    pub fn empty() -> KumipuyoSeq {
        KumipuyoSeq::new(Vec::new())
    }

    pub fn generate_random(size: usize) -> KumipuyoSeq {
        let normal_colors = [PuyoColor::RED, PuyoColor::BLUE, PuyoColor::YELLOW, PuyoColor::GREEN];

        let mut rng = thread_rng();
        let mut vs = Vec::new();
        for _ in 0 .. size {
            let axis = rng.choose(&normal_colors).unwrap();
            let child = rng.choose(&normal_colors).unwrap();
            vs.push(Kumipuyo::new(*axis, *child))
        }

        KumipuyoSeq::new(vs)
    }

    pub fn generate_ac_puyo2() -> KumipuyoSeq {
        let mut vs: Vec<PuyoColor> = Vec::new();
        for c in &[PuyoColor::RED, PuyoColor::BLUE, PuyoColor::YELLOW, PuyoColor::GREEN] {
            for _ in 0 .. 64 {
                vs.push(*c)
            }
        }

        let mut rng = thread_rng();
        rng.shuffle(&mut vs[0..64 * 3]);
        rng.shuffle(&mut vs[6..64 * 4]);

        let mut ks: Vec<Kumipuyo> = Vec::new();
        for i in 0 .. 128 {
            let axis = vs[2 * i];
            let child = vs[2 * i + 1];
            ks.push(Kumipuyo::new(axis, child));
        }

        KumipuyoSeq::new(ks)
    }

    pub fn len(&self) -> usize {
        self.seq.len()
    }

    pub fn as_slice(&self) -> &[Kumipuyo] {
        self.seq.as_slice()
    }
}

#[cfg(test)]
mod tests {
    use super::KumipuyoSeq;
    use color::{Color, PuyoColor};

    #[test]
    fn test_generate_random() {
        let seq = KumipuyoSeq::generate_random(20);

        assert_eq!(seq.len(), 20);
        for c in seq.seq {
            assert!(c.axis().is_normal_color());
            assert!(c.child().is_normal_color());
        }
    }

    #[test]
    fn test_generate_ac_puyo2() {
        let seq = KumipuyoSeq::generate_ac_puyo2();
        assert_eq!(seq.len(), 128);

        for i in 0 .. 128 {
            let ref k = seq.seq[i];

            assert!(k.axis().is_normal_color());
            assert!(k.child().is_normal_color());

            // The first 3 hand does not contain GREEN.
            if i <= 2 {
                assert!(k.axis() != PuyoColor::GREEN);
                assert!(k.child() != PuyoColor::GREEN);
            }
        }
    }
}
<commit_msg>:shirt: stylefix<commit_after>use color::PuyoColor;
use kumipuyo::Kumipuyo;
use rand::{thread_rng, Rng};
use std::vec::Vec;

pub struct KumipuyoSeq {
    seq: Vec<Kumipuyo>,
}

impl KumipuyoSeq {
    pub fn new(seq: Vec<Kumipuyo>) -> KumipuyoSeq {
        KumipuyoSeq {
            seq: seq
        }
    }

    pub fn empty() -> KumipuyoSeq {
        KumipuyoSeq::new(Vec::new())
    }

    pub fn generate_random(size: usize) -> KumipuyoSeq {
        let normal_colors = [PuyoColor::RED, PuyoColor::BLUE, PuyoColor::YELLOW, PuyoColor::GREEN];

        let mut rng = thread_rng();
        let mut vs = Vec::new();
        for _ in 0 .. size {
            let axis = rng.choose(&normal_colors).unwrap();
            let child = rng.choose(&normal_colors).unwrap();
            vs.push(Kumipuyo::new(*axis, *child))
        }

        KumipuyoSeq::new(vs)
    }

    pub fn generate_ac_puyo2() -> KumipuyoSeq {
        let mut vs: Vec<PuyoColor> = Vec::new();
        for c in &[PuyoColor::RED, PuyoColor::BLUE, PuyoColor::YELLOW, PuyoColor::GREEN] {
            for _ in 0 .. 64 {
                vs.push(*c)
            }
        }

        let mut rng = thread_rng();
        rng.shuffle(&mut vs[0..64 * 3]);
        rng.shuffle(&mut vs[6..64 * 4]);

        let mut ks: Vec<Kumipuyo> = Vec::new();
        for i in 0 .. 128 {
            let axis = vs[2 * i];
            let child = vs[2 * i + 1];
            ks.push(Kumipuyo::new(axis, child));
        }

        KumipuyoSeq::new(ks)
    }

    pub fn len(&self) -> usize {
        self.seq.len()
    }

    pub fn as_slice(&self) -> &[Kumipuyo] {
        self.seq.as_slice()
    }
}

#[cfg(test)]
mod tests {
    use super::KumipuyoSeq;
    use color::{Color, PuyoColor};

    #[test]
    fn test_generate_random() {
        let seq = KumipuyoSeq::generate_random(20);

        assert_eq!(seq.len(), 20);
        for c in seq.seq {
            assert!(c.axis().is_normal_color());
            assert!(c.child().is_normal_color());
        }
    }

    #[test]
    fn test_generate_ac_puyo2() {
        let seq = KumipuyoSeq::generate_ac_puyo2();
        assert_eq!(seq.len(), 128);

        for i in 0 .. 128 {
            let ref k = seq.seq[i];

            assert!(k.axis().is_normal_color());
            assert!(k.child().is_normal_color());

            // The first 3 hand does not contain GREEN.
            if i <= 2 {
                assert!(k.axis() != PuyoColor::GREEN);
                assert!(k.child() != PuyoColor::GREEN);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use tidb_query_codegen::AggrFunction;
use tidb_query_datatype::builder::FieldTypeBuilder;
use tidb_query_datatype::{FieldTypeFlag, FieldTypeTp};
use tipb::{Expr, ExprType, FieldType};

use super::*;
use tidb_query_common::Result;
use tidb_query_datatype::codec::data_type::*;
use tidb_query_datatype::expr::EvalContext;
use tidb_query_expr::RpnExpression;

/// The parser for COUNT aggregate function.
pub struct AggrFnDefinitionParserCount;

impl super::AggrDefinitionParser for AggrFnDefinitionParserCount {
    fn check_supported(&self, aggr_def: &Expr) -> Result<()> {
        assert_eq!(aggr_def.get_tp(), ExprType::Count);
        super::util::check_aggr_exp_supported_one_child(aggr_def)
    }

    #[inline]
    fn parse_rpn(
        &self,
        root_expr: Expr,
        exp: RpnExpression,
        _ctx: &mut EvalContext,
        _src_schema: &[FieldType],
        out_schema: &mut Vec<FieldType>,
        out_exp: &mut Vec<RpnExpression>,
    ) -> Result<Box<dyn AggrFunction>> {
        assert_eq!(root_expr.get_tp(), ExprType::Count);

        // COUNT outputs one column.
        out_schema.push(
            FieldTypeBuilder::new()
                .tp(FieldTypeTp::LongLong)
                .flag(FieldTypeFlag::UNSIGNED)
                .build(),
        );

        out_exp.push(exp);

        Ok(Box::new(AggrFnCount))
    }
}

/// The COUNT aggregate function.
#[derive(Debug, AggrFunction)]
#[aggr_function(state = AggrFnStateCount::new())]
pub struct AggrFnCount;

/// The state of the COUNT aggregate function.
#[derive(Debug)]
pub struct AggrFnStateCount {
    count: usize,
}

impl AggrFnStateCount {
    pub fn new() -> Self {
        Self { count: 0 }
    }

    #[inline]
    fn update<'a, TT>(&mut self, _ctx: &mut EvalContext, value: Option<TT>) -> Result<()>
    where
        TT: EvaluableRef<'a>,
    {
        if value.is_some() {
            self.count += 1;
        }
        Ok(())
    }

    #[inline]
    fn update_repeat<'a, TT>(
        &mut self,
        _ctx: &mut EvalContext,
        value: Option<TT>,
        repeat_times: usize,
    ) -> Result<()>
    where
        TT: EvaluableRef<'a>,
    {
        // Will be used for expressions like `COUNT(1)`.
        if value.is_some() {
            self.count += repeat_times;
        }
        Ok(())
    }

    #[inline]
    fn update_vector<'a, TT, CC>(
        &mut self,
        _ctx: &mut EvalContext,
        _phantom_data: Option<TT>,
        physical_values: CC,
        logical_rows: &[usize],
    ) -> Result<()>
    where
        TT: EvaluableRef<'a>,
        CC: ChunkRef<'a, TT>,
    {
        // Will be used for expressions like `COUNT(col)`.
        for physical_index in logical_rows {
            if physical_values.get_option_ref(*physical_index).is_some() {
                self.count += 1;
            }
        }
        Ok(())
    }
}

// Here we manually implement `AggrFunctionStateUpdatePartial` so that `update_repeat` and
// `update_vector` can be faster. Also note that we support all kind of
// `AggrFunctionStateUpdatePartial` for the COUNT aggregate function.

impl<T> super::AggrFunctionStateUpdatePartial<T> for AggrFnStateCount
where
    T: EvaluableRef<'static> + 'static,
    VectorValue: VectorValueExt<T::EvaluableType>,
{
    impl_state_update_partial! { T }
}

impl super::AggrFunctionState for AggrFnStateCount {
    #[inline]
    fn push_result(&self, _ctx: &mut EvalContext, target: &mut [VectorValue]) -> Result<()> {
        assert_eq!(target.len(), 1);
        target[0].push(Some(self.count as Int));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use tidb_query_datatype::EvalType;

    use super::super::AggrFunction;
    use super::*;

    #[test]
    fn test_update() {
        let mut ctx = EvalContext::default();
        let function = AggrFnCount;
        let mut state = function.create_state();

        let mut result = [VectorValue::with_capacity(0, EvalType::Int)];

        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(0)]);

        update!(state, &mut ctx, Option::<&Real>::None).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(0)]);

        update!(state, &mut ctx, Real::new(5.0).ok().as_ref()).unwrap();
        update!(state, &mut ctx, Option::<&Real>::None).unwrap();
        update!(state, &mut ctx, Some(&7i64)).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(2)]);

        update_repeat!(state, &mut ctx, Some(&3i64), 4).unwrap();
        update_repeat!(state, &mut ctx, Option::<&Int>::None, 7).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(6)]);

        let chunked_vec: ChunkedVecSized<Int> = vec![Some(1i64), None, Some(-1i64)].into();
        update_vector!(state, &mut ctx, &chunked_vec, &[1, 2]).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(7)]);
    }
}
<commit_msg>copr: Add unit test for aggr COUNT (#9143)<commit_after>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use tidb_query_codegen::AggrFunction;
use tidb_query_datatype::builder::FieldTypeBuilder;
use tidb_query_datatype::{FieldTypeFlag, FieldTypeTp};
use tipb::{Expr, ExprType, FieldType};

use super::*;
use tidb_query_common::Result;
use tidb_query_datatype::codec::data_type::*;
use tidb_query_datatype::expr::EvalContext;
use tidb_query_expr::RpnExpression;

/// The parser for COUNT aggregate function.
pub struct AggrFnDefinitionParserCount;

impl super::AggrDefinitionParser for AggrFnDefinitionParserCount {
    fn check_supported(&self, aggr_def: &Expr) -> Result<()> {
        assert_eq!(aggr_def.get_tp(), ExprType::Count);
        super::util::check_aggr_exp_supported_one_child(aggr_def)
    }

    #[inline]
    fn parse_rpn(
        &self,
        root_expr: Expr,
        exp: RpnExpression,
        _ctx: &mut EvalContext,
        _src_schema: &[FieldType],
        out_schema: &mut Vec<FieldType>,
        out_exp: &mut Vec<RpnExpression>,
    ) -> Result<Box<dyn AggrFunction>> {
        assert_eq!(root_expr.get_tp(), ExprType::Count);

        // COUNT outputs one column.
        out_schema.push(
            FieldTypeBuilder::new()
                .tp(FieldTypeTp::LongLong)
                .flag(FieldTypeFlag::UNSIGNED)
                .build(),
        );

        out_exp.push(exp);

        Ok(Box::new(AggrFnCount))
    }
}

/// The COUNT aggregate function.
#[derive(Debug, AggrFunction)]
#[aggr_function(state = AggrFnStateCount::new())]
pub struct AggrFnCount;

/// The state of the COUNT aggregate function.
#[derive(Debug)]
pub struct AggrFnStateCount {
    count: usize,
}

impl AggrFnStateCount {
    pub fn new() -> Self {
        Self { count: 0 }
    }

    #[inline]
    fn update<'a, TT>(&mut self, _ctx: &mut EvalContext, value: Option<TT>) -> Result<()>
    where
        TT: EvaluableRef<'a>,
    {
        if value.is_some() {
            self.count += 1;
        }
        Ok(())
    }

    #[inline]
    fn update_repeat<'a, TT>(
        &mut self,
        _ctx: &mut EvalContext,
        value: Option<TT>,
        repeat_times: usize,
    ) -> Result<()>
    where
        TT: EvaluableRef<'a>,
    {
        // Will be used for expressions like `COUNT(1)`.
        if value.is_some() {
            self.count += repeat_times;
        }
        Ok(())
    }

    #[inline]
    fn update_vector<'a, TT, CC>(
        &mut self,
        _ctx: &mut EvalContext,
        _phantom_data: Option<TT>,
        physical_values: CC,
        logical_rows: &[usize],
    ) -> Result<()>
    where
        TT: EvaluableRef<'a>,
        CC: ChunkRef<'a, TT>,
    {
        // Will be used for expressions like `COUNT(col)`.
        for physical_index in logical_rows {
            if physical_values.get_option_ref(*physical_index).is_some() {
                self.count += 1;
            }
        }
        Ok(())
    }
}

// Here we manually implement `AggrFunctionStateUpdatePartial` so that `update_repeat` and
// `update_vector` can be faster. Also note that we support all kind of
// `AggrFunctionStateUpdatePartial` for the COUNT aggregate function.

impl<T> super::AggrFunctionStateUpdatePartial<T> for AggrFnStateCount
where
    T: EvaluableRef<'static> + 'static,
    VectorValue: VectorValueExt<T::EvaluableType>,
{
    impl_state_update_partial! { T }
}

impl super::AggrFunctionState for AggrFnStateCount {
    #[inline]
    fn push_result(&self, _ctx: &mut EvalContext, target: &mut [VectorValue]) -> Result<()> {
        assert_eq!(target.len(), 1);
        target[0].push(Some(self.count as Int));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use tidb_query_datatype::EvalType;
    use tikv_util::buffer_vec::BufferVec;

    use super::super::AggrFunction;
    use super::*;

    #[test]
    fn test_update() {
        let mut ctx = EvalContext::default();
        let function = AggrFnCount;
        let mut state = function.create_state();

        let mut result = [VectorValue::with_capacity(0, EvalType::Int)];

        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(0)]);

        update!(state, &mut ctx, Option::<&Real>::None).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(0)]);

        update!(state, &mut ctx, Real::new(5.0).ok().as_ref()).unwrap();
        update!(state, &mut ctx, Option::<&Real>::None).unwrap();
        update!(state, &mut ctx, Some(&7i64)).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(2)]);

        update_repeat!(state, &mut ctx, Some(&3i64), 4).unwrap();
        update_repeat!(state, &mut ctx, Option::<&Int>::None, 7).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(6)]);

        let chunked_vec: ChunkedVecSized<Int> = vec![Some(1i64), None, Some(-1i64)].into();
        update_vector!(state, &mut ctx, &chunked_vec, &[1, 2]).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(7)]);
    }

    #[test]
    fn test_update_enum() {
        let mut ctx = EvalContext::default();
        let function = AggrFnCount;
        let mut state = function.create_state();

        let mut result = [VectorValue::with_capacity(0, EvalType::Int)];

        let mut buf = BufferVec::new();
        buf.push("我好强啊");
        buf.push("我太强啦");
        let buf = Arc::new(buf);

        update!(state, &mut ctx, Some(EnumRef::new(&buf, 1))).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(1)]);
    }

    #[test]
    fn test_update_set() {
        let mut ctx = EvalContext::default();
        let function = AggrFnCount;
        let mut state = function.create_state();

        let mut result = [VectorValue::with_capacity(0, EvalType::Int)];

        let mut buf = BufferVec::new();
        buf.push("我好强啊");
        buf.push("我太强啦");
        let buf = Arc::new(buf);

        update!(state, &mut ctx, Some(SetRef::new(&buf, 0b11))).unwrap();

        result[0].clear();
        state.push_result(&mut ctx, &mut result).unwrap();
        assert_eq!(result[0].to_int_vec(), &[Some(1)]);
    }
}
<|endoftext|>


<commit_before>use std::ops;

/// A owned window around an underlying buffer.
///
/// Normally slices work great for considering sub-portions of a buffer, but
/// unfortunately a slice is a *borrowed* type in Rust which has an associated
/// lifetime. When working with future and async I/O these lifetimes are not
/// always appropriate, and are sometimes difficult to store in tasks. This
/// type strives to fill this gap by providing an "owned slice" around an
/// underlying buffer of bytes.
///
/// A `Window<T>` wraps an underlying buffer, `T`, and has configurable
/// start/end indexes to alter the behavior of the `AsRef<[u8]>` implementation
/// that this type carries.
///
/// This type can be particularly useful when working with the `write_all`
/// combinator in this crate. Data can be sliced via `Window`, consumed by
/// `write_all`, and then earned back once the write operation finishes through
/// the `into_inner` method on this type.
pub struct Window<T> {
    inner: T,
    range: ops::Range<usize>,
}

impl<T: AsRef<[u8]>> Window<T> {
    /// Creates a new window around the buffer `t` defaulting to the entire
    /// slice.
    ///
    /// Further methods can be called on the returned `Window<T>` to alter the
    /// window into the data provided.
    pub fn new(t: T) -> Window<T> {
        Window {
            range: 0..t.as_ref().len(),
            inner: t,
        }
    }

    /// Gets a shared reference to the underlying buffer inside of this
    /// `Window`.
    pub fn get_ref(&self) -> &T {
        &self.inner
    }

    /// Gets a mutable reference to the underlying buffer inside of this
    /// `Window`.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.inner
    }

    /// Consumes this `Window`, returning the underlying buffer.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Returns the starting index of this window into the underlying buffer
    /// `T`.
    pub fn start(&self) -> usize {
        self.range.start
    }

    /// Returns the end index of this window into the underlying buffer
    /// `T`.
    pub fn end(&self) -> usize {
        self.range.end
    }

    /// Changes the starting index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    pub fn set_start(&mut self, start: usize) -> &mut Window<T> {
        assert!(start < self.inner.as_ref().len());
        assert!(start <= self.range.end);
        self.range.start = start;
        self
    }

    /// Changes the end index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `end` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    pub fn set_end(&mut self, end: usize) -> &mut Window<T> {
        assert!(end < self.inner.as_ref().len());
        assert!(self.range.start <= end);
        self.range.end = end;
        self
    }

    // TODO: how about a generic set() method along the lines of:
    //
    //       buffer.set(..3)
    //             .set(0..2)
    //             .set(4..)
    //
    // etc.
}

impl<T: AsRef<[u8]>> AsRef<[u8]> for Window<T> {
    fn as_ref(&self) -> &[u8] {
        &self.inner.as_ref()[self.range.start..self.range.end]
    }
}
<commit_msg>Add AsMut to Window<T><commit_after>use std::ops;

/// A owned window around an underlying buffer.
///
/// Normally slices work great for considering sub-portions of a buffer, but
/// unfortunately a slice is a *borrowed* type in Rust which has an associated
/// lifetime. When working with future and async I/O these lifetimes are not
/// always appropriate, and are sometimes difficult to store in tasks. This
/// type strives to fill this gap by providing an "owned slice" around an
/// underlying buffer of bytes.
///
/// A `Window<T>` wraps an underlying buffer, `T`, and has configurable
/// start/end indexes to alter the behavior of the `AsRef<[u8]>` implementation
/// that this type carries.
///
/// This type can be particularly useful when working with the `write_all`
/// combinator in this crate. Data can be sliced via `Window`, consumed by
/// `write_all`, and then earned back once the write operation finishes through
/// the `into_inner` method on this type.
pub struct Window<T> {
    inner: T,
    range: ops::Range<usize>,
}

impl<T: AsRef<[u8]>> Window<T> {
    /// Creates a new window around the buffer `t` defaulting to the entire
    /// slice.
    ///
    /// Further methods can be called on the returned `Window<T>` to alter the
    /// window into the data provided.
    pub fn new(t: T) -> Window<T> {
        Window {
            range: 0..t.as_ref().len(),
            inner: t,
        }
    }

    /// Gets a shared reference to the underlying buffer inside of this
    /// `Window`.
    pub fn get_ref(&self) -> &T {
        &self.inner
    }

    /// Gets a mutable reference to the underlying buffer inside of this
    /// `Window`.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.inner
    }

    /// Consumes this `Window`, returning the underlying buffer.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Returns the starting index of this window into the underlying buffer
    /// `T`.
    pub fn start(&self) -> usize {
        self.range.start
    }

    /// Returns the end index of this window into the underlying buffer
    /// `T`.
    pub fn end(&self) -> usize {
        self.range.end
    }

    /// Changes the starting index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `start` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    pub fn set_start(&mut self, start: usize) -> &mut Window<T> {
        assert!(start < self.inner.as_ref().len());
        assert!(start <= self.range.end);
        self.range.start = start;
        self
    }

    /// Changes the end index of this window to the index specified.
    ///
    /// Returns the windows back to chain multiple calls to this method.
    ///
    /// # Panics
    ///
    /// This method will panic if `end` is out of bounds for the underlying
    /// slice or if it comes after the `end` configured in this window.
    pub fn set_end(&mut self, end: usize) -> &mut Window<T> {
        assert!(end < self.inner.as_ref().len());
        assert!(self.range.start <= end);
        self.range.end = end;
        self
    }

    // TODO: how about a generic set() method along the lines of:
    //
    //       buffer.set(..3)
    //             .set(0..2)
    //             .set(4..)
    //
    // etc.
}

impl<T: AsRef<[u8]>> AsRef<[u8]> for Window<T> {
    fn as_ref(&self) -> &[u8] {
        &self.inner.as_ref()[self.range.start..self.range.end]
    }
}

impl<T: AsMut<[u8]>> AsMut<[u8]> for Window<T> {
    fn as_mut(&mut self) -> &mut [u8] {
        &mut self.inner.as_mut()[self.range.start..self.range.end]
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub enum ExpectedVersion {
    Number(u64),
    Empty,       //  0 states that the stream should exist but should be empty.
    NoStream,    // -1 states that the stream should not exist at the time of the writing (this write will create it).
    NoConflict,  // -2 states that this write should never conflict with anything and should always succeed.
    Exist,       // -4 to say that the stream should exist with any number of events in it.

    Unexpected(String) // Any string (including -3 OR less than or equal -5).
}

impl From<ExpectedVersion> for String {
    fn from(version: ExpectedVersion) -> String {
        match version {
            ExpectedVersion::Number(n) => n.to_string(),
            ExpectedVersion::Empty => "0".to_string(),
            ExpectedVersion::NoStream => "-1".to_string(),
            ExpectedVersion::NoConflict => "-2".to_string(),
            ExpectedVersion::Exist => "-4".to_string(),
            ExpectedVersion::Unexpected(s) => s,
        }
    }
}

impl From<String> for ExpectedVersion {
    fn from(string: String) -> ExpectedVersion {
        match string.as_ref() {
            "-4" => ExpectedVersion::Exist,
            "-2" => ExpectedVersion::NoConflict,
            "-1" => ExpectedVersion::NoStream,
            "0" => ExpectedVersion::Empty,
            _ => ExpectedVersion::parse_number_or_unexpected(string)
        }
    }
}

impl ExpectedVersion {
    fn parse_number_or_unexpected(string: String) -> ExpectedVersion {
        match string.parse::<u64>() {
            Ok(n) =>  ExpectedVersion::Number(n),
            Err(_) => ExpectedVersion::Unexpected(string)
        }
    }
}
<commit_msg>Do refactoring<commit_after>#[derive(Debug)]
pub enum ExpectedVersion {
    Number(u64),
    Empty,       //  0 states that the stream should exist but should be empty.
    NoStream,    // -1 states that the stream should not exist at the time of the writing (this write will create it).
    Any,         // -2 states that this write should never conflict with anything and should always succeed.
    Exist,       // -4 to say that the stream should exist with any number of events in it.

    Unexpected(String) // Any string (including -3 OR less than or equal -5).
}

impl From<ExpectedVersion> for String {
    fn from(version: ExpectedVersion) -> String {
        match version {
            ExpectedVersion::Number(n) => n.to_string(),
            ExpectedVersion::Empty => "0".to_string(),
            ExpectedVersion::NoStream => "-1".to_string(),
            ExpectedVersion::Any => "-2".to_string(),
            ExpectedVersion::Exist => "-4".to_string(),
            ExpectedVersion::Unexpected(s) => s,
        }
    }
}

impl From<String> for ExpectedVersion {
    fn from(string: String) -> ExpectedVersion {
        match string.as_ref() {
            "-4" => ExpectedVersion::Exist,
            "-2" => ExpectedVersion::Any,
            "-1" => ExpectedVersion::NoStream,
            "0" => ExpectedVersion::Empty,
            _ => ExpectedVersion::parse_number_or_unexpected(string)
        }
    }
}

impl ExpectedVersion {
    fn parse_number_or_unexpected(string: String) -> ExpectedVersion {
        match string.parse::<u64>() {
            Ok(n) =>  ExpectedVersion::Number(n),
            Err(_) => ExpectedVersion::Unexpected(string)
        }
    }
}
<|endoftext|>


<commit_before>use handlebars::Handlebars;
use serde_json::json;

#[test]
fn test_partial_with_blocks() {
    let hbs = Handlebars::new();

    let data = json!({
        "a": [
            {"b": 1},
            {"b": 2},
        ],
    });

    let template = "{{#*inline \"test\"}}{{b}};{{/inline}}{{#each a as |z|}}{{> test z}}{{/each}}";
    assert_eq!(hbs.render_template(template, &data).unwrap(), "1;2;");
}

#[test]
fn test_root_with_blocks() {
    let hbs = Handlebars::new();

    let data = json!({
        "a": [
            {"b": 1},
            {"b": 2},
        ],
        "b": 3,
    });

    let template =
        "{{#*inline \"test\"}}{{b}}:{{@root.b}};{{/inline}}{{#each a}}{{> test}}{{/each}}";
    assert_eq!(hbs.render_template(template, &data).unwrap(), "1:3;2:3;");
}

#[test]
fn test_singular_and_pair_block_params() {
    let hbs = Handlebars::new();

    let data = json!([
        {"value": 11},
        {"value": 22},
    ]);

    let template =
        "{{#each this as |b index|}}{{b.value}}{{#each this as |value key|}}:{{key}},{{/each}}{{/each}}";
    assert_eq!(hbs.render_template(template, &data).unwrap(), "11:value,22:value,");
}
<commit_msg>(test) added failing case for #275<commit_after>use handlebars::Handlebars;
use serde_json::json;

#[test]
fn test_partial_with_blocks() {
    let hbs = Handlebars::new();

    let data = json!({
        "a": [
            {"b": 1},
            {"b": 2},
        ],
    });

    let template = "{{#*inline \"test\"}}{{b}};{{/inline}}{{#each a as |z|}}{{> test z}}{{/each}}";
    assert_eq!(hbs.render_template(template, &data).unwrap(), "1;2;");
}

#[test]
fn test_root_with_blocks() {
    let hbs = Handlebars::new();

    let data = json!({
        "a": [
            {"b": 1},
            {"b": 2},
        ],
        "b": 3,
    });

    let template =
        "{{#*inline \"test\"}}{{b}}:{{@root.b}};{{/inline}}{{#each a}}{{> test}}{{/each}}";
    assert_eq!(hbs.render_template(template, &data).unwrap(), "1:3;2:3;");
}

#[test]
fn test_singular_and_pair_block_params() {
    let hbs = Handlebars::new();

    let data = json!([
        {"value": 11},
        {"value": 22},
    ]);

    let template =
        "{{#each this as |b index|}}{{b.value}}{{#each this as |value key|}}:{{key}},{{/each}}{{/each}}";
    assert_eq!(
        hbs.render_template(template, &data).unwrap(),
        "11:value,22:value,"
    );
}

#[test]
fn test_nested_each() {
    let hbs = Handlebars::new();

    let data = json!({
        "classes": [
            {
                "methods": [
                    {"id": 1},
                    {"id": 2}
                ]
            },
            {
                "methods": [
                    {"id": 3},
                    {"id": 4}
                ]
            },
        ],
    });

    let template = "{{#each classes as |class|}}{{#each class.methods as |method|}}{{method.id}}{{/each}}{{/each}}";
    assert_eq!(hbs.render_template(template, &data).unwrap(), "1;2;3;4;");
}
<|endoftext|>


<commit_before>/// Code generator for the `select!` macro.

/// TODO
#[macro_export]
#[doc(hidden)]
macro_rules! __crossbeam_channel_codegen {
    (@declare
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt, $($tail:tt)*)
        $recv:tt
        $send:tt
        $default:tt
    ) => {
        {
            #[allow(unused_imports)]
            use $crate::internal::select::RecvArgument;
            #[allow(unused_imports)]
            use $crate::internal::channel::Receiver;

            // TODO: document that we can't expect a mut iterator here because of Clone
            match &mut (&$rs).__as_recv_argument() {
                $var => {
                    __crossbeam_channel_codegen!(
                        @declare
                        ($($tail)*)
                        $recv
                        $send
                        $default
                    )
                }
            }
        }
    };
    (@declare
        (($i:tt $var:ident) send($ss:expr, $m:pat, $s:pat) => $body:tt, $($tail:tt)*)
        $recv:tt
        $send:tt
        $default:tt
    ) => {
        {
            #[allow(unused_imports)]
            use $crate::internal::select::SendArgument;
            #[allow(unused_imports)]
            use $crate::internal::channel::Sender;

            match &mut (&$ss).__as_send_argument() {
                $var => {
                    __crossbeam_channel_codegen!(
                        @declare
                        ($($tail)*)
                        $recv
                        $send
                        $default
                    )
                }
            }
        }
    };
    (@declare
        ()
        $recv:tt
        $send:tt
        $default:tt
    ) => {
        __crossbeam_channel_codegen!(@mainloop $recv $send $default)
    };

    (@mainloop $recv:tt $send:tt $default:tt) => {{
        use std::time::Instant;

        use $crate::internal::select::CaseId;
        use $crate::internal::select::Token;
        use $crate::internal::context;
        use $crate::internal::utils::{Backoff, shuffle};

        #[allow(unused_imports)]
        use $crate::internal::select::Select;

        let deadline: Option<Instant>;
        let default_index: usize;
        __crossbeam_channel_codegen!(@default deadline default_index $default);

        let mut cases;
        __crossbeam_channel_codegen!(@container cases $recv $send);

        let mut token: Token = unsafe { ::std::mem::zeroed() };
        let mut index: usize = !0;
        let mut selected: usize = 0;

        shuffle(&mut cases);
        loop {
            // TODO: Tune backoff for zero flavor performance (too much yielding is bad)
            let backoff = &mut Backoff::new();
            loop {
                for &(sel, i, addr) in &cases {
                    if sel.try(&mut token, backoff) {
                        index = i;
                        selected = addr;
                        break;
                    }
                }

                if index != !0 {
                    break;
                }

                // TODO: break here if we have only zero-capacity channels
                break;//////////////////

                if !backoff.step() {
                    break;
                }
            }

            if index != !0 {
                break;
            }

            if default_index != !0 && deadline.is_none() {
                index = default_index;
                selected = 0;
                break;
            }

            context::current_reset();

            // TODO: do we need a try_or_register() call here?

            for case in &cases {
                let case_id = CaseId::new(case as *const _ as usize);
                let &(sel, _, _) = case;
                if !sel.promise(&mut token, case_id) {
                    context::current_try_abort();
                    break;
                }
                if context::current_selected() != CaseId::none() {
                    break;
                }
            }

            // if context::current_selected() == CaseId::none() {
            //     for &(sel, _, _) in &cases {
            //         if !sel.is_blocked() {
            //             context::current_try_abort();
            //         }
            //     }
            // }

            let timed_out = !context::current_wait_until(deadline);
            let s = context::current_selected();

            for case in &cases {
                let case_id = CaseId::new(case as *const _ as usize);
                let &(sel, _, _) = case;
                sel.revoke(case_id);
            }

            if timed_out {
                index = default_index;
                selected = 0;
                break;
            }

            if s != CaseId::abort() {
                for case in &cases {
                    let case_id = CaseId::new(case as *const _ as usize);
                    let &(sel, i, addr) = case;
                    if case_id == s {
                        if sel.fulfill(&mut token, &mut Backoff::new()) {
                            index = i;
                            selected = addr;
                            break;
                        }
                    }
                }

                if index != !0 {
                    break;
                }
            }

            // TODO: reshuffle cases here?
        }

        // This drop is just to ignore a warning complaining about unused `selected`.
        drop(selected);

        __crossbeam_channel_codegen!(@finish token index selected $recv $send $default)

        // TODO: allocate less memory in unbounded flavor if few elements are sent.
        // TODO: allocate memory lazily in unbounded flavor?

        // TODO: Run `cargo clippy` and make sure there are no warnings in here.
        // TODO: Add a Travis test for clippy
    }};

    (@container
        $cases:ident
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt,)
        ()
    ) => {
        use $crate::internal::smallvec::SmallVec;
        let mut c: SmallVec<[_; 4]> = SmallVec::new();
        while let Some(r) = $var.next() {
            let addr = r as *const Receiver<_> as usize;
            c.push((r, $i, addr));
        }
        $cases = c;
    };
    (@container
        $cases:ident
        (($i:tt $var:ident) send($ss:expr, $m:expr, $s:pat) => $body:tt,)
        ()
    ) => {
        use $crate::internal::smallvec::SmallVec;
        let mut c: SmallVec<[_; 4]> = SmallVec::new();
        while let Some(s) = $var.next() {
            let addr = s as *const Sender<_> as usize;
            c.push((s, $i, addr));
        }
        $cases = c;
    };
    (@container
        $cases:ident
        $recv:tt
        $send:tt
    ) => {
        use $crate::internal::smallvec::SmallVec;
        $cases = SmallVec::<[(&Select, usize, usize); 4]>::new();
        __crossbeam_channel_codegen!(@push $cases $recv $send);
    };

    (@push
        $cases:ident
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt, $($tail:tt)*)
        $send:tt
    ) => {
        while let Some(r) = $var.next() {
            let addr = r as *const Receiver<_> as usize;
            $cases.push((r, $i, addr));
        }
        __crossbeam_channel_codegen!(@push $cases ($($tail)*) $send);
    };
    (@push
        $cases:ident
        ()
        (($i:tt $var:ident) send($ss:expr, $m:expr, $s:pat) => $body:tt, $($tail:tt)*)
    ) => {
        while let Some(s) = $var.next() {
            let addr = s as *const Sender<_> as usize;
            $cases.push((s, $i, addr));
        }
        __crossbeam_channel_codegen!(@push $cases () ($($tail)*));
    };
    (@push
        $cases:ident
        ()
        ()
    ) => {
    };

    (@default
        $deadline:ident
        $default_index:ident
        ()
    ) => {
        $deadline = None;
        $default_index = !0;
    };
    (@default
        $deadline:ident
        $default_index:ident
        (($i:tt $var:ident) default() => $body:tt,)
    ) => {
        $deadline = None;
        $default_index = $i;
    };
    (@default
        $deadline:ident
        $default_index:ident
        (($i:tt $var:ident) default($t:expr) => $body:tt,)
    ) => {
        if let Some(instant) = $crate::internal::select::DefaultArgument::default_argument($t) {
            $deadline = Some(instant);
            $default_index = $i;
        } else {
            $deadline = None;
            $default_index = !0;
        }
    };

    (@finish
        $token:ident
        $index:ident
        $selected:ident
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt, $($tail:tt)*)
        $send:tt
        $default:tt
    ) => {
        if $index == $i {
            unsafe fn bind<'a, T: 'a, I>(_: &I, addr: usize) -> &'a Receiver<T>
            where
                I: Iterator<Item = &'a Receiver<T>>,
            {
                &*(addr as *const Receiver<T>)
            }
            let ($m, $r) = unsafe {
                let r = bind(&$var, $selected);
                let msg = $crate::internal::channel::read(r, &mut $token);
                (msg, r)
            };
            $body
        } else {
            __crossbeam_channel_codegen!(
                @finish
                $token
                $index
                $selected
                ($($tail)*)
                $send
                $default
            )
        }
    };
    (@finish
        $token:ident
        $index:ident
        $selected:ident
        ()
        (($i:tt $var:ident) send($ss:expr, $m:expr, $s:pat) => $body:tt, $($tail:tt)*)
        $default:tt
    ) => {
        if $index == $i {
            let $s = {
                struct Guard<F: FnMut()>(F);
                impl<F: FnMut()> Drop for Guard<F> {
                    fn drop(&mut self) {
                        self.0();
                    }
                }

                unsafe fn bind<'a, T: 'a, I>(_: &I, addr: usize) -> &'a T
                where
                    I: Iterator<Item = &'a T>,
                {
                    &*(addr as *const T)
                }

                #[allow(unused_variables)]
                let s = unsafe { bind(&$var, $selected) };

                // We have to prefix variables with an underscore to get rid of warnings in
                // case `$m` is of type `!`.
                #[allow(unused_variables)]
                let guard = Guard(|| {
                    eprintln!(
                        "a send case triggered a panic while evaluating the message, {}:{}:{}",
                        file!(),
                        line!(),
                        column!(),
                    );
                    ::std::process::abort();
                });

                let _msg = $m;

                #[allow(unreachable_code)]
                {
                    ::std::mem::forget(guard);
                    unsafe { $crate::internal::channel::write(s, &mut $token, _msg); }
                    s
                }
            };
            $body
        } else {
            __crossbeam_channel_codegen!(
                @finish
                $token
                $index
                $selected
                ()
                ($($tail)*)
                $default
            )
        }
    };
    (@finish
        $token:ident
        $index:ident
        $selected:ident
        ()
        ()
        (($i:tt $var:ident) default $args:tt => $body:tt,)
    ) => {
        if $index == $i {
            $body
        } else {
            __crossbeam_channel_codegen!(
                @finish
                $token
                $index
                $selected
                ()
                ()
                ()
            )
        }
    };
    (@finish
        $token:ident
        $index:ident
        $selected:ident
        ()
        ()
        ()
    ) => {
        unreachable!()
    };

    // Catches a bug within this macro (should not happen).
    (@$($tokens:tt)*) => {
        compile_error!(concat!(
            "internal error in crossbeam-channel: ",
            stringify!(@$($tokens)*),
        ))
    };

    // The entry point.
    (($($recv:tt)*) ($($send:tt)*) $default:tt) => {
        __crossbeam_channel_codegen!(
            @declare
            ($($recv)* $($send)*)
            ($($recv)*)
            ($($send)*)
            $default
        )
    }
}
<commit_msg>Remove a warning<commit_after>/// Code generator for the `select!` macro.

/// TODO
#[macro_export]
#[doc(hidden)]
macro_rules! __crossbeam_channel_codegen {
    (@declare
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt, $($tail:tt)*)
        $recv:tt
        $send:tt
        $default:tt
    ) => {
        {
            #[allow(unused_imports)]
            use $crate::internal::select::RecvArgument;
            #[allow(unused_imports)]
            use $crate::internal::channel::Receiver;

            // TODO: document that we can't expect a mut iterator here because of Clone
            match &mut (&$rs).__as_recv_argument() {
                $var => {
                    __crossbeam_channel_codegen!(
                        @declare
                        ($($tail)*)
                        $recv
                        $send
                        $default
                    )
                }
            }
        }
    };
    (@declare
        (($i:tt $var:ident) send($ss:expr, $m:pat, $s:pat) => $body:tt, $($tail:tt)*)
        $recv:tt
        $send:tt
        $default:tt
    ) => {
        {
            #[allow(unused_imports)]
            use $crate::internal::select::SendArgument;
            #[allow(unused_imports)]
            use $crate::internal::channel::Sender;

            match &mut (&$ss).__as_send_argument() {
                $var => {
                    __crossbeam_channel_codegen!(
                        @declare
                        ($($tail)*)
                        $recv
                        $send
                        $default
                    )
                }
            }
        }
    };
    (@declare
        ()
        $recv:tt
        $send:tt
        $default:tt
    ) => {
        __crossbeam_channel_codegen!(@mainloop $recv $send $default)
    };

    (@mainloop $recv:tt $send:tt $default:tt) => {{
        use std::time::Instant;

        use $crate::internal::select::CaseId;
        use $crate::internal::select::Token;
        use $crate::internal::context;
        use $crate::internal::utils::{Backoff, shuffle};

        #[allow(unused_imports)]
        use $crate::internal::select::Select;

        let deadline: Option<Instant>;
        let default_index: usize;
        __crossbeam_channel_codegen!(@default deadline default_index $default);

        let mut cases;
        __crossbeam_channel_codegen!(@container cases $recv $send);

        let mut token: Token = unsafe { ::std::mem::zeroed() };
        let mut index: usize = !0;
        let mut selected: usize = 0;

        shuffle(&mut cases);
        loop {
            // TODO: Tune backoff for zero flavor performance (too much yielding is bad)
            let backoff = &mut Backoff::new();
            loop {
                for &(sel, i, addr) in &cases {
                    if sel.try(&mut token, backoff) {
                        index = i;
                        selected = addr;
                        break;
                    }
                }

                if index != !0 {
                    break;
                }

                // TODO: break here if we have only zero-capacity channels
                // break;//////////////////

                if !backoff.step() {
                    break;
                }
            }

            if index != !0 {
                break;
            }

            if default_index != !0 && deadline.is_none() {
                index = default_index;
                selected = 0;
                break;
            }

            context::current_reset();

            // TODO: do we need a try_or_register() call here?

            for case in &cases {
                let case_id = CaseId::new(case as *const _ as usize);
                let &(sel, _, _) = case;
                if !sel.promise(&mut token, case_id) {
                    context::current_try_abort();
                    break;
                }
                if context::current_selected() != CaseId::none() {
                    break;
                }
            }

            // if context::current_selected() == CaseId::none() {
            //     for &(sel, _, _) in &cases {
            //         if !sel.is_blocked() {
            //             context::current_try_abort();
            //         }
            //     }
            // }

            let timed_out = !context::current_wait_until(deadline);
            let s = context::current_selected();

            for case in &cases {
                let case_id = CaseId::new(case as *const _ as usize);
                let &(sel, _, _) = case;
                sel.revoke(case_id);
            }

            if timed_out {
                index = default_index;
                selected = 0;
                break;
            }

            if s != CaseId::abort() {
                for case in &cases {
                    let case_id = CaseId::new(case as *const _ as usize);
                    let &(sel, i, addr) = case;
                    if case_id == s {
                        if sel.fulfill(&mut token, &mut Backoff::new()) {
                            index = i;
                            selected = addr;
                            break;
                        }
                    }
                }

                if index != !0 {
                    break;
                }
            }

            // TODO: reshuffle cases here?
        }

        // This drop is just to ignore a warning complaining about unused `selected`.
        drop(selected);

        __crossbeam_channel_codegen!(@finish token index selected $recv $send $default)

        // TODO: allocate less memory in unbounded flavor if few elements are sent.
        // TODO: allocate memory lazily in unbounded flavor?

        // TODO: Run `cargo clippy` and make sure there are no warnings in here.
        // TODO: Add a Travis test for clippy
    }};

    (@container
        $cases:ident
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt,)
        ()
    ) => {
        use $crate::internal::smallvec::SmallVec;
        let mut c: SmallVec<[_; 4]> = SmallVec::new();
        while let Some(r) = $var.next() {
            let addr = r as *const Receiver<_> as usize;
            c.push((r, $i, addr));
        }
        $cases = c;
    };
    (@container
        $cases:ident
        (($i:tt $var:ident) send($ss:expr, $m:expr, $s:pat) => $body:tt,)
        ()
    ) => {
        use $crate::internal::smallvec::SmallVec;
        let mut c: SmallVec<[_; 4]> = SmallVec::new();
        while let Some(s) = $var.next() {
            let addr = s as *const Sender<_> as usize;
            c.push((s, $i, addr));
        }
        $cases = c;
    };
    (@container
        $cases:ident
        $recv:tt
        $send:tt
    ) => {
        use $crate::internal::smallvec::SmallVec;
        $cases = SmallVec::<[(&Select, usize, usize); 4]>::new();
        __crossbeam_channel_codegen!(@push $cases $recv $send);
    };

    (@push
        $cases:ident
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt, $($tail:tt)*)
        $send:tt
    ) => {
        while let Some(r) = $var.next() {
            let addr = r as *const Receiver<_> as usize;
            $cases.push((r, $i, addr));
        }
        __crossbeam_channel_codegen!(@push $cases ($($tail)*) $send);
    };
    (@push
        $cases:ident
        ()
        (($i:tt $var:ident) send($ss:expr, $m:expr, $s:pat) => $body:tt, $($tail:tt)*)
    ) => {
        while let Some(s) = $var.next() {
            let addr = s as *const Sender<_> as usize;
            $cases.push((s, $i, addr));
        }
        __crossbeam_channel_codegen!(@push $cases () ($($tail)*));
    };
    (@push
        $cases:ident
        ()
        ()
    ) => {
    };

    (@default
        $deadline:ident
        $default_index:ident
        ()
    ) => {
        $deadline = None;
        $default_index = !0;
    };
    (@default
        $deadline:ident
        $default_index:ident
        (($i:tt $var:ident) default() => $body:tt,)
    ) => {
        $deadline = None;
        $default_index = $i;
    };
    (@default
        $deadline:ident
        $default_index:ident
        (($i:tt $var:ident) default($t:expr) => $body:tt,)
    ) => {
        if let Some(instant) = $crate::internal::select::DefaultArgument::default_argument($t) {
            $deadline = Some(instant);
            $default_index = $i;
        } else {
            $deadline = None;
            $default_index = !0;
        }
    };

    (@finish
        $token:ident
        $index:ident
        $selected:ident
        (($i:tt $var:ident) recv($rs:expr, $m:pat, $r:pat) => $body:tt, $($tail:tt)*)
        $send:tt
        $default:tt
    ) => {
        if $index == $i {
            unsafe fn bind<'a, T: 'a, I>(_: &I, addr: usize) -> &'a Receiver<T>
            where
                I: Iterator<Item = &'a Receiver<T>>,
            {
                &*(addr as *const Receiver<T>)
            }
            let ($m, $r) = unsafe {
                let r = bind(&$var, $selected);
                let msg = $crate::internal::channel::read(r, &mut $token);
                (msg, r)
            };
            $body
        } else {
            __crossbeam_channel_codegen!(
                @finish
                $token
                $index
                $selected
                ($($tail)*)
                $send
                $default
            )
        }
    };
    (@finish
        $token:ident
        $index:ident
        $selected:ident
        ()
        (($i:tt $var:ident) send($ss:expr, $m:expr, $s:pat) => $body:tt, $($tail:tt)*)
        $default:tt
    ) => {
        if $index == $i {
            let $s = {
                struct Guard<F: FnMut()>(F);
                impl<F: FnMut()> Drop for Guard<F> {
                    fn drop(&mut self) {
                        self.0();
                    }
                }

                unsafe fn bind<'a, T: 'a, I>(_: &I, addr: usize) -> &'a T
                where
                    I: Iterator<Item = &'a T>,
                {
                    &*(addr as *const T)
                }

                #[allow(unused_variables)]
                let s = unsafe { bind(&$var, $selected) };

                // We have to prefix variables with an underscore to get rid of warnings in
                // case `$m` is of type `!`.
                #[allow(unused_variables)]
                let guard = Guard(|| {
                    eprintln!(
                        "a send case triggered a panic while evaluating the message, {}:{}:{}",
                        file!(),
                        line!(),
                        column!(),
                    );
                    ::std::process::abort();
                });

                let _msg = $m;

                #[allow(unreachable_code)]
                {
                    ::std::mem::forget(guard);
                    unsafe { $crate::internal::channel::write(s, &mut $token, _msg); }
                    s
                }
            };
            $body
        } else {
            __crossbeam_channel_codegen!(
                @finish
                $token
                $index
                $selected
                ()
                ($($tail)*)
                $default
            )
        }
    };
    (@finish
        $token:ident
        $index:ident
        $selected:ident
        ()
        ()
        (($i:tt $var:ident) default $args:tt => $body:tt,)
    ) => {
        if $index == $i {
            $body
        } else {
            __crossbeam_channel_codegen!(
                @finish
                $token
                $index
                $selected
                ()
                ()
                ()
            )
        }
    };
    (@finish
        $token:ident
        $index:ident
        $selected:ident
        ()
        ()
        ()
    ) => {
        unreachable!()
    };

    // Catches a bug within this macro (should not happen).
    (@$($tokens:tt)*) => {
        compile_error!(concat!(
            "internal error in crossbeam-channel: ",
            stringify!(@$($tokens)*),
        ))
    };

    // The entry point.
    (($($recv:tt)*) ($($send:tt)*) $default:tt) => {
        __crossbeam_channel_codegen!(
            @declare
            ($($recv)* $($send)*)
            ($($recv)*)
            ($($send)*)
            $default
        )
    }
}
<|endoftext|>