1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
use std::sync::Arc;
use async_trait::async_trait;
use multiversx_sc_scenario::multiversx_sc::codec::TopDecodeMulti;
use multiversx_sc_scenario::scenario_model::ScCallStep;
use tokio::sync::Mutex;
use novax_data::NativeConvertible;
use crate::error::executor::ExecutorError;
/// A trait representing the execution of smart contract queries.
///
/// This trait is implemented by types that can execute smart contract queries in a specific environment,
/// like a real blockchain or a mocked one. The trait's associated function, `execute`, is responsible for
/// sending a query request, executing the query on the blockchain or mocked environment,
/// and returning the result of the query.
#[async_trait]
pub trait QueryExecutor: Clone + Send + Sync {
    /// Executes a smart contract query and returns the result.
    ///
    /// # Parameters
    ///
    /// - `request`: A reference to the [`ScCallStep`] representing the smart contract query to be executed.
    ///
    /// # Type Parameters
    ///
    /// - `OutputManaged`: The managed type representing the expected output of the query.
    ///   It must implement [`TopDecodeMulti`], [`NativeConvertible`], [`Send`], and [`Sync`].
    ///
    /// # Returns
    ///
    /// A [`Result`] containing the native representation of the query result,
    /// or an [`ExecutorError`] if the query execution fails.
    async fn execute<OutputManaged>(&self, request: &ScCallStep) -> Result<OutputManaged::Native, ExecutorError>
        where
            OutputManaged: TopDecodeMulti + NativeConvertible + Send + Sync;
}
/// An implementation of `QueryExecutor` for `Arc<T>` where `T: QueryExecutor`.
///
/// This implementation allows shared access to an executor instance.
#[async_trait]
impl<T: QueryExecutor> QueryExecutor for Arc<T> {
    async fn execute<OutputManaged>(&self, request: &ScCallStep) -> Result<OutputManaged::Native, ExecutorError> where OutputManaged: TopDecodeMulti + NativeConvertible + Send + Sync {
        T::execute::<OutputManaged>(self, request).await
    }
}
/// An implementation of `QueryExecutor` for `Arc<Mutex<T>>` where `T: QueryExecutor`.
///
/// This implementation allows exclusive access to an executor instance, ensuring safe mutable access.
#[async_trait]
impl<T: QueryExecutor> QueryExecutor for Arc<Mutex<T>> {
    async fn execute<OutputManaged>(&self, request: &ScCallStep) -> Result<OutputManaged::Native, ExecutorError> where OutputManaged: TopDecodeMulti + NativeConvertible + Send + Sync {
        {
            let executor = self.lock().await;
            executor.execute::<OutputManaged>(request).await
        }
    }
}