cido-macros 0.2.0

Macros for generating code that enables easier interfacing with cido
Documentation
use deluxe::{ExtractAttributes, ParseMetaItem};
use proc_macro2::TokenStream;
use quote::format_ident;
use syn::{Expr, Field, Ident, Path, Type, Visibility};

#[derive(Debug)]
pub struct CidomapStruct {
  pub name: Ident,
  pub vis: Visibility,
  pub opts: CidomapOptions,
  pub fields: Vec<CidomapField>,
}

impl CidomapStruct {
  pub fn parse(args: TokenStream, input: TokenStream) -> deluxe::Result<Self> {
    let cidomap_options = deluxe::parse2::<CidomapOptionsParse>(args)?.into();
    let t = syn::parse2::<syn::ItemStruct>(input)?;
    super::ensure_generics_zero(&t.generics)?;

    if t.semi_token.is_some() {
      return Err(crate::err(
        &t,
        "Only structs with named fields are supported",
      ));
    }

    let mut fields = Vec::with_capacity(t.fields.len());

    for mut field in t.fields {
      field
        .ident
        .as_ref()
        .ok_or_else(|| crate::err(&field, "Unnamed fields are not supported"))?;
      let graphql = GraphqlField::extract_attributes(&mut field)?;
      fields.push(CidomapField { field, graphql });
    }

    let this = Self {
      name: t.ident.clone(),
      vis: t.vis,
      opts: cidomap_options,
      fields,
    };
    Ok(this)
  }
}

#[derive(Debug)]
pub struct CidomapField {
  pub field: Field,
  pub graphql: GraphqlField,
}

#[derive(Debug)]
/// Options specified in the attributes of the top level struct definition.
pub struct CidomapOptions {
  pub gql: GraphqlStructDef,
  pub config: CidomapStructDef,
  pub embed_generated_code: bool,
}

impl From<CidomapOptionsParse> for CidomapOptions {
  fn from(p: CidomapOptionsParse) -> Self {
    Self {
      gql: p.gql,
      config: p.config,
      embed_generated_code: p.embed_generated_code.is_set(),
    }
  }
}

#[derive(Debug, ParseMetaItem)]
/// Options specified in the attributes of the top level struct definition.
pub struct CidomapOptionsParse {
  #[deluxe(default)]
  pub gql: GraphqlStructDef,
  pub config: CidomapStructDef,
  pub embed_generated_code: deluxe::Flag,
}

#[derive(Debug, ParseMetaItem)]
pub struct CidomapStructDef {
  #[deluxe(with = deluxe::with::maybe_quoted)]
  pub start_block: Expr,
  #[deluxe(with = deluxe::with::maybe_quoted)]
  pub max_block: Option<Expr>,
  #[deluxe(default = 1)]
  pub max_processing_order: u8,
  pub initial_filters: Path,
  pub init: Option<Path>,
  pub create: Option<Path>,
  pub error: Option<Type>,
  pub network: Type,
  pub events: Type,
}

#[derive(Debug, ParseMetaItem, Default)]
pub struct GraphqlStructDef {
  #[deluxe(default)]
  pub extensions: Vec<Type>,
  #[deluxe(default)]
  pub single: PrePostFixes,
  #[deluxe(default)]
  pub multiple: PrePostFixes,
  #[deluxe(default)]
  pub history: PrePostFixes,
}

#[derive(Debug, ParseMetaItem, Default)]
pub struct PrePostFixes {
  #[deluxe(with = deluxe::with::maybe_quoted)]
  pub prefix: Option<Ident>,
  #[deluxe(with = deluxe::with::maybe_quoted)]
  pub suffix: Option<Ident>,
}

impl PrePostFixes {
  pub fn apply_default_name(&self, name: &Ident) -> Option<Ident> {
    match (&self.prefix, &self.suffix) {
      (None, None) => None,
      (None, Some(suffix)) => Some(format_ident!("{name}{suffix}")),
      (Some(prefix), None) => Some(format_ident!("{prefix}{name}")),
      (Some(prefix), Some(suffix)) => Some(format_ident!("{prefix}{name}{suffix}")),
    }
  }
}

#[derive(Debug, ExtractAttributes)]
#[deluxe(attributes(gql))]
pub struct GraphqlField {
  pub id: Option<Type>,
  #[deluxe(default)]
  pub single: FnOptions,
  #[deluxe(default)]
  pub multiple: FnOptions,
  #[deluxe(default)]
  pub history: FnOptions,
  #[deluxe(with = deluxe::with::maybe_quoted)]
  pub to_id_borrow: Option<Expr>,
}

#[derive(Debug, Default, ParseMetaItem)]
pub struct FnOptions {
  pub name: Option<Ident>,
  #[deluxe(with = deluxe::with::maybe_quoted)]
  pub complexity: Option<Expr>,
}