dynamic-graphql-derive 0.10.2

Dynamic GraphQL schema macro
Documentation
use std::ops::Deref;
use std::ops::DerefMut;

use darling::FromDeriveInput;
use darling::FromField;
use darling::FromVariant;
use darling::ast::Data;
use darling::util::Ignored;

use crate::FromItemImpl;
use crate::utils::impl_block::FromFnArg;
use crate::utils::impl_block::FromImplItemFn;
use crate::utils::impl_block::FromItemTrait;
use crate::utils::impl_block::FromTraitItemFn;
use crate::utils::with_index::SetIndex;

pub trait MakeContext<C: Clone> {
    fn make_context(&self) -> C;
}

impl<T> MakeContext<()> for T {
    fn make_context(&self) {}
}

impl<T> MakeContext<Ignored> for T {
    fn make_context(&self) -> Ignored {
        Ignored
    }
}

pub trait SetContext {
    type Context: Clone;
    fn set_context(&mut self, context: Self::Context);
}

impl SetContext for () {
    type Context = Ignored;

    fn set_context(&mut self, _: Self::Context) {}
}

impl SetContext for Ignored {
    type Context = Ignored;

    fn set_context(&mut self, _: Self::Context) {}
}

impl<T: SetContext, E> SetContext for Result<T, E> {
    type Context = T::Context;

    fn set_context(&mut self, context: Self::Context) {
        if let Ok(inner) = self {
            inner.set_context(context);
        }
    }
}

impl<T: SetContext> SetContext for Option<T> {
    type Context = T::Context;

    fn set_context(&mut self, context: Self::Context) {
        if let Some(inner) = self {
            inner.set_context(context);
        }
    }
}

impl<T: SetContext> SetContext for Vec<T> {
    type Context = T::Context;

    fn set_context(&mut self, context: Self::Context) {
        self.iter_mut()
            .for_each(|item| item.set_context(context.clone()));
    }
}

impl<T: SetContext> SetContext for darling::ast::Fields<T> {
    type Context = T::Context;

    fn set_context(&mut self, context: Self::Context) {
        self.fields.set_context(context);
    }
}

impl<C: Clone, V: SetContext<Context = C>, F: SetContext<Context = C>> SetContext
    for darling::ast::Data<V, F>
{
    type Context = C;

    fn set_context(&mut self, context: Self::Context) {
        match self {
            Data::Enum(vs) => {
                vs.set_context(context);
            }
            Data::Struct(st) => {
                st.fields.set_context(context);
            }
        }
    }
}

#[derive(Debug, Clone)]
pub struct WithContext<C, T> {
    pub ctx: C,
    pub inner: T,
}

impl<C, T> Deref for WithContext<C, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<C, T> DerefMut for WithContext<C, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<C: Clone, T> SetContext for WithContext<C, T> {
    type Context = C;

    fn set_context(&mut self, context: Self::Context) {
        self.ctx = context;
    }
}

impl<C, T> SetIndex for WithContext<C, T>
where
    T: SetIndex,
{
    fn with_index(self, index: usize) -> Self {
        Self {
            ctx: self.ctx,
            inner: T::with_index(self.inner, index),
        }
    }
}

macro_rules! impl_for_with_context {
    ($trayt:ident, $method:ident, $syn:path) => {
        impl<A: $trayt, C: Default> $trayt for WithContext<C, A> {
            fn $method(input: &$syn) -> darling::Result<Self> {
                let inner = A::$method(input)?;
                Ok(WithContext {
                    ctx: C::default(),
                    inner,
                })
            }
        }
    };
}

macro_rules! impl_mut_for_with_context {
    ($trayt:ident, $method:ident, $syn:path) => {
        impl<A: $trayt, C: Default> $trayt for WithContext<C, A> {
            fn $method(input: &mut $syn) -> darling::Result<Self> {
                let inner = A::$method(input)?;
                Ok(WithContext {
                    ctx: C::default(),
                    inner,
                })
            }
        }
    };
}

impl_for_with_context!(FromDeriveInput, from_derive_input, syn::DeriveInput);
impl_for_with_context!(FromField, from_field, syn::Field);
impl_for_with_context!(FromVariant, from_variant, syn::Variant);

impl_mut_for_with_context!(FromFnArg, from_fn_arg, syn::FnArg);
impl_mut_for_with_context!(FromImplItemFn, from_impl_item_method, syn::ImplItemFn);
impl_mut_for_with_context!(FromItemImpl, from_item_impl, syn::ItemImpl);
impl_mut_for_with_context!(FromItemTrait, from_item_trait, syn::ItemTrait);
impl_mut_for_with_context!(FromTraitItemFn, from_trait_item_method, syn::TraitItemFn);