dynamic_object_derive/
lib.rs1#![allow(non_snake_case)]
3
4use proc_macro::{TokenStream};
5use syn::{*, parse::Parse, punctuated::Punctuated};
6use std::time::UNIX_EPOCH;
7use quote::quote;
8use uuid;
9
10extern crate proc_macro;
11
12struct Parent {
13 parent: Type,
14}
15
16impl Parse for Parent {
17 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
18 let vars = Punctuated::<Type, Token![,]>::parse_terminated(input)?;
19 let parent = match vars.first() {
20 Some(p) => p,
21 None => {
22 panic!("Error: #[subclass] takes a parent(ParentT, parent_field)");
23 },
24 };
25
26 Ok(Self {
27 parent: parent.clone(),
28 })
29 }
30}
31
32struct ParentFieldName {
33 name: Option<Ident>
34}
35
36impl Parse for ParentFieldName {
37 fn parse(input: parse::ParseStream) -> Result<Self> {
38 let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
39 let vars: Vec<_> = vars.iter().collect();
40
41 let name = if vars.len() > 1 {
42 Some(vars[1].clone())
43 } else {
44 None
45 };
46 Ok(Self {
47 name
48 })
49 }
50}
51
52fn generateID(name: &Ident) -> String {
53 let now = std::time::SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
54 let id = uuid::Uuid::new_v4();
55 format!("{:?}{}{}", now, id, name.to_string())
56}
57
58fn offsetof(parent: &Type, parentField: ParentFieldName) -> __private::TokenStream2 {
59 match parentField.name {
60 Some(name) => {
61 return quote! {
62 fn offset() -> isize {
63 let this: *const Self = 0 as *const Self;
64 let parent = unsafe {
65 &((*this).#name) as *const _ as *const u8
66 };
67 parent as isize
68 }
69 }
70 },
71 None => {}
72 }
73 match *parent {
74 Type::Path(ref path) => {
75 match path.path.segments.iter().last() {
76 Some(parent) => {
77 if parent.ident.to_string() == "DynamicObjectBase" {
80 return quote! {
81 fn offset() -> isize {
82 0
83 }
84 }
85 }
86 },
87 None => {}
88 }
89 },
90 _ => panic!("Expected super class")
91 }
92 panic!("Expect parent field name in second argument of attribute");
93}
94
95#[proc_macro_attribute]
96pub fn subclass(args: TokenStream, tokens: TokenStream) -> TokenStream {
97 let argsCpy = args.clone();
98 let parse = parse_macro_input!(tokens as ItemStruct);
99 let parent = parse_macro_input!(args as Parent).parent;
100 let name = &parse.ident;
101
102 let parentField = parse_macro_input!(argsCpy as ParentFieldName);
103 let id = generateID(name);
104 let offsetof = offsetof(&parent, parentField);
105
106 let result = quote! {
107 #parse
108
109 impl dynamic_object::Class for #name {
110 type Parent = #parent;
111 const NAME:&'static str = #id;
112
113 fn isa(id: usize) -> bool {
114 id == Self::id() || <Self as dynamic_object::Class>::Parent::isa(id)
115 }
116
117 #offsetof
119
120 fn id() -> usize {
121 Self::id as *const u8 as usize
122 }
123 }
124 };
125 TokenStream::from(result)
126}
127
128#[proc_macro_attribute]
129pub fn module_name(_: TokenStream, stream: TokenStream) -> TokenStream {
130 let parse = parse_macro_input!(stream as ItemStruct);
131
132 let name = &parse.ident;
133
134 let result = quote! {
135 #parse
136
137 impl #name {
138
139 }
140 };
141 TokenStream::from(result)
142}