eql_core 0.1.15

EVM Query Language core components
Documentation
use super::ens::NameOrAddress;
use crate::interpreter::frontend::parser::Rule;
use alloy::hex::FromHexError;
use eql_macros::EnumVariants;
use pest::iterators::{Pair, Pairs};
use serde::{Deserialize, Serialize};
use std::{fmt::Display, str::FromStr};

#[derive(thiserror::Error, Debug)]
pub enum AccountError {
    #[error("Unexpected token {0}")]
    UnexpectedToken(String),

    #[error(transparent)]
    AccountFieldError(#[from] AccountFieldError),

    #[error(transparent)]
    AccountFilterError(#[from] AccountFilterError),

    #[error(transparent)]
    FromHexError(#[from] FromHexError),
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Account {
    id: Option<Vec<NameOrAddress>>,
    filter: Option<Vec<AccountFilter>>,
    fields: Vec<AccountField>,
}

impl Account {
    pub fn new(
        id: Option<Vec<NameOrAddress>>,
        filter: Option<Vec<AccountFilter>>,
        fields: Vec<AccountField>,
    ) -> Self {
        Self { id, filter, fields }
    }

    pub fn ids(&self) -> Option<Vec<NameOrAddress>> {
        self.id.clone()
    }

    pub fn filter(&self) -> Option<Vec<AccountFilter>> {
        self.filter.clone()
    }

    pub fn fields(&self) -> Vec<AccountField> {
        self.fields.clone()
    }
}

impl TryFrom<Pairs<'_, Rule>> for Account {
    type Error = AccountError;

    fn try_from(pairs: Pairs<'_, Rule>) -> Result<Self, Self::Error> {
        let mut fields: Vec<AccountField> = vec![];
        let mut id: Option<Vec<NameOrAddress>> = None;
        let mut filter: Option<Vec<AccountFilter>> = None;

        for pair in pairs {
            match pair.as_rule() {
                Rule::account_fields => {
                    let inner_pairs = pair.into_inner();

                    if let Some(pair) = inner_pairs.peek() {
                        if pair.as_rule() == Rule::wildcard {
                            fields = AccountField::all_variants().to_vec();
                            continue;
                        }
                    }

                    fields = inner_pairs
                        .map(|pair| AccountField::try_from(pair))
                        .collect::<Result<Vec<AccountField>, AccountFieldError>>()?;
                }
                Rule::account_id => {
                    if let Some(id) = id.as_mut() {
                        id.push(NameOrAddress::from_str(pair.as_str())?);
                    } else {
                        id = Some(vec![NameOrAddress::from_str(pair.as_str())?]);
                    }
                }
                Rule::account_filter_list => {
                    filter = Some(
                        pair.into_inner()
                            .map(|pair| AccountFilter::try_from(pair))
                            .collect::<Result<Vec<AccountFilter>, AccountFilterError>>()?,
                    );
                }
                _ => {
                    return Err(AccountError::UnexpectedToken(pair.as_str().to_string()));
                }
            }
        }

        Ok(Account { id, filter, fields })
    }
}

#[derive(thiserror::Error, Debug)]
pub enum AccountFilterError {
    #[error("Unexpected token {0} for account filter")]
    UnexpectedToken(String),

    #[error(transparent)]
    FromHexError(#[from] FromHexError),
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AccountFilter {
    Address(NameOrAddress),
}

impl TryFrom<Pair<'_, Rule>> for AccountFilter {
    type Error = AccountFilterError;

    fn try_from(pair: Pair<'_, Rule>) -> Result<Self, Self::Error> {
        match pair.as_rule() {
            Rule::address_filter => {
                let address = NameOrAddress::from_str(pair.as_str())?;
                Ok(AccountFilter::Address(address))
            }
            _ => {
                return Err(AccountFilterError::UnexpectedToken(
                    pair.as_str().to_string(),
                ));
            }
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, EnumVariants)]
pub enum AccountField {
    Address,
    Nonce,
    Balance,
    Code,
}

impl Display for AccountField {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AccountField::Address => write!(f, "address"),
            AccountField::Nonce => write!(f, "nonce"),
            AccountField::Balance => write!(f, "balance"),
            AccountField::Code => write!(f, "code"),
        }
    }
}

#[derive(thiserror::Error, Debug)]
pub enum AccountFieldError {
    #[error("Invalid field for entity Account: {0}")]
    InvalidField(String),

    #[error(transparent)]
    FromHexError(#[from] FromHexError),
}

impl<'a> TryFrom<Pair<'a, Rule>> for AccountField {
    type Error = AccountFieldError;

    fn try_from(pair: Pair<'a, Rule>) -> Result<Self, Self::Error> {
        AccountField::try_from(pair.as_str())
    }
}

impl TryFrom<&str> for AccountField {
    type Error = AccountFieldError;

    fn try_from(value: &str) -> Result<Self, AccountFieldError> {
        match value {
            "address" => Ok(AccountField::Address),
            "nonce" => Ok(AccountField::Nonce),
            "balance" => Ok(AccountField::Balance),
            "code" => Ok(AccountField::Code),
            invalid_field => Err(AccountFieldError::InvalidField(invalid_field.to_string())),
        }
    }
}