Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- extern crate proc_macro;
- extern crate syn;
- #[macro_use]
- extern crate quote;
- use proc_macro::TokenStream;
- #[derive(Debug)]
- struct StructMeta {
- name: String,
- fields: Vec<Field>
- }
- #[derive(Debug)]
- struct Field {
- name: String,
- kind: String,
- }
- /// Reads through the derive AST tree and returns the structures field name and type information.
- fn read_struct(ast: &syn::DeriveInput) -> StructMeta {
- let mut result = StructMeta {
- name: ast.ident.clone().to_string(),
- fields: vec![]
- };
- if let syn::Body::Struct(ref _struct) = ast.body {
- match _struct {
- syn::VariantData::Struct(fields) => {
- for field in fields {
- let name = field.ident.clone().unwrap().to_string();
- match field.ty {
- syn::Ty::Path(ref _opt, ref path) => {
- let kind = path.segments[0].ident.to_string();
- result.fields.push({
- Field { name, kind }
- });
- },
- _ => panic!(format!("Unable to read field '{}'", name))
- }
- }
- },
- _ => panic!("Interpolate is only defined for structs"),
- };
- };
- result
- }
- fn build_new_function(s: &StructMeta) -> quote::Tokens {
- let initializers = s.fields.iter().map(|field| {
- match field.kind.as_ref() {
- "Vector4" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector4::new(0.0, 0.0, 0.0, 0.0)
- }
- },
- "Vector3" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector3::new(0.0, 0.0, 0.0)
- }
- },
- "Vector2" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector2::new(0.0, 0.0)
- }
- },
- _ => panic!(format!("Cannot interpolate type '{}'", field.kind))
- }
- });
- let name = quote::Ident::from(s.name.clone());
- quote!(
- fn new() -> #name {
- #name {
- #( #initializers ),*
- }
- }
- )
- }
- fn build_correct_function(s: &StructMeta) -> quote::Tokens {
- let initializers = s.fields.iter().map(|field| {
- match field.kind.as_ref() {
- "Vector4" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector4::new(
- v.#field_name.x / w,
- v.#field_name.y / w,
- v.#field_name.z / w,
- v.#field_name.w / w,
- )
- }
- },
- "Vector3" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector3::new(
- v.#field_name.x / w,
- v.#field_name.y / w,
- v.#field_name.z / w,
- )
- }
- },
- "Vector2" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector2::new(
- v.#field_name.x / w,
- v.#field_name.y / w,
- )
- }
- },
- _ => panic!(format!("Cannot interpolate type '{}'", field.kind))
- }
- });
- let name = quote::Ident::from(s.name.clone());
- quote!(
- fn correct(v: &#name, w: &f32) -> #name {
- #name {
- #( #initializers ),*
- }
- }
- )
- }
- fn build_interpolate_function(s: &StructMeta) -> quote::Tokens {
- let initializers = s.fields.iter().map(|field| {
- match field.kind.as_ref() {
- "Vector4" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector4::new(
- ((w0 * v0.#field_name.x) + (w1 * v1.#field_name.x) + (w2 * v2.#field_name.x)) / w,
- ((w0 * v0.#field_name.y) + (w1 * v1.#field_name.y) + (w2 * v2.#field_name.y)) / w,
- ((w0 * v0.#field_name.z) + (w1 * v1.#field_name.z) + (w2 * v2.#field_name.z)) / w,
- ((w0 * v0.#field_name.w) + (w1 * v1.#field_name.w) + (w2 * v2.#field_name.w)) / w,
- )
- }
- },
- "Vector3" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector3::new(
- ((w0 * v0.#field_name.x) + (w1 * v1.#field_name.x) + (w2 * v2.#field_name.x)) / w,
- ((w0 * v0.#field_name.y) + (w1 * v1.#field_name.y) + (w2 * v2.#field_name.y)) / w,
- ((w0 * v0.#field_name.z) + (w1 * v1.#field_name.z) + (w2 * v2.#field_name.z)) / w,
- )
- }
- },
- "Vector2" => {
- let field_name = quote::Ident::from(field.name.clone());
- quote! {
- #field_name: Vector2::new(
- ((w0 * v0.#field_name.x) + (w1 * v1.#field_name.x) + (w2 * v2.#field_name.x)) / w,
- ((w0 * v0.#field_name.y) + (w1 * v1.#field_name.y) + (w2 * v2.#field_name.y)) / w,
- )
- }
- },
- _ => panic!(format!("Cannot interpolate type '{}'", field.kind))
- }
- });
- let name = quote::Ident::from(s.name.clone());
- quote!(
- fn interpolate(v0: &#name, v1: &#name, v2: &#name, w0: &f32, w1: &f32, w2: &f32, w: &f32) -> #name {
- #name {
- #( #initializers ),*
- }
- }
- )
- }
- fn impl_interpolate(s: &StructMeta) -> quote::Tokens {
- let kind = quote::Ident::from(s.name.clone());
- let new_function = build_new_function(&s);
- let correct_function = build_correct_function(&s);
- let interpolate_function = build_interpolate_function(&s);
- let implementation = quote! {
- impl Interpolate for #kind {
- #new_function
- #correct_function
- #interpolate_function
- }
- };
- // println!("{}", implementation);
- implementation
- }
- #[proc_macro_derive(Interpolate)]
- pub fn interpolate(input: TokenStream) -> TokenStream {
- // Construct a string representation of the type definition
- let s = input.to_string();
- // Parse the string representation
- let ast = syn::parse_derive_input(&s).unwrap();
- // Read struct metadata
- let meta = read_struct(&ast);
- // Generate implementation
- let gen = impl_interpolate(&meta);
- // Return the generated impl
- gen.parse().unwrap()
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement