179 lines
5.5 KiB
Rust
179 lines
5.5 KiB
Rust
|
use quote::quote;
|
||
|
use syn::{Path, Ident};
|
||
|
use proc_macro2::Span;
|
||
|
|
||
|
#[derive(Default)]
|
||
|
pub(crate) struct VecWrapper;
|
||
|
|
||
|
#[allow(dead_code)]
|
||
|
impl VecWrapper {
|
||
|
fn vec_size(&self, wrapper_ident: &Ident) -> usize {
|
||
|
let name = wrapper_ident.to_string();
|
||
|
name[name.len() - 1..].parse::<usize>()
|
||
|
.or_else(|_| name[name.len() - 2.. name.len() - 1].parse::<usize>())
|
||
|
.expect("Failure to grab Vec size from ident name")
|
||
|
}
|
||
|
|
||
|
/// Returns the token stream of the type of the axis of the vec (Vec2 vs IVec2 vs I64Vec2, etc.)
|
||
|
fn vec_axis_type(&self, wrapper_ident: &Ident) -> &'static str {
|
||
|
let name = wrapper_ident.to_string();
|
||
|
let start = name.find("Vec").unwrap();
|
||
|
|
||
|
let before = &name[start - 1.. start];
|
||
|
match before {
|
||
|
"D" => return "f64",
|
||
|
"I" => return "i32",
|
||
|
"U" => return "u32",
|
||
|
"B" => return "bool",
|
||
|
_ => {},
|
||
|
}
|
||
|
//println!("before is {before}");
|
||
|
|
||
|
let three_before = &name[start - 3.. start];
|
||
|
match three_before {
|
||
|
"I64" => return "i64",
|
||
|
"U64" => return "u64",
|
||
|
_ => {},
|
||
|
}
|
||
|
//println!("three before is {three_before}");
|
||
|
|
||
|
"f32"
|
||
|
}
|
||
|
|
||
|
pub fn to_field_tokens(&self, wrapped_path: &Path, wrapper_ident: &Ident) -> proc_macro2::TokenStream {
|
||
|
let mut consts = vec![quote!(ZERO), quote!(ONE), quote!(X),
|
||
|
quote!(Y), ]; // , quote!(AXES)
|
||
|
|
||
|
let vec_size = self.vec_size(wrapper_ident);
|
||
|
let axis_type_name = self.vec_axis_type(wrapper_ident);
|
||
|
|
||
|
if axis_type_name.contains("b") {
|
||
|
return quote! {
|
||
|
builder.field("FALSE", #wrapper_ident(#wrapped_path::FALSE));
|
||
|
builder.field("TRUE", #wrapper_ident(#wrapped_path::TRUE));
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if vec_size >= 3 {
|
||
|
consts.push(quote!(Z));
|
||
|
|
||
|
// no negative numbers for unsigned vecs
|
||
|
if !axis_type_name.contains("u") {
|
||
|
consts.push(quote!(NEG_Z));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if vec_size == 4 {
|
||
|
consts.push(quote!(W));
|
||
|
|
||
|
// no negative numbers for unsigned vecs
|
||
|
if !axis_type_name.contains("u") {
|
||
|
consts.push(quote!(NEG_W));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// no negative numbers for unsigned vecs
|
||
|
if !axis_type_name.contains("u") {
|
||
|
consts.push(quote!(NEG_X));
|
||
|
consts.push(quote!(NEG_Y));
|
||
|
consts.push(quote!(NEG_ONE));
|
||
|
}
|
||
|
|
||
|
if axis_type_name.contains("f") {
|
||
|
consts.push(quote!(NAN))
|
||
|
}
|
||
|
|
||
|
let const_tokens = consts.iter().map(|cnst| {
|
||
|
let const_name = cnst.to_string();
|
||
|
|
||
|
quote! {
|
||
|
builder.field(#const_name, #wrapper_ident(#wrapped_path::#cnst));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
quote! {
|
||
|
#(#const_tokens)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn to_method_tokens(&self, wrapper_ident: &Ident) -> proc_macro2::TokenStream {
|
||
|
let vec_size = self.vec_size(wrapper_ident);
|
||
|
let axis_type_name = self.vec_axis_type(wrapper_ident);
|
||
|
// methods that only some vecs have
|
||
|
let mut optional_methods = vec![];
|
||
|
|
||
|
// boolean vectors dont have much :(
|
||
|
if axis_type_name.contains("b") {
|
||
|
return quote!(); // TODO: all, any, bitmask, splat
|
||
|
}
|
||
|
|
||
|
if axis_type_name.contains("f") {
|
||
|
let type_id = Ident::new(axis_type_name, Span::call_site());
|
||
|
|
||
|
optional_methods.push(
|
||
|
quote! {
|
||
|
builder.method("clamp_length",
|
||
|
|_, this, (min, max): (#type_id, #type_id)| {
|
||
|
Ok(#wrapper_ident(this.clamp_length(min, max)))
|
||
|
});
|
||
|
|
||
|
builder.method("abs_diff_eq",
|
||
|
|_, this, (rhs, max_abs_diff): (#wrapper_ident, #type_id)| {
|
||
|
Ok(this.abs_diff_eq(rhs.0, max_abs_diff))
|
||
|
});
|
||
|
|
||
|
builder.method("ceil",
|
||
|
|_, this, (): ()| {
|
||
|
Ok(#wrapper_ident(this.ceil()))
|
||
|
});
|
||
|
}
|
||
|
);
|
||
|
|
||
|
if vec_size != 4 {
|
||
|
optional_methods.push(
|
||
|
quote! {
|
||
|
builder.method("angle_between",
|
||
|
|_, this, (rhs,): (#wrapper_ident,)| {
|
||
|
Ok(this.angle_between(rhs.0))
|
||
|
});
|
||
|
}
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !axis_type_name.contains("u") {
|
||
|
optional_methods.push(
|
||
|
quote! {
|
||
|
builder.method("abs",
|
||
|
|_, this, (): ()| {
|
||
|
Ok(#wrapper_ident(this.abs()))
|
||
|
});
|
||
|
}
|
||
|
)
|
||
|
}
|
||
|
|
||
|
let optional_methods_iter = optional_methods.iter();
|
||
|
quote! {
|
||
|
|
||
|
|
||
|
builder.method("clamp",
|
||
|
|_, this, (min, max): (#wrapper_ident, #wrapper_ident)| {
|
||
|
Ok(#wrapper_ident(this.clamp(min.0, max.0)))
|
||
|
});
|
||
|
|
||
|
// TODO: Not all Vecs have this
|
||
|
/* builder.method("clamp_length",
|
||
|
|_, this, (min, max): (f32, f32)| {
|
||
|
Ok(#wrapper_ident(this.clamp_length(min, max)))
|
||
|
}); */
|
||
|
|
||
|
|
||
|
builder.method("to_array",
|
||
|
|_, this, (): ()| {
|
||
|
Ok(this.to_array())
|
||
|
});
|
||
|
|
||
|
#(#optional_methods_iter)*
|
||
|
}
|
||
|
}
|
||
|
}
|