tia 1.0.3

tia; trait, impl, accessors | automatic
Documentation
mod generator;
mod parser;

use proc_macro as pm;
use std::collections::{
 HashMap,
 HashSet
};

const EMPTY_STR: &str = "";
use self::EMPTY_STR as NO_SEPARATOR;

#[derive(Debug)]
pub struct Tia
{
 target_type_symbol:       TargetTypeSymbol,
 target_type:              TargetType,
 trait_to_field_accessors: TraitToFieldAccessors
}

pub type TraitToFieldAccessors = HashMap<TraitSymbol, FieldSymbolToFieldParams>;
pub type FieldSymbolToFieldParams = HashMap<FieldSymbol, FieldParams>;
pub type TargetTypeSymbol = String;
pub type FieldSymbol = String;
pub type FieldType = String;
pub type TraitSymbol = String;

#[derive(Debug)]
pub enum TargetType
{
 Struct,
 Enum,
 Union
}

#[derive(Debug, Clone, Eq)]
pub enum Accessor
{
 Setter
 {
  fsp: FieldSymbolPolicy,
  ptp: SetterParameterTypePolicy
 },
 Getter
 {
  fsp: FieldSymbolPolicy,
  ptp: GetterParameterTypePolicy
 }
}

impl PartialEq for Accessor
{
 fn eq(&self, other: &Self) -> bool
 {
  match (self, other)
  {
   (
    Accessor::Getter {
     fsp: _,
     ptp: _
    },
    Accessor::Getter {
     fsp: _,
     ptp: _
    }
   )
   | (
    Accessor::Setter {
     fsp: _,
     ptp: _
    },
    Accessor::Setter {
     fsp: _,
     ptp: _
    }
   ) => true,
   _ => false
  }
 }
}

impl std::hash::Hash for Accessor
{
 fn hash<H: std::hash::Hasher>(&self, h: &mut H)
 {
  match self
  {
   Accessor::Getter {
    fsp: _,
    ptp: _
   } => 0.hash(h),
   Accessor::Setter {
    fsp: _,
    ptp: _
   } => 1.hash(h)
  }
 }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum GetterParameterTypePolicy
{
 Move,
 Value,
 Ref,
 RefMut
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SetterParameterTypePolicy
{
 Value,
 RefClone,
 Into
}

#[allow(dead_code)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FieldSymbolPolicy
{
 Default,
 Prefix(String),
 Suffix(String),
 Fullname(String)
}

#[derive(Debug, Default, Clone)]
pub struct FieldParams
{
 pub field_type: FieldType,
 pub accessors:  HashSet<Accessor>
}

impl Tia
{
 pub fn new(i: syn::DeriveInput) -> Self { parser::parse(i) }
}

impl Into<pm::TokenStream> for Tia
{
 fn into(self) -> pm::TokenStream
 {
  let impl_definitions = generator::generate_impl_definitions(&self.trait_to_field_accessors, &self.target_type_symbol, self.target_type);

  if cfg!(feature = "print")
  {
   eprintln!("[proc-macro:tia +print Target: {}]", &self.target_type_symbol);
   eprintln!("{}", &impl_definitions);
  }

  if cfg!(feature = "file") || cfg!(feature = "file-pretty") || cfg!(feature = "include") || cfg!(feature = "include-pretty")
  {
   write_file(&self.target_type_symbol, &impl_definitions)
  };

  impl_definitions
   .parse::<pm::TokenStream>()
   .expect("tia::into<proc_macro::TokenStream> was failed. #TIA-PANIC-4001")
 }
}

fn write_file(target_type_symbol: &String, source: &String)
{
 use std::{
  fs::{
   create_dir_all,
   File
  },
  io::Write
 };

 let out_dir = "src/.tia/";
 create_dir_all(out_dir).unwrap();

 let path = format!("{}{}.rs", out_dir, &target_type_symbol);
 let mut file = File::create(&path).unwrap();
 write!(file, "{}", source).unwrap();

 if cfg!(feature = "file-pretty") || cfg!(feature = "include-pretty")
 {
  let result = if file_pretty(&path) { "<OK>" } else { "<NG>" };
  eprintln!(
   "[proc-macro:tia +file-pretty Target: {} => {} ; rustfmt {} ]",
   &target_type_symbol, &path, result
  );
 }
 else
 {
  eprintln!("[proc-macro:tia +file Target: {} => {}]", &target_type_symbol, &path);
 }
}

fn file_pretty(path: &String) -> bool
{
 std::process::Command::new("rustfmt")
  .arg("-q")
  .arg(path)
  .stdin(std::process::Stdio::null())
  .stdout(std::process::Stdio::null())
  .stderr(std::process::Stdio::null())
  .spawn()
  .and_then(|mut child_process| child_process.wait())
  .is_ok()
}