-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1f2ec50
commit 503091e
Showing
19 changed files
with
3,801 additions
and
1,119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ node_modules/ | |
# Added by cargo | ||
|
||
target | ||
build_logs.txt |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
#![allow(clippy::ptr_arg, clippy::collapsible_if)] | ||
|
||
use std::{fmt::Debug, io::Write, ops::Not}; | ||
|
||
use heck::ToSnakeCase; | ||
use itertools::Itertools; | ||
use proc_macro2::TokenStream; | ||
use quote::{quote, ToTokens}; | ||
use syn::{Field, ItemStruct}; | ||
|
||
fn main() { | ||
std::fs::write("build_logs.txt", "").unwrap(); | ||
|
||
let objects = std::fs::read_to_string("./src/objects/chart_objects.rs").unwrap(); | ||
|
||
let symbols = syn::parse_file(&objects).unwrap(); | ||
|
||
let use_ = quote! { | ||
#![allow(clippy::default_constructed_unit_structs)] | ||
'\n' | ||
use { | ||
super::{ | ||
chart_objects::*, | ||
helper_objects::* | ||
}, | ||
crate::{Annotation, FnWithArgs}, | ||
std::collections::* | ||
}; | ||
}; | ||
|
||
let impl_blocks = symbols | ||
.items | ||
.into_iter() | ||
.filter_map(|item| match item { | ||
syn::Item::Struct(item_struct) => Some(item_struct), | ||
_ => None, | ||
}) | ||
.map(|s| { | ||
let s_name = &s.ident; | ||
|
||
let generics = &s.generics; | ||
|
||
let type_param = s | ||
.generics | ||
.type_params() | ||
.map(|t| t.ident.clone()) | ||
.collect_vec(); | ||
|
||
let type_params = if type_param.is_empty().not() { | ||
quote! { < #(#type_param),* > } | ||
} else { | ||
quote! {} | ||
}; | ||
|
||
let new = quote! { | ||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
'\n' | ||
}; | ||
|
||
let methods = s.clone() | ||
.fields | ||
.into_iter() | ||
.map(|field| { | ||
let name = &field.ident; | ||
let get_name = syn::Ident::new( | ||
&format!("get_{}", name.clone().unwrap().to_string().to_snake_case()), | ||
proc_macro2::Span::call_site(), | ||
); | ||
let set_name = ident( | ||
&name.clone().unwrap().to_string().to_snake_case(), | ||
).unwrap(); | ||
let type_ = field.ty.clone(); | ||
|
||
let (type_segments, type_seperators) = type_segments(&type_); | ||
|
||
let default_set_fn = if type_segments[0].0 == "Option" { | ||
let mut seps = type_seperators.iter().skip(1).rev().skip(1).rev(); | ||
let mut type_vec = Vec::new(); | ||
for (seg, _) in type_segments.iter().skip(1) { | ||
type_vec.push(seg); | ||
if let Some(s) = seps.next() { | ||
type_vec.push(s); | ||
} | ||
} | ||
append_log(type_vec.clone().into_iter().join("")); | ||
let type_ = ident(&type_vec.into_iter().join("")).unwrap().to_token_stream(); | ||
|
||
quote!{ | ||
pub fn #set_name(mut self, value: impl Into<#type_>) -> #s_name #type_params { | ||
self.#name = Some(value.into()); | ||
self | ||
} | ||
} | ||
} | ||
else { | ||
quote!{ | ||
pub fn #set_name(mut self, value: impl Into<#type_>) -> #s_name #type_params { | ||
self.#name = value.into(); | ||
self | ||
} | ||
} | ||
}; | ||
|
||
let override_fn = override_set_fn(&s, &field); | ||
|
||
let set_fn = override_fn.unwrap_or(default_set_fn); | ||
|
||
quote! { | ||
pub fn #get_name(&mut self) -> &mut #type_ { | ||
&mut self.#name | ||
} | ||
#set_fn | ||
'\n' | ||
} | ||
.to_token_stream() | ||
}) | ||
.collect_vec(); | ||
|
||
quote! { | ||
'\n' | ||
impl #generics #s_name #type_params { | ||
#new | ||
|
||
#(#methods)* | ||
} | ||
} | ||
}) | ||
.collect(); | ||
|
||
let code = [Vec::from([use_]), impl_blocks] | ||
.concat() | ||
.into_iter() | ||
.map(|token| token.to_string()) | ||
.collect_vec() | ||
.join("\n") | ||
.replace("'\\n'", "\n\n"); | ||
|
||
let mut formatted_code = std::process::Command::new("rustfmt") | ||
.stdin(std::process::Stdio::piped()) | ||
.stdout(std::process::Stdio::piped()) | ||
.spawn() | ||
.unwrap(); | ||
formatted_code | ||
.stdin | ||
.take() | ||
.map(|mut s| s.write_all(code.as_bytes())); | ||
|
||
std::fs::write( | ||
"./src/objects/methods.rs", | ||
String::from_utf8_lossy(&formatted_code.wait_with_output().unwrap().stdout).to_string(), | ||
) | ||
.unwrap(); | ||
} | ||
|
||
fn override_set_fn(s: &ItemStruct, field: &Field) -> Option<TokenStream> { | ||
let s_name = &s.ident; | ||
let name = &field.ident; | ||
let type_ = &field.ty; | ||
let type_param = s | ||
.generics | ||
.type_params() | ||
.map(|t| t.ident.clone()) | ||
.collect_vec(); | ||
let type_params = if type_param.is_empty().not() { | ||
quote! { < #(#type_param),* > } | ||
} else { | ||
quote! {} | ||
}; | ||
let set_name = ident(&name.clone().unwrap().to_string().to_snake_case()).unwrap(); | ||
|
||
let (type_segments, _type_seperators) = type_segments(type_); | ||
|
||
// append_log(type_.to_token_stream().to_string()); | ||
// append_log( | ||
// type_segments | ||
// .clone() | ||
// .into_iter() | ||
// .map(|(seg, _)| seg) | ||
// .collect_vec() | ||
// .join(" | "), | ||
// ); | ||
|
||
if let Some((seg, _type_)) = type_segments.first() { | ||
// for Vec<T> | ||
if seg == "Vec" { | ||
let inner_t = &type_segments[1].1; | ||
let iterator_set_fn = quote! { | ||
pub fn #set_name<T: Into<#inner_t>>(mut self, value: impl IntoIterator<Item = T>) -> #s_name #type_params { | ||
self.#name = value.into_iter().map(Into::into).collect(); | ||
self | ||
} | ||
}; | ||
return Some(iterator_set_fn); | ||
} | ||
|
||
if seg == "Option" { | ||
// for Option<HashMap<T, U>> | ||
if type_segments[1].0 == "HashMap" { | ||
let inner_t = &type_segments[2].1; | ||
let inner_u = &type_segments[3].1; | ||
let iterator_set_fn = quote! { | ||
pub fn #set_name<T: Into<#inner_t>, U: IntoIterator<Item = (T, #inner_u)>>(mut self, value: U) -> #s_name #type_params { | ||
self.#name = Some(value.into_iter().map(|(k, v)| (k.into(), v)).collect()); | ||
self | ||
} | ||
}; | ||
return Some(iterator_set_fn); | ||
} | ||
} | ||
} | ||
|
||
None | ||
} | ||
|
||
fn type_segments(type_: &syn::Type) -> (Vec<(String, syn::Type)>, Vec<String>) { | ||
let type_segments = type_.to_token_stream().to_string(); | ||
append_log(&type_segments); | ||
let segs = type_segments | ||
.split("<") | ||
.flat_map(|seg| seg.split(",")) | ||
.flat_map(|seg| seg.split(">")) | ||
.map(|seg| seg.trim().to_string()) | ||
.filter_map(|seg| Some((seg.clone(), ident(seg.trim()).ok()?))) | ||
.collect_vec(); | ||
|
||
let mut chars = type_segments | ||
.chars() | ||
.filter(|c| [':', '<', '>', ','].contains(c)) | ||
.collect_vec(); | ||
if chars.len() % 2 != 0 { | ||
chars.push(' '); | ||
} | ||
let seps = chars | ||
.into_iter() | ||
.tuples() | ||
.fold(Vec::new(), |mut acc, (c1, c2)| { | ||
if c1 == ':' && c2 == ':' { | ||
acc.push("::".to_string()); | ||
} | ||
|
||
if ['<', '>', ','].contains(&c1) { | ||
acc.push(c1.to_string()); | ||
} | ||
if ['<', '>', ','].contains(&c2) { | ||
acc.push(c2.to_string()); | ||
} | ||
|
||
acc | ||
}); | ||
|
||
append_log(&seps); | ||
|
||
(segs, seps) | ||
} | ||
|
||
fn ident(i: &str) -> Result<syn::Type, syn::Error> { | ||
syn::parse_str(i) | ||
} | ||
|
||
fn append_log(s: impl Debug) { | ||
let mut file = std::fs::OpenOptions::new() | ||
.append(true) | ||
.open("build_logs.txt") | ||
.unwrap(); | ||
|
||
file.write_all(format!("{:#?}", s).as_bytes()).unwrap(); | ||
file.write_all(b"\n").unwrap(); | ||
} |
Oops, something went wrong.