openrr_internal_codegen/
main.rsmod plugin;
mod rpc;
use std::path::{Path, PathBuf};
use anyhow::{format_err, Result};
use fs_err as fs;
use proc_macro2::TokenStream;
fn main() -> Result<()> {
let workspace_root = workspace_root();
plugin::gen(&workspace_root)?;
rpc::gen(&workspace_root)?;
Ok(())
}
fn arci_types(
workspace_root: &Path,
) -> Result<(
Vec<syn::ItemTrait>,
Vec<syn::ItemStruct>,
Vec<syn::ItemEnum>,
)> {
let path = &workspace_root.join("arci/src/traits");
let mut files: Vec<_> = fs::read_dir(path)?
.filter_map(Result::ok)
.filter_map(|entry| {
let path = entry.path();
if !path.is_file() || path.extension().is_none_or(|e| e != "rs") {
None
} else {
Some(path)
}
})
.collect();
files.sort_unstable();
let mut traits = vec![];
let mut structs = vec![];
let mut enums = vec![];
for path in &files {
let s = &fs::read_to_string(path)?;
let file: syn::File = syn::parse_str(s)?;
for item in file.items {
match item {
syn::Item::Trait(item) if matches!(item.vis, syn::Visibility::Public(_)) => {
traits.push(item);
}
syn::Item::Struct(item) if matches!(item.vis, syn::Visibility::Public(_)) => {
structs.push(item);
}
syn::Item::Enum(item) if matches!(item.vis, syn::Visibility::Public(_)) => {
enums.push(item);
}
_ => {}
}
}
}
Ok((traits, structs, enums))
}
fn is_str(ty: &syn::Type) -> bool {
if let syn::Type::Reference(ty) = ty {
if let Some(path) = get_ty_path(&ty.elem) {
if path.is_ident("str") {
return true;
}
}
}
false
}
fn get_ty_path(ty: &syn::Type) -> Option<&syn::Path> {
if let syn::Type::Path(ty) = ty {
return Some(&ty.path);
}
None
}
fn is_option(ty: &syn::Type) -> Option<&syn::Type> {
let path = get_ty_path(ty)?;
if path.segments.len() == 1 && path.segments[0].ident == "Option" {
if let syn::PathArguments::AngleBracketed(args) = &path.segments.last().unwrap().arguments {
if let syn::GenericArgument::Type(ty) = &args.args[0] {
return Some(ty);
}
}
}
None
}
fn is_result(ty: &syn::Type) -> Option<&syn::Type> {
let path = get_ty_path(ty)?;
if path.segments.len() == 1 && path.segments[0].ident == "Result" {
if let syn::PathArguments::AngleBracketed(args) = &path.segments.last().unwrap().arguments {
if let syn::GenericArgument::Type(ty) = &args.args[0] {
return Some(ty);
}
}
}
None
}
fn is_vec(ty: &syn::Type) -> Option<&syn::Type> {
let path = get_ty_path(ty)?;
if path.segments.len() == 1 && path.segments[0].ident == "Vec" {
if let syn::PathArguments::AngleBracketed(args) = &path.segments.last().unwrap().arguments {
if let syn::GenericArgument::Type(ty) = &args.args[0] {
return Some(ty);
}
}
}
None
}
pub(crate) fn is_primitive(ty: &syn::Type) -> bool {
if let Some(path) = get_ty_path(ty) {
if let Some(ident) = path.get_ident() {
return matches!(
ident.to_string().as_str(),
"isize"
| "i8"
| "i16"
| "i32"
| "i64"
| "i128"
| "usize"
| "u8"
| "u16"
| "u32"
| "u64"
| "u128"
| "f32"
| "f64"
| "bool"
);
}
}
false
}
fn workspace_root() -> PathBuf {
let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
dir.pop(); dir.pop(); dir
}
fn header() -> String {
concat!(
"// This file is @generated by ",
env!("CARGO_BIN_NAME"),
".\n",
"// It is not intended for manual editing.\n",
"\n",
"#![allow(unused_variables)]\n",
"#![allow(clippy::useless_conversion, clippy::unit_arg)]\n",
"\n",
)
.into()
}
fn write(path: &Path, contents: TokenStream) -> Result<()> {
let mut out = header().into_bytes();
out.extend_from_slice(
prettyplease::unparse(
&syn::parse2(contents.clone())
.map_err(|e| format_err!("{e} in:\n---\n{contents}\n---"))?,
)
.as_bytes(),
);
if path.is_file() && fs::read(path)? == out {
return Ok(());
}
fs::write(path, out)?;
Ok(())
}