Advertisement
Guest User

Untitled

a guest
Sep 7th, 2019
257
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 7.14 KB | None | 0 0
  1. extern crate proc_macro;
  2. extern crate syn;
  3. #[macro_use]
  4. extern crate quote;
  5.  
  6. use proc_macro::TokenStream;
  7.  
  8. #[derive(Debug)]
  9. struct StructMeta {
  10.     name:   String,
  11.     fields: Vec<Field>
  12. }
  13. #[derive(Debug)]
  14. struct Field {
  15.     name: String,
  16.     kind: String,
  17. }
  18.  
  19. /// Reads through the derive AST tree and returns the structures field name and type information.
  20. fn read_struct(ast: &syn::DeriveInput) -> StructMeta {
  21.     let mut result = StructMeta {
  22.         name:   ast.ident.clone().to_string(),
  23.         fields: vec![]
  24.     };
  25.     if let syn::Body::Struct(ref _struct) = ast.body {
  26.         match _struct {
  27.             syn::VariantData::Struct(fields) => {
  28.                 for field in fields {
  29.                     let name = field.ident.clone().unwrap().to_string();
  30.                     match field.ty {
  31.                         syn::Ty::Path(ref _opt, ref path) => {
  32.                             let kind = path.segments[0].ident.to_string();
  33.                             result.fields.push({
  34.                                 Field { name, kind }
  35.                             });
  36.                         },
  37.                         _ => panic!(format!("Unable to read field '{}'", name))
  38.                     }
  39.                 }
  40.             },
  41.             _ => panic!("Interpolate is only defined for structs"),
  42.         };
  43.     };
  44.     result
  45. }
  46.  
  47. fn build_new_function(s: &StructMeta) -> quote::Tokens {
  48.     let initializers = s.fields.iter().map(|field| {
  49.         match field.kind.as_ref() {
  50.             "Vector4" => {
  51.                 let field_name = quote::Ident::from(field.name.clone());
  52.                 quote! {
  53.                     #field_name: Vector4::new(0.0, 0.0, 0.0, 0.0)
  54.                 }
  55.             },
  56.             "Vector3" => {
  57.                 let field_name = quote::Ident::from(field.name.clone());
  58.                 quote! {
  59.                     #field_name: Vector3::new(0.0, 0.0, 0.0)
  60.                 }
  61.             },
  62.             "Vector2" => {
  63.                 let field_name = quote::Ident::from(field.name.clone());
  64.                 quote! {
  65.                     #field_name: Vector2::new(0.0, 0.0)
  66.                 }
  67.             },
  68.             _ => panic!(format!("Cannot interpolate type '{}'", field.kind))
  69.         }
  70.     });
  71.     let name = quote::Ident::from(s.name.clone());
  72.     quote!(
  73.         fn new() -> #name {
  74.             #name {
  75.                 #( #initializers ),*
  76.             }
  77.         }
  78.     )
  79. }
  80.  
  81. fn build_correct_function(s: &StructMeta) -> quote::Tokens {
  82.     let initializers = s.fields.iter().map(|field| {
  83.         match field.kind.as_ref() {
  84.             "Vector4" => {
  85.                 let field_name = quote::Ident::from(field.name.clone());
  86.                 quote! {
  87.                     #field_name: Vector4::new(
  88.                         v.#field_name.x / w,
  89.                         v.#field_name.y / w,
  90.                         v.#field_name.z / w,
  91.                         v.#field_name.w / w,
  92.                     )
  93.                 }
  94.             },
  95.             "Vector3" => {
  96.                 let field_name = quote::Ident::from(field.name.clone());
  97.                 quote! {
  98.                     #field_name: Vector3::new(
  99.                         v.#field_name.x / w,
  100.                         v.#field_name.y / w,
  101.                         v.#field_name.z / w,
  102.                     )
  103.                 }
  104.             },
  105.             "Vector2" => {
  106.                 let field_name = quote::Ident::from(field.name.clone());
  107.                 quote! {
  108.                     #field_name: Vector2::new(
  109.                         v.#field_name.x / w,
  110.                         v.#field_name.y / w,
  111.                     )
  112.                 }
  113.             },
  114.             _ => panic!(format!("Cannot interpolate type '{}'", field.kind))
  115.         }
  116.     });
  117.     let name = quote::Ident::from(s.name.clone());
  118.     quote!(
  119.         fn correct(v: &#name, w: &f32)  -> #name {
  120.             #name {
  121.                 #( #initializers ),*
  122.             }
  123.         }
  124.     )
  125. }
  126.  
  127. fn build_interpolate_function(s: &StructMeta) -> quote::Tokens {
  128.     let initializers = s.fields.iter().map(|field| {
  129.         match field.kind.as_ref() {
  130.             "Vector4" => {
  131.                 let field_name = quote::Ident::from(field.name.clone());
  132.                 quote! {
  133.                     #field_name: Vector4::new(
  134.                         ((w0 * v0.#field_name.x) + (w1 * v1.#field_name.x) + (w2 * v2.#field_name.x)) / w,
  135.                         ((w0 * v0.#field_name.y) + (w1 * v1.#field_name.y) + (w2 * v2.#field_name.y)) / w,
  136.                         ((w0 * v0.#field_name.z) + (w1 * v1.#field_name.z) + (w2 * v2.#field_name.z)) / w,
  137.                         ((w0 * v0.#field_name.w) + (w1 * v1.#field_name.w) + (w2 * v2.#field_name.w)) / w,
  138.                     )
  139.                 }
  140.             },
  141.             "Vector3" => {
  142.                 let field_name = quote::Ident::from(field.name.clone());
  143.                 quote! {
  144.                     #field_name: Vector3::new(
  145.                         ((w0 * v0.#field_name.x) + (w1 * v1.#field_name.x) + (w2 * v2.#field_name.x)) / w,
  146.                         ((w0 * v0.#field_name.y) + (w1 * v1.#field_name.y) + (w2 * v2.#field_name.y)) / w,
  147.                         ((w0 * v0.#field_name.z) + (w1 * v1.#field_name.z) + (w2 * v2.#field_name.z)) / w,
  148.                     )
  149.                 }
  150.             },
  151.             "Vector2" => {
  152.                 let field_name = quote::Ident::from(field.name.clone());
  153.                 quote! {
  154.                     #field_name: Vector2::new(
  155.                         ((w0 * v0.#field_name.x) + (w1 * v1.#field_name.x) + (w2 * v2.#field_name.x)) / w,
  156.                         ((w0 * v0.#field_name.y) + (w1 * v1.#field_name.y) + (w2 * v2.#field_name.y)) / w,
  157.                     )
  158.                 }
  159.             },
  160.             _ => panic!(format!("Cannot interpolate type '{}'", field.kind))
  161.         }
  162.     });
  163.     let name = quote::Ident::from(s.name.clone());
  164.     quote!(
  165.         fn interpolate(v0: &#name, v1: &#name, v2: &#name, w0: &f32, w1: &f32, w2: &f32, w:  &f32) -> #name {
  166.             #name {
  167.                 #( #initializers ),*
  168.             }
  169.         }
  170.     )
  171. }
  172.  
  173. fn impl_interpolate(s: &StructMeta) -> quote::Tokens {
  174.     let kind                 = quote::Ident::from(s.name.clone());
  175.     let new_function         = build_new_function(&s);
  176.     let correct_function     = build_correct_function(&s);
  177.     let interpolate_function = build_interpolate_function(&s);
  178.     let implementation       = quote! {
  179.         impl Interpolate for #kind {
  180.             #new_function
  181.             #correct_function
  182.             #interpolate_function
  183.         }
  184.     };
  185.     // println!("{}", implementation);
  186.     implementation
  187. }
  188.  
  189. #[proc_macro_derive(Interpolate)]
  190. pub fn interpolate(input: TokenStream) -> TokenStream {
  191.     // Construct a string representation of the type definition
  192.     let s = input.to_string();
  193.     // Parse the string representation
  194.     let ast = syn::parse_derive_input(&s).unwrap();
  195.     // Read struct metadata
  196.     let meta = read_struct(&ast);
  197.     // Generate implementation
  198.     let gen = impl_interpolate(&meta);
  199.     // Return the generated impl
  200.     gen.parse().unwrap()
  201. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement