use core::marker::PhantomData;
use crate::query::CustomQuery;
use crate::results::Empty;
use crate::traits::{Api, Querier, Storage};
use crate::QuerierWrapper;
pub struct OwnedDeps<S: Storage, A: Api, Q: Querier, C: CustomQuery = Empty> {
    pub storage: S,
    pub api: A,
    pub querier: Q,
    pub custom_query_type: PhantomData<C>,
}
pub struct DepsMut<'a, C: CustomQuery = Empty> {
    pub storage: &'a mut dyn Storage,
    pub api: &'a dyn Api,
    pub querier: QuerierWrapper<'a, C>,
}
#[derive(Clone)]
pub struct Deps<'a, C: CustomQuery = Empty> {
    pub storage: &'a dyn Storage,
    pub api: &'a dyn Api,
    pub querier: QuerierWrapper<'a, C>,
}
impl<'a, C: CustomQuery> Copy for Deps<'a, C> {}
impl<S: Storage, A: Api, Q: Querier, C: CustomQuery> OwnedDeps<S, A, Q, C> {
    pub fn as_ref(&'_ self) -> Deps<'_, C> {
        Deps {
            storage: &self.storage,
            api: &self.api,
            querier: QuerierWrapper::new(&self.querier),
        }
    }
    pub fn as_mut(&'_ mut self) -> DepsMut<'_, C> {
        DepsMut {
            storage: &mut self.storage,
            api: &self.api,
            querier: QuerierWrapper::new(&self.querier),
        }
    }
}
impl<'a, C: CustomQuery> DepsMut<'a, C> {
    pub fn as_ref(&'_ self) -> Deps<'_, C> {
        Deps {
            storage: self.storage,
            api: self.api,
            querier: self.querier,
        }
    }
    pub fn branch(&'_ mut self) -> DepsMut<'_, C> {
        DepsMut {
            storage: self.storage,
            api: self.api,
            querier: self.querier,
        }
    }
    pub fn into_empty(self) -> DepsMut<'a, Empty> {
        DepsMut {
            storage: self.storage,
            api: self.api,
            querier: self.querier.into_empty(),
        }
    }
}
impl<'a, C: CustomQuery> Deps<'a, C> {
    pub fn into_empty(self) -> Deps<'a, Empty> {
        Deps {
            storage: self.storage,
            api: self.api,
            querier: self.querier.into_empty(),
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::testing::{mock_dependencies, MockApi, MockQuerier, MockStorage};
    use serde::{Deserialize, Serialize};
    fn execute(mut deps: DepsMut) {
        execute2(deps.branch());
        query(deps.as_ref());
        execute2(deps.branch());
    }
    fn execute2(_deps: DepsMut) {}
    fn query(deps: Deps) {
        query2(deps);
        query2(deps);
    }
    fn query2(_deps: Deps) {}
    #[test]
    fn ensure_easy_reuse() {
        let mut deps = mock_dependencies();
        execute(deps.as_mut());
        query(deps.as_ref())
    }
    #[derive(Clone, Serialize, Deserialize)]
    struct MyQuery;
    impl CustomQuery for MyQuery {}
    #[test]
    fn deps_implements_copy() {
        impl CustomQuery for u64 {}
        let owned = OwnedDeps::<_, _, _, u64> {
            storage: MockStorage::default(),
            api: MockApi::default(),
            querier: MockQuerier::<u64>::new(&[]),
            custom_query_type: PhantomData,
        };
        let deps: Deps<u64> = owned.as_ref();
        let _copy1 = deps;
        let _copy2 = deps;
        let owned = OwnedDeps::<_, _, _, MyQuery> {
            storage: MockStorage::default(),
            api: MockApi::default(),
            querier: MockQuerier::<MyQuery>::new(&[]),
            custom_query_type: PhantomData,
        };
        let deps: Deps<MyQuery> = owned.as_ref();
        let _copy1 = deps;
        let _copy2 = deps;
    }
    #[test]
    fn deps_to_empty() {
        let mut owned = OwnedDeps::<_, _, _, MyQuery> {
            storage: MockStorage::default(),
            api: MockApi::default(),
            querier: MockQuerier::<u64>::new(&[]),
            custom_query_type: PhantomData,
        };
        let deps_mut: DepsMut<MyQuery> = owned.as_mut();
        let _: DepsMut<Empty> = deps_mut.into_empty();
        let deps: Deps<MyQuery> = owned.as_ref();
        let _: Deps<Empty> = deps.into_empty();
    }
}