argus-ser-macros 0.1.20

Rustc Ty serialization and TS bindings.
Documentation
pub(crate) mod utils;

use proc_macro::TokenStream;
use quote::quote;
use syn::{Item, parse_macro_input};
use utils::*;

#[proc_macro_attribute]
pub fn argus(_attr: TokenStream, item: TokenStream) -> TokenStream {
  item
}

#[proc_macro]
pub fn serialize_custom_seq(input: TokenStream) -> TokenStream {
  let SerializeCustomSeqArgs {
    wrap,
    serializer,
    value,
  } = parse_macro_input!(input as SerializeCustomSeqArgs);

  TokenStream::from(quote! {{
     use serde::ser::SerializeSeq;
     let mut seq = #serializer.serialize_seq(Some(#value.len()))?;
     for e in #value.into_iter() {
         seq.serialize_element(&(#wrap)(e))?;
     }
     seq.end()
  }})
}

#[proc_macro_derive(Many)]
pub fn create_slice_wrapper(item: TokenStream) -> TokenStream {
  let ast = parse_macro_input!(item as Item);
  let argus: ArgusIdentifiers = argus_identifiers(&ast);

  let mut generics_outlive_a = argus.generics.clone();
  let life_a = introduce_outlives(&mut generics_outlive_a);

  let ArgusIdentifiers {
    name,
    remote,
    slice: slice_name,
    generics,
    ..
  } = argus;
  let name_str = name.to_string();
  let raw = remote.path();

  TokenStream::from(quote! {
      pub struct #slice_name;
      impl #slice_name {
        pub fn serialize<S: serde::Serializer>(
          value: &[#raw],
          s: S
        ) -> Result<S::Ok, S::Error> {
          #[derive(serde::Serialize)]
          struct Wrapper #generics_outlive_a (
            #[serde(with = #name_str)]
            & #life_a #raw #generics
          );
          crate::serialize_custom_seq!(Wrapper, s, value)
        }
      }
  })
}

#[proc_macro_derive(Poly)]
pub fn create_poly_wrapper(item: TokenStream) -> TokenStream {
  let ast = parse_macro_input!(item as Item);

  let ArgusIdentifiers {
    name, remote, poly, ..
  } = argus_identifiers(&ast);

  let raw = remote.path();
  let remote_path_str = remote.lit();
  let ts_ty_str = remote.path().segments.last().unwrap().ident.to_string();
  let name_str = name.to_string();
  let ts_str = format!("Poly{}", remove_def_annotation(&name_str));

  TokenStream::from(quote! {
      #[derive(Clone, Debug, serde::Serialize)]
      #[serde(rename_all = "camelCase")]
      #[argus(remote = #remote_path_str)]
      #[cfg_attr(feature = "testing", derive(ts_rs::TS))]
      #[cfg_attr(feature = "testing", ts(export, rename = #ts_str))]
      pub struct #poly<'tcx> {
          #[serde(with = #name_str)]
          #[cfg_attr(feature = "testing", ts(type = #ts_ty_str))]
          value: #raw<'tcx>,

          #[serde(with = "crate::ty::BoundVariableKindDefs")]
          #[cfg_attr(feature = "testing", ts(type = "BoundVariableKind[]"))]
          bound_vars: &'tcx rustc_middle::ty::List<rustc_middle::ty::BoundVariableKind>,
      }

      impl<'tcx> #poly<'tcx> {
          pub fn new(value: &rustc_middle::ty::Binder<'tcx, #raw<'tcx>>) -> Self {
              let value = value.clone();
              Self {
                  bound_vars: value.bound_vars(),
                  value: value.skip_binder(),
              }
          }

          pub fn serialize<S: serde::Serializer>(
              value: &rustc_middle::ty::Binder<'tcx, #raw<'tcx>>,
              s: S,
          ) -> Result<S::Ok, S::Error> {
              Self::new(value).serialize(s)
          }
      }
  })
}

#[proc_macro_derive(Maybe)]
pub fn create_maybe_wrapper(item: TokenStream) -> TokenStream {
  let ast = parse_macro_input!(item as Item);

  let ArgusIdentifiers {
    name,
    remote,
    maybe,
    ..
  } = argus_identifiers(&ast);

  let raw = remote.path();

  TokenStream::from(quote! {
      pub struct #maybe;
    impl #maybe {
        pub fn serialize<S>(value: &Option<#raw>, s: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer,
        {
            match value {
            None => s.serialize_none(),
            Some(ty) => #name::serialize(ty, s),
            }
        }
        }
  })
}