#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::{borrow::Cow, string::String, vec::Vec};
use core::{
convert::Infallible,
fmt::{self, Display},
};
#[cfg(feature = "std")]
use std::{borrow::Cow, error, string::String, vec::Vec};
use generic_array::{ArrayLength, GenericArray};
use typenum::U1;
use crate::{
values::{self, InvalidType},
ConstantTy,
};
macro_rules! count_ident {
($i0:ident) => {1};
($i0:ident, $($I:ident),*) => {1 + count_ident!($($I),*)};
}
macro_rules! count_ident_typenum {
($i0:ident) => {U1};
($i0:ident, $($I:ident),*) => {<U1 as core::ops::Add<count_ident_typenum!($($I),*)>>::Output};
}
macro_rules! ignore_ident {
($id:ident, $($t:tt)*) => {
$($t)*
};
}
pub trait IntoArray<T>: Sized {
type Length: ArrayLength<T>;
fn into_array(self) -> GenericArray<T, Self::Length>;
}
macro_rules! impl_into_array_single_ty {
($i0:ty) => {
impl<'a> IntoArray<values::Constant<'a>> for $i0
{
type Length = U1;
fn into_array(self) -> GenericArray<values::Constant<'a>, Self::Length> {
[values::Constant::from(self)].into()
}
}
};
($i0:ty, $($I:ty),+) => {
impl_into_array_single_ty!($i0);
impl_into_array_single_ty!($($I),+);
};
}
impl_into_array_single_ty!(bool, i64, &'a str, &'a [u8]);
macro_rules! impl_into_array_tuple {
($i0:ident) => {};
($i0:ident, $($I:ident),+) => {
impl_into_array_tuple!($($I),+);
impl<T, $($I),+> IntoArray<T> for ($($I,)+)
where $(T: From<$I>,)+
{
type Length = count_ident_typenum!($($I),+);
fn into_array(self) -> GenericArray<T, Self::Length> {
#[allow(non_snake_case)]
let ($($I,)+) = self;
[$(T::from($I)),+].into()
}
}
impl<T, S> IntoArray<S> for [T; { count_ident!($($I),+) }]
where S: From<T>,
{
type Length = count_ident_typenum!($($I),+);
fn into_array(self) -> GenericArray<S, Self::Length> {
#[allow(non_snake_case)]
let [$($I,)+] = self;
[$(S::from($I)),+].into()
}
}
};
}
impl_into_array_tuple!(dummy, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
pub trait QueryValue {
type Ty<'a>: TryFrom<values::Constant<'a>>;
fn ty() -> ConstantTy;
fn is_match(&self, other: &Self::Ty<'_>) -> bool;
}
impl QueryValue for bool {
type Ty<'a> = bool;
fn ty() -> ConstantTy {
ConstantTy::Bool
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
*self == *other
}
}
#[derive(Debug, Clone, Copy)]
pub struct AnyBool;
impl QueryValue for AnyBool {
type Ty<'a> = bool;
fn ty() -> ConstantTy {
ConstantTy::Bool
}
fn is_match(&self, _other: &Self::Ty<'_>) -> bool {
true
}
}
impl QueryValue for i64 {
type Ty<'a> = i64;
fn ty() -> ConstantTy {
ConstantTy::Num
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
*self == *other
}
}
#[derive(Debug, Clone, Copy)]
pub struct AnyNum;
impl QueryValue for AnyNum {
type Ty<'a> = i64;
fn ty() -> ConstantTy {
ConstantTy::Num
}
fn is_match(&self, _other: &Self::Ty<'_>) -> bool {
true
}
}
impl<'b> QueryValue for &'b str {
type Ty<'a> = &'a str;
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
self == other
}
}
impl QueryValue for String {
type Ty<'a> = &'a str;
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
self == *other
}
}
impl<'b> QueryValue for Cow<'b, str> {
type Ty<'a> = &'a str;
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
self == *other
}
}
impl<'b> QueryValue for &'b [u8] {
type Ty<'a> = &'a [u8];
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
self == other
}
}
impl QueryValue for Vec<u8> {
type Ty<'a> = &'a [u8];
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
self == other
}
}
impl<'b> QueryValue for Cow<'b, [u8]> {
type Ty<'a> = &'a [u8];
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, other: &Self::Ty<'_>) -> bool {
*self == *other
}
}
#[derive(Debug, Clone, Copy)]
pub struct AnyStr;
impl QueryValue for AnyStr {
type Ty<'a> = &'a str;
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, _other: &Self::Ty<'_>) -> bool {
true
}
}
#[derive(Debug, Clone, Copy)]
pub struct AnyBytes;
impl QueryValue for AnyBytes {
type Ty<'a> = &'a [u8];
fn ty() -> ConstantTy {
ConstantTy::Bytes
}
fn is_match(&self, _other: &Self::Ty<'_>) -> bool {
true
}
}
#[derive(Debug, Clone, Copy)]
pub struct AnyConstant;
impl QueryValue for AnyConstant {
type Ty<'a> = crate::values::Constant<'a>;
fn ty() -> ConstantTy {
ConstantTy::Unknown
}
fn is_match(&self, _other: &Self::Ty<'_>) -> bool {
true
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum QueryResultError {
MissingElement,
InvalidLength,
InvalidType,
}
#[cfg(feature = "std")]
impl error::Error for QueryResultError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
impl Display for QueryResultError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MissingElement => f.write_str("missing element"),
Self::InvalidLength => f.write_str("invalid length"),
Self::InvalidType => f.write_str("invalid element type"),
}
}
}
impl fmt::Debug for QueryResultError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MissingElement => f.write_str("missing element"),
Self::InvalidLength => f.write_str("invalid length"),
Self::InvalidType => f.write_str("invalid element type"),
}
}
}
impl From<InvalidType> for QueryResultError {
fn from(_value: InvalidType) -> Self {
Self::InvalidType
}
}
impl From<Infallible> for QueryResultError {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
pub trait QueryResult<'a>
where
Self: Sized,
{
type Length: ArrayLength<values::Constant<'a>> + ArrayLength<ConstantTy>;
type ResultTy;
fn tys() -> GenericArray<ConstantTy, Self::Length>;
fn is_match(&self, other: &Self::ResultTy) -> bool;
fn into_tuple(
values: GenericArray<values::Constant<'a>, Self::Length>,
) -> Result<Self::ResultTy, QueryResultError>;
}
impl<'a, T, E> QueryResult<'a> for T
where
T::Ty<'a>: TryFrom<values::Constant<'a>, Error = E>,
T: QueryValue,
QueryResultError: From<E>,
{
type Length = U1;
type ResultTy = T::Ty<'a>;
fn tys() -> GenericArray<ConstantTy, Self::Length> {
generic_array::arr![ConstantTy; T::ty()]
}
fn is_match(&self, other: &Self::ResultTy) -> bool {
self.is_match(other)
}
fn into_tuple(
values: GenericArray<values::Constant<'a>, Self::Length>,
) -> Result<Self::ResultTy, QueryResultError> {
let mut iter = values.into_iter();
let t = <T::Ty<'a>>::try_from(iter.next().ok_or(QueryResultError::MissingElement)?)?;
if iter.next().is_some() {
return Err(QueryResultError::InvalidLength);
}
Ok(t)
}
}
macro_rules! impl_query_result {
($i0:ident) => {};
($i0:ident, $($I:ident),+) => {
impl_query_result!($($I),+);
paste::paste! {
impl<'a, $($I),+, $([<E $I>]),+> QueryResult<'a> for ($($I,)+)
where $($I::Ty<'a> : TryFrom<values::Constant<'a>, Error = [<E $I>]>),+,
$($I: QueryValue),+,
$(QueryResultError: From<[<E $I>]>),+,
Self: Sized
{
type Length = count_ident_typenum!($($I),+);
type ResultTy = ($($I::Ty<'a>,)+);
fn tys() -> GenericArray<ConstantTy, Self::Length> {
generic_array::arr![ConstantTy; $($I::ty()),+]
}
fn is_match(&self, other: &Self::ResultTy) -> bool {
#[allow(non_snake_case)]
let ($([<a_ $I>],)+) = self;
#[allow(non_snake_case)]
let ($([<b_ $I>],)+) = other;
$(
if ![<a_ $I>].is_match([<b_ $I>]) {
return false;
}
)+
true
}
fn into_tuple(values: GenericArray<values::Constant<'a>, Self::Length>) -> Result<Self::ResultTy, QueryResultError> {
let mut iter = values.into_iter();
let t = (
$(
{
let ignore_ident!($I, a) = <$I::Ty<'a>>::try_from(iter.next().ok_or_else(|| QueryResultError::MissingElement)?)?;
a
}
,)+
);
if iter.next().is_some() {
return Err(QueryResultError::InvalidLength);
}
Ok(t)
}
}
}
};
}
impl_query_result!(dummy, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);