mod adapter;
mod anchor;
mod assert;
mod builder;
mod consume;
mod empty;
mod fail;
mod into;
mod literal;
#[cfg(feature = "alloc")]
mod rec;

use core::cell::Cell;
use core::cell::RefCell;

pub use self::adapter::Adapter;
pub use self::adapter::DynRefAdapter;
pub use self::adapter::RefAdapter;
pub use self::anchor::AnchorEnd;
pub use self::anchor::AnchorStart;
pub use self::anchor::end;
pub use self::anchor::start;
pub use self::assert::Assert;
pub use self::assert::assert;
pub use self::assert::not;
pub use self::assert::peek;
pub use self::builder::DynamicRegexBuilderHelper;
pub use self::builder::into_regex_builder;
pub use self::consume::Consume;
pub use self::consume::ConsumeAll;
pub use self::consume::consume;
pub use self::consume::consume_all;
pub use self::empty::EmptyRegex;
pub use self::empty::empty;
pub use self::fail::FailRegex;
pub use self::fail::fail;
pub use self::into::RegexIntoHelper;
pub use self::literal::Literal;
pub use self::literal::LiteralTy;
pub use self::literal::literal;

#[cfg(feature = "alloc")]
pub use self::rec::*;

use crate::ctor::Array;
use crate::ctor::PairArray;
use crate::ctor::PairSlice;
use crate::ctor::Slice;
use crate::ctx::Context;
use crate::ctx::Match;
use crate::err::Error;
use crate::neu::EmptyCond;
use crate::neu::Many0;
use crate::neu::Many1;
use crate::neu::Neu;
use crate::neu::Once;
use crate::neu::Opt;
use crate::span::Span;

pub trait Regex<C> {
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error>;

    fn parse(&self, ctx: &mut C) -> bool {
        self.try_parse(ctx).is_ok()
    }
}

impl<C, F> Regex<C> for F
where
    F: Fn(&mut C) -> Result<Span, Error>,
{
    #[inline]
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        (self)(ctx)
    }
}

impl<'a, C> Regex<C> for ()
where
    C: Context<'a>,
{
    #[inline(always)]
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        Ok(Span::new(ctx.offset(), 0))
    }
}

macro_rules! impl_orig_regex {
    ($self:ident, $regex:expr, $type:ty, $orig:ty) => {
        impl<'a, C> Regex<C> for $type
        where
            C: Context<'a, Orig<'a> = &'a $orig>,
        {
            #[inline(always)]
            fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
                let $self = self;

                Regex::try_parse($regex, ctx)
            }
        }
    };
}

macro_rules! impl_forward_regex {
    ($self:ident, $regex:expr, $type:ty) => {
        impl<P, C> Regex<C> for $type
        where
            P: Regex<C>,
        {
            #[inline(always)]
            fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
                let $self = self;

                Regex::try_parse($regex, ctx)
            }
        }
    };
}

#[cfg(feature = "alloc")]
mod alloc_regex_impls {

    use crate::alloc::Arc;
    use crate::alloc::Box;
    use crate::alloc::Rc;
    use crate::alloc::String;
    use crate::alloc::Vec;
    use crate::ctor::Ctor;
    use crate::ctx::Context;
    use crate::err::Error;
    use crate::regex::Regex;
    use crate::regex::literal;
    use crate::span::Span;

    impl_orig_regex!(self_, &literal(self_.as_str()), String, str);

    impl_orig_regex!(self_, &literal(self_.as_str()), &String, str);

    impl_orig_regex!(self_, &literal(self_.as_slice()), Vec<u8>, [u8]);

    impl_orig_regex!(self_, &literal(self_.as_slice()), &Vec<u8>, [u8]);

    impl_forward_regex!(self_, self_.as_ref(), Arc<P>);

    impl_forward_regex!(self_, self_.as_ref(), Rc<P>);

    macro_rules! impl_dyn_regex {
        ($type:ty) => {
            impl<'b, C> Regex<C> for $type {
                fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
                    self.as_ref().try_parse(ctx)
                }
            }
        };
    }

    macro_rules! impl_dyn_ctor {
        ($ctor:ty) => {
            impl<'a, 'b, C, O, H> Regex<C> for $ctor {
                fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
                    self.as_ref().try_parse(ctx)
                }
            }
        };
    }

    impl_dyn_regex!(Box<dyn Regex<C> + 'b>);

    impl_dyn_regex!(Box<dyn Regex<C> + Send + 'b>);

    impl_dyn_regex!(Box<dyn Regex<C> + Send + Sync + 'b>);

    impl_dyn_ctor!(Box<dyn Ctor<'a, C, O, H> + 'b>);

    impl_dyn_ctor!(Box<dyn Ctor<'a, C, O, H> + Send + 'b>);

    impl_dyn_ctor!(Box<dyn Ctor<'a, C, O, H> + Send + Sync + 'b>);

    impl_dyn_regex!(Arc<dyn Regex<C> + 'b>);

    impl_dyn_regex!(Arc<dyn Regex<C> + Send + 'b>);

    impl_dyn_regex!(Arc<dyn Regex<C> + Send + Sync + 'b>);

    impl_dyn_ctor!(Arc<dyn Ctor<'a, C, O, H> + 'b>);

    impl_dyn_ctor!(Arc<dyn Ctor<'a, C, O, H> + Send + 'b>);

    impl_dyn_ctor!(Arc<dyn Ctor<'a, C, O, H> + Send + Sync + 'b>);

    impl_dyn_regex!(Rc<dyn Regex<C> + 'b>);

    impl_dyn_regex!(Rc<dyn Regex<C> + Send + 'b>);

    impl_dyn_ctor!(Rc<dyn Ctor<'a, C, O, H> + 'b>);

    impl_dyn_ctor!(Rc<dyn Ctor<'a, C, O, H> + Send + 'b>);
}

impl_orig_regex!(self_, &literal(*self_), &str, str);

impl_orig_regex!(self_, &literal(*self_), &[u8], [u8]);

impl<'a, const N: usize, C> Regex<C> for &[u8; N]
where
    C: Context<'a, Orig<'a> = &'a [u8]>,
{
    #[inline(always)]
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        let pattern = crate::regex::literal(self.as_slice());
        pattern.try_parse(ctx)
    }
}

impl<'a, const N: usize, C> Regex<C> for [u8; N]
where
    C: Context<'a, Orig<'a> = &'a [u8]>,
{
    #[inline(always)]
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        let pattern = crate::regex::literal(self.as_slice());
        pattern.try_parse(ctx)
    }
}

impl_forward_regex!(self_, self_.as_ref().ok_or(Error::Option)?, Option<P>);

impl_forward_regex!(self_, &*self_.borrow(), RefCell<P>);

#[cfg(feature = "std")]
impl_forward_regex!(
    self_,
    &*self_.lock().map_err(|_| Error::Mutex)?,
    crate::std::Mutex<P>
);

impl<P, C> Regex<C> for Cell<P>
where
    P: Regex<C> + Copy,
{
    fn try_parse(&self, ctx: &mut C) -> Result<Span, Error> {
        self.get().try_parse(ctx)
    }
}

///
/// Match one item.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// #     color_eyre::install()?;
///     let sign = regex::once('+');
///     let num = regex::many1('0'..='9');
///     let mut ctx = CharsCtx::new("+2077");
///
///     assert_eq!(ctx.try_mat(&sign)?, Span::new(0, 1));
///     assert_eq!(ctx.try_mat(&num)?, Span::new(1, 4));
///
///     let mut ctx = CharsCtx::new("2077");
///
///     assert!(ctx.try_mat(&sign).is_err());
///     Ok(())
/// # }
/// ```
pub const fn once<'a, C, U>(unit: U) -> Once<C, U, C::Item, EmptyCond>
where
    C: Context<'a>,
    U: Neu<C::Item>,
{
    Once::new(unit, EmptyCond)
}

///
/// Match zero or one item.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// #     color_eyre::install()?;
///     let sign = regex::opt('+');
///     let num = regex::many1('0'..='9');
///     let mut ctx = CharsCtx::new("+2077");
///
///     assert_eq!(ctx.try_mat(&sign)?, Span::new(0, 1));
///     assert_eq!(ctx.try_mat(&num)?, Span::new(1, 4));
///
///     let mut ctx = CharsCtx::new("2077");
///
///     assert_eq!(ctx.try_mat(&sign)?, Span::new(0, 0));
///     assert_eq!(ctx.try_mat(&num)?, Span::new(0, 4));
///     Ok(())
/// # }
/// ```
pub const fn opt<'a, C, U>(unit: U) -> Opt<C, U, C::Item, EmptyCond>
where
    C: Context<'a>,
    U: Neu<C::Item>,
{
    Opt::new(unit, EmptyCond)
}

///
/// Match at least zero item.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// #     color_eyre::install()?;
///     let num = regex::many0('0'..='9');
///     let mut ctx = CharsCtx::new("2048mb");
///
///     assert_eq!(ctx.try_mat(&num)?, Span::new(0, 4));
///
///     let mut ctx = CharsCtx::new("rust2021");
///
///     assert_eq!(ctx.try_mat(&num)?, Span::new(0, 0));
///     Ok(())
/// # }
/// ```
///
pub const fn many0<'a, C, U>(unit: U) -> Many0<C, U, C::Item, EmptyCond>
where
    C: Context<'a>,
    U: Neu<C::Item>,
{
    Many0::new(unit, EmptyCond)
}

///
/// Match at least one item.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// #     color_eyre::install()?;
///     let num = regex::many1('0'..='9');
///     let mut ctx = CharsCtx::new("2048mb");
///
///     assert_eq!(ctx.try_mat(&num)?, Span::new(0, 4));
///
///     let mut ctx = CharsCtx::new("rust2021");
///
///     assert!(ctx.try_mat(&num).is_err());
///     Ok(())
/// # }
/// ```
pub const fn many1<'a, C, N>(unit: N) -> Many1<C, N, C::Item, EmptyCond>
where
    N: Neu<C::Item>,
    C: Context<'a>,
{
    Many1::new(unit, EmptyCond)
}

///
/// Match the given `Neu` M ..= N times.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// #     color_eyre::install()?;
///     let website = regex::count::<0, { usize::MAX }, _, _>(('a'..'{'));
///     let mut ctx = CharsCtx::new("example.com");
///
///     assert_eq!(ctx.try_mat(&website)?, Span::new(0, 7));
///     assert_eq!(ctx.orig_sub(0, 7)?, "example");
///     Ok(())
/// }
/// ```
///
pub const fn count<'a, const M: usize, const N: usize, C, U>(
    unit: U,
) -> crate::neu::Between<M, N, C, U, EmptyCond>
where
    C: Context<'a>,
    U: Neu<C::Item>,
{
    crate::neu::Between::new(unit, EmptyCond)
}

///
/// Match the given `Neu` M ..= N times.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// #     color_eyre::install()?;
///     let website = regex::count_if::<0, { usize::MAX }, _, _, _>(
///         ('a'..'{').or('.'),
///         |ctx: &CharsCtx, pair: &(usize, char)| {
///             Ok(pair.1 != '.'
///                 || ctx
///                     .orig()?
///                     .get((pair.0 + 1)..)
///                     .map(|v| v.find('.').is_some())
///                     .unwrap_or(false))
///         },
///     );
///     let mut ctx = CharsCtx::new("domain.example.com");
///
///     assert_eq!(ctx.try_mat(&website)?, Span::new(0, 14));
///     assert_eq!(ctx.orig_sub(0, 14)?, "domain.example");
///     Ok(())
/// }
/// ```
///
pub const fn count_if<'a, const M: usize, const N: usize, C, U, F>(
    unit: U,
    cond: F,
) -> crate::neu::Between<M, N, C, U, F>
where
    C: Context<'a> + 'a,
    U: Neu<C::Item>,
    F: crate::neu::NeuCond<'a, C>,
{
    crate::neu::Between::new(unit, cond)
}

/// Matches the **first successful expression** from a dynamic sequence of alternatives.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let ty = neu::ascii_alphabetic().many1();
///     let id = neu::ascii_alphabetic().many1();
///     let var = ty.sep_once("", id);
///     let ptr = ty.sep_once("*", id);
///     let r#ref = ty.sep_once("&", id);
///     let vec = regex::vector([var, ptr, r#ref]);
///     let sp = neu::whitespace().many0();
///
///     assert_eq!(CharsCtx::new("int a").skip_before(sp).ctor(&vec)?, ("int", "a"));
///     assert_eq!(CharsCtx::new("int *a").skip_before(sp).ctor(&vec)?, ("int", "a"));
///     assert_eq!(CharsCtx::new("int &a").skip_before(sp).ctor(&vec)?, ("int", "a"));
/// #   Ok(())
/// # }
/// ```
#[cfg(feature = "alloc")]
pub fn vector<T>(val: impl IntoIterator<Item = T>) -> crate::ctor::Vector<T> {
    crate::ctor::Vector::new(val.into_iter().collect(), false)
}

/// Matches the **first successful expression** from a dynamic sequence of alternatives
/// in longest token match mode.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let ty = neu::ascii_alphabetic().many1();
///     let id = regex::empty();
///     let var = ty.sep_once(" ", id);
///     let ptr = ty.sep_once(" *", id);
///     let r#ref = ty.sep_once(" &", id);
///     let vec = regex::vector_ltm([var, ptr, r#ref]);
///
///     assert_eq!(CharsCtx::new("int &").try_mat(&vec)?, Span::new(0, 5));
///     assert_eq!(CharsCtx::new("int *").try_mat(&vec)?, Span::new(0, 5));
/// #   Ok(())
/// # }
/// ```
#[cfg(feature = "alloc")]
pub fn vector_ltm<T>(val: impl IntoIterator<Item = T>) -> crate::ctor::Vector<T> {
    crate::ctor::Vector::new(val.into_iter().collect(), true)
}

/// Matches the first successful expression from a dynamic sequence while carrying associated data.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
///     pub enum C {
///         Var,
///         Ptr,
///         Ref,
///     }
///
///     let ty = neu::ascii_alphabetic().many1();
///     let id = neu::ascii_alphabetic().many1();
///     let var = ty.sep_once("", id);
///     let ptr = ty.sep_once("*", id);
///     let r#ref = ty.sep_once("&", id);
///     let vec = regex::pair_vector([(var, C::Var), (ptr, C::Ptr), (r#ref, C::Ref)]);
///     let sp = neu::whitespace().many0();
///
///     assert_eq!(
///         CharsCtx::new("int a").skip_before(sp).ctor(&vec)?,
///         (("int", "a"), C::Var)
///     );
///     assert_eq!(
///         CharsCtx::new("int *a").skip_before(sp).ctor(&vec)?,
///         (("int", "a"), C::Ptr)
///     );
///     assert_eq!(
///         CharsCtx::new("int &a").skip_before(sp).ctor(&vec)?,
///         (("int", "a"), C::Ref)
///     );
/// #   Ok(())
/// # }
/// ```
#[cfg(feature = "alloc")]
pub fn pair_vector<T, V: Clone>(
    val: impl IntoIterator<Item = (T, V)>,
) -> crate::ctor::PairVector<T, V> {
    crate::ctor::PairVector::new(val.into_iter().collect(), false)
}

/// Matches the first successful expression from a dynamic sequence while carrying associated data
/// in longest token match mode.
///
/// # Example
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
///     pub enum C {
///         Var,
///         Ptr,
///         Ref,
///     }
///
///     let ty = neu::ascii_alphabetic().many1();
///     let id = regex::empty();
///     let var = ty.sep_once("", id);
///     let ptr = ty.sep_once("*", id);
///     let r#ref = ty.sep_once("&", id);
///     let vec = regex::pair_vector_ltm([(var, C::Var), (ptr, C::Ptr), (r#ref, C::Ref)]);
///     let sp = neu::whitespace().many0();
///
///     assert_eq!(
///         CharsCtx::new("int ").skip_before(sp).ctor(&vec)?,
///         (("int", ""), C::Var)
///     );
///     assert_eq!(
///         CharsCtx::new("int *").skip_before(sp).ctor(&vec)?,
///         (("int", ""), C::Ptr)
///     );
///     assert_eq!(
///         CharsCtx::new("int &").skip_before(sp).ctor(&vec)?,
///         (("int", ""), C::Ref)
///     );
/// #   Ok(())
/// # }
/// ```
#[cfg(feature = "alloc")]
pub fn pair_vector_ltm<T, V: Clone>(
    val: impl IntoIterator<Item = (T, V)>,
) -> crate::ctor::PairVector<T, V> {
    crate::ctor::PairVector::new(val.into_iter().collect(), true)
}

/// Iterate over the array and match the [`regex`](crate::regex::Regex) against the [`Context`].
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let parser = regex::array([b"rust".as_ref(), b"jawa", b"golang"]);
///     let mut ctx = BytesCtx::new(b"rust is so awesome!");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 4));
/// #   Ok(())
/// # }
/// ```
pub const fn array<const N: usize, T>(val: [T; N]) -> Array<N, T> {
    Array::new(val, false)
}

/// Iterate over the array and match the [`regex`](crate::regex::Regex) against the [`Context`]
/// in longest token match mode.
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let parser = regex::array_ltm([b"go".as_ref(), b"golang"]);
///     let mut ctx = BytesCtx::new(b"golang is so awesome!");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 6));
/// #   Ok(())
/// # }
/// ```
pub const fn array_ltm<const N: usize, T>(val: [T; N]) -> Array<N, T> {
    Array::new(val, true)
}

/// Attempts patterns in sequence, returning the first successful match from a **compile-time fixed array**.
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let slice = [b"rust".as_ref(), b"jawa", b"golang"];
///     let parser = regex::slice(&slice);
///     let mut ctx = BytesCtx::new(b"rust is so awesome!");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 4));
/// #   Ok(())
/// # }
/// ```
pub const fn slice<T>(val: &[T]) -> Slice<'_, T> {
    Slice::new(val, false)
}

/// Attempts patterns in sequence, returning the first successful match from a **compile-time fixed array**
/// in longest token match mode.
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     let slice = [b"g".as_ref(), b"go", b"golang"];
///     let parser = regex::slice_ltm(&slice);
///     let mut ctx = BytesCtx::new(b"go is so awesome!");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 2));
/// #   Ok(())
/// # }
/// ```
pub const fn slice_ltm<T>(val: &[T]) -> Slice<'_, T> {
    Slice::new(val, true)
}

/// Iterate over the array and match the regex against the [`Context`].
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     #[derive(Debug, Clone, PartialEq)]
///     enum Lang {
///         Rust,
///         Java,
///         Golang,
///     }
///
///     let parser = regex::pair_array([
///         (b"rust".as_ref(), Lang::Rust),
///         (b"jawa", Lang::Java),
///         (b"golang", Lang::Golang),
///     ]);
///     let mut ctx = BytesCtx::new(b"golang is so awesome!");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 6));
/// #   Ok(())
/// # }
/// ```
pub const fn pair_array<const N: usize, K, V>(val: [(K, V); N]) -> PairArray<N, K, V> {
    PairArray::new(val, false)
}

/// Iterate over the array and match the regex against the [`Context`] in longest token match mode.
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     #[derive(Debug, Clone, PartialEq)]
///     enum Protocol {
///         Http,
///         Https,
///     }
///
///     let parser = regex::pair_array_ltm([
///         (b"http".as_ref(), Protocol::Http),
///         (b"https", Protocol::Https),
///     ]);
///     let mut ctx = BytesCtx::new(b"https://docs.example.dev");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 5));
/// #   Ok(())
/// # }
/// ```
pub const fn pair_array_ltm<const N: usize, K, V>(val: [(K, V); N]) -> PairArray<N, K, V> {
    PairArray::new(val, true)
}

/// Maps patterns to associated values, returning the first successful match with its paired value.
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     #[derive(Debug, Clone, PartialEq)]
///     enum Lang {
///         Rust,
///         Java,
///         Golang,
///     }
///
///     let array = [
///         (b"rust".as_ref(), Lang::Rust),
///         (b"jawa", Lang::Java),
///         (b"golang", Lang::Golang),
///     ];
///     let parser = regex::pair_slice(&array);
///     let mut ctx = BytesCtx::new(b"jawa is so awesome!");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 4));
/// #   Ok(())
/// # }
/// ```
pub const fn pair_slice<K, V>(val: &[(K, V)]) -> PairSlice<'_, K, V> {
    PairSlice::new(val, false)
}

/// Maps patterns to associated values, returning the first successful match with its paired value
/// in longest token match mode.
///
/// # Example
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> Result<(), Box<dyn core::error::Error>> {
///     #[derive(Debug, Clone, PartialEq)]
///     enum Protocol {
///         Http,
///         Https,
///     }
///
///     let array = [
///         (b"http".as_ref(), Protocol::Http),
///         (b"https", Protocol::Https),
///     ];
///     let parser = regex::pair_slice_ltm(&array);
///     let mut ctx = BytesCtx::new(b"https://docs.example.dev");
///
///     assert_eq!(ctx.try_mat(&parser)?, Span::new(0, 5));
/// #   Ok(())
/// # }
/// ```
pub const fn pair_slice_ltm<K, V>(val: &[(K, V)]) -> PairSlice<'_, K, V> {
    PairSlice::new(val, true)
}

pub(crate) fn handler<'a, C, P, T, A>(
    err: Error,
    t2p: A,
) -> impl Fn(&[T], &mut C) -> Result<Span, Error>
where
    P: Regex<C>,
    C: Match<'a>,
    A: Fn(&T) -> &P,
{
    move |slice: &[T], ctx: &mut C| {
        let beg = ctx.offset();
        let mut ret = Err(err);

        for item in slice.iter() {
            let regex = t2p(item);

            if let Ok(span) = ctx.try_mat(regex).inspect_err(|_| {
                ctx.set_offset(beg);
            }) {
                ret = Ok(span);
                break;
            }
        }
        ret
    }
}

pub(crate) fn handler_ltm<'a, C, P, T, A>(
    err: Error,
    t2p: A,
) -> impl Fn(&[T], &mut C) -> Result<Span, Error>
where
    P: Regex<C>,
    C: Match<'a>,
    A: Fn(&T) -> &P,
{
    move |slice: &[T], ctx: &mut C| {
        let beg = ctx.offset();
        let mut longest = None;

        for item in slice.iter() {
            // reset offset for every regex
            ctx.set_offset(beg);

            // match regex
            if let Ok(span) = ctx.try_mat(t2p(item))
                && longest.map(|v: Span| v.len() < span.len()).unwrap_or(true)
            {
                longest = Some(span);
            }
        }
        longest.ok_or(err)
    }
}

pub trait RegexRefAsCtor<C>
where
    Self: Regex<C>,
{
    fn as_ctor(&self) -> RefAdapter<'_, C, Self>;
}

impl<T: ?Sized, C> RegexRefAsCtor<C> for T
where
    Self: Regex<C>,
{
    fn as_ctor(&self) -> RefAdapter<'_, C, Self> {
        RefAdapter::new(self)
    }
}

pub trait RegexRefAsDynRegex<C>
where
    Self: Regex<C>,
{
    fn as_dyn_regex(&self) -> DynRefAdapter<'_, C>;
}

impl<C, T> RegexRefAsDynRegex<C> for T
where
    Self: Regex<C>,
{
    fn as_dyn_regex(&self) -> DynRefAdapter<'_, C> {
        DynRefAdapter::new(self)
    }
}

macro_rules! impl_not_for_regex {
    (@$ty:ident [ ]  [ ]) => {
        impl core::ops::Not for $ty {
            type Output = $crate::regex::Assert<Self>;

            fn not(self) -> Self::Output { $crate::regex::not(self) }
        }
    };
    (@$ty:ident [ ]  [ $($p:ident),+ ]) => {
        impl<$($p),+> core::ops::Not for $ty<$($p),+> {
            type Output = $crate::regex::Assert<Self>;

            fn not(self) -> Self::Output { $crate::regex::not(self) }
        }
    };
    (@$ty:ident [ $($l:lifetime),+ ]  [ $($p:ident),* ]) => {
        impl<$($l),+ , $($p),*> core::ops::Not for $ty<$($l),+ , $($p),*> {
            type Output = $crate::regex::Assert<Self>;

            fn not(self) -> Self::Output { $crate::regex::not(self) }
        }
    };
    ($ty:ident) => {
        impl_not_for_regex! { @$ty [ ] [ ] }
    };
    ($ty:ident < $($l:lifetime),* $(,)? $($p:ident),* >) => {
        impl_not_for_regex! { @$ty [$($l),*] [$($p),*] }
    };
}

pub(crate) use impl_not_for_regex;
