|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
use std::env;
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
use syn::{Item, Type, ItemImpl};
|
|
|
|
|
use syn::{Item, ItemImpl, Type};
|
|
|
|
|
|
|
|
|
|
// This script reads the contents of any rust file in the `tiles/` directory,
|
|
|
|
|
// and gathers any type that implements `Tile`. These types are then put into
|
|
|
|
@ -13,20 +13,7 @@ use syn::{Item, Type, ItemImpl};
|
|
|
|
|
// - only impls in the format "impl Tile for X" are accepted (X must not contain any "::")
|
|
|
|
|
|
|
|
|
|
// TODO: generate a kind of Reflection API for AnyTile
|
|
|
|
|
|
|
|
|
|
fn parse_impl_tile(item: &ItemImpl) -> Option<String> {
|
|
|
|
|
let (_, trait_, _) = item.trait_.as_ref()?;
|
|
|
|
|
let ident = trait_.get_ident()?;
|
|
|
|
|
|
|
|
|
|
if ident.to_string() == "Tile" {
|
|
|
|
|
if let Type::Path(path) = &*item.self_ty {
|
|
|
|
|
let name = path.path.get_ident().map(|i| i.to_string())?;
|
|
|
|
|
return Some(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
// - reading and writing can now be done through serde
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
|
|
@ -37,16 +24,16 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
// Read and parse the contents of every .rs file in tiles/
|
|
|
|
|
|
|
|
|
|
for entry in fs::read_dir("tiles/").expect("Error while reading tiles/") {
|
|
|
|
|
let entry = entry.expect("Error while reading tiles/");
|
|
|
|
|
let src_path = entry.path();
|
|
|
|
|
for src_path in list_files("tiles/") {
|
|
|
|
|
if let Some("rs") = src_path.extension().and_then(|x| x.to_str()) {
|
|
|
|
|
let contents = fs::read_to_string(src_path.clone())
|
|
|
|
|
.expect(&format!("Couldn't read {:?}", src_path));
|
|
|
|
|
.unwrap_or_else(|err| panic!("Couldn't read {:?}: {}", src_path, err));
|
|
|
|
|
let mut local_names: Vec<String> = Vec::new();
|
|
|
|
|
|
|
|
|
|
// TODO: don't throw an error when a parsing error occured;
|
|
|
|
|
// Instead, include the file so that rustc can give a helpful error
|
|
|
|
|
let syntax = syn::parse_file(&contents)
|
|
|
|
|
.expect(&format!("Unable to parse file {:?}", src_path));
|
|
|
|
|
.unwrap_or_else(|err| panic!("Unable to parse file {:?}: {}", src_path, err));
|
|
|
|
|
|
|
|
|
|
for item in syntax.items.iter() {
|
|
|
|
|
match item {
|
|
|
|
@ -70,23 +57,67 @@ fn main() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate code
|
|
|
|
|
// == Generate code ==
|
|
|
|
|
|
|
|
|
|
let res = generate_code(files, names);
|
|
|
|
|
|
|
|
|
|
fs::write(dest_path.clone(), &res)
|
|
|
|
|
.unwrap_or_else(|err| panic!("Couldn't write to {:?}: {}", dest_path, err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Helper function to recognize `impl Tile for XYZ`
|
|
|
|
|
fn parse_impl_tile(item: &ItemImpl) -> Option<String> {
|
|
|
|
|
let (_, trait_, _) = item.trait_.as_ref()?;
|
|
|
|
|
let ident = trait_.get_ident()?;
|
|
|
|
|
|
|
|
|
|
if ident.to_string() == "Tile" {
|
|
|
|
|
if let Type::Path(path) = &*item.self_ty {
|
|
|
|
|
let name = path.path.get_ident().map(|i| i.to_string())?;
|
|
|
|
|
return Some(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut res = String::from("use enum_dispatch::enum_dispatch;\n\n");
|
|
|
|
|
// TODO: recursively list files in `path` (right now only the top-level files are listed).
|
|
|
|
|
// The method can return a `Vec` instead if necessary.
|
|
|
|
|
fn list_files(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
|
|
|
|
let iter = fs::read_dir(path.as_ref())
|
|
|
|
|
.unwrap_or_else(|err| panic!("Error while reading {}: {}", path.as_ref().display(), err));
|
|
|
|
|
|
|
|
|
|
for file in files {
|
|
|
|
|
let mod_name = file.0.as_path().file_stem().map(|x| x.to_str()).flatten().expect(&format!("Couldn't extract valid UTF-8 filename from path {:?}", file));
|
|
|
|
|
let path = file.0.as_path().to_str().expect("Invalid UTF-8 path");
|
|
|
|
|
iter.filter_map(|entry| match entry {
|
|
|
|
|
Ok(entry) => Some(entry.path()),
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res += &format!("#[path = \"{}\"]\nmod {};\n", path, mod_name);
|
|
|
|
|
res += &format!("pub use {}::{{", mod_name);
|
|
|
|
|
for name in file.1 {
|
|
|
|
|
fn generate_code(files: Vec<(PathBuf, Vec<String>)>, names: Vec<String>) -> String {
|
|
|
|
|
let mut res = String::new();
|
|
|
|
|
|
|
|
|
|
// TODO: use a HashMap to prevent duplicate module names
|
|
|
|
|
for (file, names) in files {
|
|
|
|
|
let module_name = file
|
|
|
|
|
.as_path()
|
|
|
|
|
.file_stem()
|
|
|
|
|
.map(|x| x.to_str())
|
|
|
|
|
.flatten()
|
|
|
|
|
.expect(&format!(
|
|
|
|
|
"Couldn't extract valid UTF-8 filename from path {:?}",
|
|
|
|
|
file
|
|
|
|
|
));
|
|
|
|
|
let path = file.as_path().to_str().expect("Invalid UTF-8 path");
|
|
|
|
|
|
|
|
|
|
res += &format!("#[path = \"{}\"]\nmod {};\n", path, module_name);
|
|
|
|
|
res += &format!("pub use {}::{{", module_name);
|
|
|
|
|
for name in names {
|
|
|
|
|
res += &format!("{}, ", name);
|
|
|
|
|
}
|
|
|
|
|
res += "};\n\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res += &fs::read_to_string("src/tile/anytile.doc.rs").expect("Couldn't read src/tile/anytile.doc.rs");
|
|
|
|
|
res += &fs::read_to_string("src/tile/anytile.doc.rs")
|
|
|
|
|
.expect("Couldn't read src/tile/anytile.doc.rs");
|
|
|
|
|
res += "#[derive(Clone, Debug, Serialize, Deserialize)]\n";
|
|
|
|
|
res += "#[enum_dispatch]\n";
|
|
|
|
|
res += "pub enum AnyTile {\n";
|
|
|
|
@ -96,10 +127,10 @@ fn main() {
|
|
|
|
|
}
|
|
|
|
|
res += "}\n";
|
|
|
|
|
|
|
|
|
|
// impl<T: Tile> TryInto<&T> for &AnyTile
|
|
|
|
|
res += "\n";
|
|
|
|
|
|
|
|
|
|
for name in names {
|
|
|
|
|
// impl<T: Tile> TryInto<&T> for &AnyTile
|
|
|
|
|
res += &format!(
|
|
|
|
|
concat!(
|
|
|
|
|
"impl<'a> TryInto<&'a {0}> for &'a AnyTile {{\n",
|
|
|
|
@ -115,6 +146,7 @@ fn main() {
|
|
|
|
|
name
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// impl<T: Tile> TryInto<&mut T> for &mut AnyTile
|
|
|
|
|
res += &format!(
|
|
|
|
|
concat!(
|
|
|
|
|
"impl<'a> TryInto<&'a mut {0}> for &'a mut AnyTile {{\n",
|
|
|
|
@ -131,5 +163,5 @@ fn main() {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs::write(dest_path.clone(), &res).expect(&format!("Couldn't write to {:?}", dest_path));
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|