rust_oop/
lib.rs

1//! Macro to implement inherit
2//! 
3//! Provide <code>class</code> to cover a struct itself, it's impl and trait implements that need to inherit.
4//! To borrow as mut, see <code>def_as_mut</code>
5//! 
6
7use std::{collections::HashMap, sync::Mutex};
8
9use parse_class::parse_class;
10use proc_macro::TokenStream;
11use lazy_static::lazy_static;
12use quote::quote;
13
14mod info;
15mod parse_class;
16mod parse_expr;
17use info::ClassInfo;
18
19use crate::info::Serializable;
20lazy_static!{
21    static ref CLASSES: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
22}
23
24/// 
25/// need to wrap struct and implements.
26/// 
27/// using <code>#\[keep\]</code> for method make that method keep in the original impl.
28/// 
29/// methods without <code>#\[keep\]</code> will be put into trait <code>\_\_XXX\_\_</code>.
30/// 
31/// and macro will auto generate a <code>new</code> function which return <code>Pin<Box<Self>></code>.
32/// 
33/// expression in the method will be converted.
34/// 
35/// instead of use <code>self</code>, using <code>this</code>.
36/// 
37/// <code>self</code> will be convert to use <code>unsafe { self.\_\_real\_\_.as_ref().unwrap() }</code>.
38/// 
39/// <code>self_mut</code> will be convert to use <code>unsafe { self.\_\_real\_\_.as_mut().unwrap() }</code>.
40/// 
41/// <code>\_super</code> will be convert to use <code>self.\_\_prototype\_\_</code>.
42/// 
43/// <code>\_super_mut</code> will be convert to use <code>unsafe { self.\_\_prototype\_\_.as_mut().get_unchecked_mut() }</code>.
44/// 
45/// 
46/// An example to use this macro:
47/// ```rust
48/// class! {
49///     struct Example {
50///         data: String    
51///     }
52///     impl Example {
53///         #[keep]
54///         fn with() -> Pin<Box<Self>> where Self: Sized {
55///             Self::new("example".to_string())
56///         }
57///         
58///         fn set_data(&mut self, data: String) {
59///             this.data = data;
60///         }
61/// 
62///         fn get_data(&self) -> String {
63///             this.data.clone()
64///         }
65///     }
66///     impl Something for Example {
67///         //do something
68///     }
69/// }
70/// class! {
71///     extends Example;
72///     struct Sub { }
73///     impl Sub { }
74/// }
75/// ```
76/// the struct will become:
77/// ```rust
78/// struct Example {
79///     __real__: *mut dyn __Example__,
80///     _pinned: ::std::marker::PhantomPinned,
81///     data: String
82/// }
83/// struct Sub {
84///     __prototype__: ::std::pin::Pin<Box<Example>>
85///     __real__: *mut dyn __Sub__,
86///     _pinned: ::std::marker::PhantomPinned,
87/// }
88/// ```
89/// 
90
91#[proc_macro]
92pub fn class(token: TokenStream) -> TokenStream {
93    let option =syn::parse(token);
94    if option.is_err() {
95        return option.err().unwrap().into_compile_error().into()
96    }
97    let mut class_info: ClassInfo = option.unwrap();
98    let class_info = &mut class_info;
99
100    parse_class(class_info);
101
102    let _struct = class_info._struct.as_ref().unwrap();
103    if class_info._impl.is_none() {
104        panic!("there is no impl for this struct");
105    }
106    let _impl = class_info._impl.as_ref().unwrap();
107    let _trait_impl = class_info._trait_impl.values();
108
109    let name = class_info.get_ident();
110    let _trait = class_info.real_trait.as_ref().unwrap();
111    CLASSES.lock().as_mut().unwrap().insert(name.to_string(), class_info.serialize());
112    
113    quote!{
114        #_trait
115        #_struct
116        #_impl
117        #(#_trait_impl)*
118    }.into()
119}
120
121
122/// this macro will define macro <code>as_mut</code>
123/// 
124/// example:
125/// ```rust
126/// def_as_mut!();
127/// 
128/// fn main() {
129///     let mut example = Sub::new("data".to_string());
130///     as_mut!(example).set_data("modified".to_string());
131///     assert_eq!(example.get_data(), "modified".to_string());
132/// }
133/// ```
134
135
136#[proc_macro]
137pub fn def_as_mut(_: TokenStream) -> TokenStream {
138    quote!{
139        macro_rules! as_mut {
140            ($tt: tt) => {
141                unsafe {Pin::get_unchecked_mut( $tt .as_mut())}
142            };
143        }
144    }.into()
145}