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}