oop_inheritance_proc/
lib.rs

1#![feature(proc_macro_diagnostic)]
2
3// use std::iter::FromIterator;
4use proc_macro::TokenStream;
5// use proc_macro2::Span;
6use quote::{quote, ToTokens};
7// use quote::{quote, quote_spanned};
8use syn::parse::{Parse, ParseStream, Result};
9use syn::punctuated::Punctuated;
10use syn::token::{Comma, Pub};
11// use syn::spanned::Spanned;
12use syn::{parse_macro_input, Ident, Token, Path, Visibility, Attribute, Type, Expr, Generics, FnArg, Stmt, braced, WhereClause, parenthesized};
13
14struct ClassExtends {
15    /// Types in descending order
16    type_sequence: Vec<Path>,
17    component_type: Path,
18    oop_inheritance_crate: Option<proc_macro2::TokenStream>,
19}
20
21fn parse_full_qualified_id(input: ParseStream) -> Result<Path> {
22    Ok(Path::parse_mod_style(input)?)
23}
24
25impl Parse for ClassExtends {
26    fn parse(input: ParseStream) -> Result<Self> {
27        let mut type_sequence: Vec<Path> = vec![];
28        type_sequence.push(parse_full_qualified_id(input)?);
29
30        // Super types in descending order
31        input.parse::<Token![<]>()?;
32        type_sequence.push(parse_full_qualified_id(input)?);
33        while input.peek(Token![<]) {
34            input.parse::<Token![<]>()?;
35            type_sequence.push(parse_full_qualified_id(input)?);
36        }
37
38        // Component type
39        input.parse::<Token![,]>()?;
40        input.parse::<Token![use]>()?;
41        let component_type = parse_full_qualified_id(input)?;
42
43        let mut oop_inheritance_crate = None;
44        if input.peek(Token![,]) {
45            input.parse::<Token![,]>()?;
46            oop_inheritance_crate = Some(parse_full_qualified_id(input)?.to_token_stream());
47        }
48
49        Ok(ClassExtends {
50            type_sequence,
51            component_type,
52            oop_inheritance_crate,
53        })
54    }
55}
56
57/// Operation used when defining classes. Using `class_extends!`,
58/// the traits `Deref`, `Clone`, `PartialEq`, `Eq`, `Hash`, `AsRef`, `From`
59/// and `TryFrom` are implemented to inherit characteristics from
60/// ascending classes.
61/// 
62/// This assumes that the class is a struct of the form `struct S(o);`.
63/// 
64/// # Syntax
65/// 
66/// The syntax takes a sequence of types in descending order followed by
67/// an identifying Component type:
68/// 
69/// ```ignore
70/// class_extends!(Subtype < Super1 < SuperN < Node, use SubtypeComponent);
71/// ```
72/// 
73/// # Notes
74/// 
75/// This operation is for internal use by `oop_inheritance`. To define classes,
76/// use simply the `class!` syntax.
77/// 
78#[proc_macro]
79pub fn class_extends(input: TokenStream) -> TokenStream {
80    let ClassExtends { type_sequence, component_type, oop_inheritance_crate } = parse_macro_input!(input as ClassExtends);
81    let subtype = type_sequence[0].clone();
82    let super_type = type_sequence[1].clone();
83    let oop_inheritance_crate = oop_inheritance_crate.unwrap_or(quote! {::oop_inheritance});
84
85    let mut expanded = TokenStream::new();
86
87    expanded.extend::<TokenStream>(quote! {
88        impl ::std::ops::Deref for #subtype { type Target = #super_type; fn deref(&self) -> &Self::Target { &self.0 } }
89        impl Clone for #subtype { fn clone(&self) -> Self { Self(self.0.clone()) } }
90        impl PartialEq for #subtype { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } }
91        impl Eq for #subtype {}
92        impl ::std::hash::Hash for #subtype { fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) { self.0.hash(state); } }
93
94        // AsRef<SuperType> for Subtype and AsRef<Subtype> for Subtype
95        impl AsRef<#super_type> for #subtype { fn as_ref(&self) -> &#super_type { &self.0 } }
96        impl AsRef<#subtype> for #subtype { fn as_ref(&self) -> &Self { self } }
97
98        // From<Subtype> for SuperType
99        impl From<#subtype> for #super_type { fn from(value: #subtype) -> Self { value.0.clone() } }
100
101        // TryFrom<SuperType> for Subtype
102        impl TryFrom<#super_type> for #subtype { type Error = #oop_inheritance_crate::ClassError; fn try_from(value: #super_type) -> Result<Self, Self::Error> { if value.has::<#component_type>() { Ok(#subtype(value.clone())) } else { Err(#oop_inheritance_crate::ClassError::new("Type conversion failed")) } } }
103    }.into());
104
105    // Indirect super types
106    for super_type in &type_sequence[2..] {
107        expanded.extend::<TokenStream>(quote! {
108            impl AsRef<#super_type> for #subtype { fn as_ref(&self) -> &#super_type { self.0.as_ref() } }
109            impl From<#subtype> for #super_type { fn from(value: #subtype) -> Self { #super_type::from(value.0) } }
110            impl TryFrom<#super_type> for #subtype { type Error = #oop_inheritance_crate::ClassError; fn try_from(value: #super_type) -> Result<Self, Self::Error> { if value.has::<#component_type>() { Ok(#subtype(value.try_into()?)) } else { Err(#oop_inheritance_crate::ClassError::new("Type conversion failed")) } } }
111        }.into());
112    }
113
114    expanded
115}
116
117struct Class {
118    oop_inheritance_crate: Option<proc_macro2::TokenStream>,
119    attributes: Vec<Attribute>,
120    visibility: Visibility,
121    name: Ident,
122    inherited: Vec<Path>,
123    fields: Vec<ClassField>,
124    constructor: ClassConstructor,
125}
126
127/// A field stores a `RwLock` inside the struct.
128struct ClassField {
129    attributes: Vec<Attribute>,
130    visibility: Visibility,
131    is_reference: bool,
132    name: Ident,
133    type_annotation: Type,
134    default_value: Expr,
135}
136
137struct ClassConstructor {
138    attributes: Vec<Attribute>,
139    visibility: Visibility,
140    generics: Generics,
141    inputs: Punctuated<FnArg, Comma>,
142    super_arguments: Punctuated<Expr, Comma>,
143    statements: Vec<Stmt>,
144}
145
146impl Parse for Class {
147    fn parse(input: ParseStream) -> Result<Self> {
148        let mut oop_inheritance_crate = None;
149        if input.peek(Token![use]) {
150            oop_inheritance_crate = Some(parse_class_oop_inheritance_crate_ref(input)?.to_token_stream());
151        }
152
153        let attributes = Attribute::parse_outer(input)?;
154        let visibility = input.parse::<Visibility>()?;
155 
156        input.parse::<Token![struct]>()?;
157 
158        let name = input.parse::<Ident>()?;
159        input.parse::<Token![:]>()?;
160
161        // Inherited
162        let mut inherited = vec![];
163        inherited.push(Path::parse_mod_style(input)?);
164        if input.peek(Token![<]) {
165            input.parse::<Token![<]>()?;
166            inherited.push(Path::parse_mod_style(input)?);
167        }
168
169        let mut fields = vec![];
170        let braced_content;
171        let _ = braced!(braced_content in input);
172
173        while !braced_content.is_empty() {
174            fields.push(parse_class_field(&braced_content)?);
175            if braced_content.peek(Token![,]) {
176                braced_content.parse::<Token![,]>()?;
177            } else {
178                break;
179            }
180        }
181
182        let mut constructor = ClassConstructor {
183            attributes: vec![],
184            visibility: Visibility::Public(Pub::default()),
185            generics: Generics::default(),
186            inputs: Punctuated::new(),
187            super_arguments: Punctuated::new(),
188            statements: vec![],
189        };
190
191        if !input.is_empty() {
192            constructor = parse_class_constructor(input)?;
193        }
194
195        Ok(Class {
196            oop_inheritance_crate,
197            attributes,
198            visibility,
199            name,
200            inherited,
201            fields,
202            constructor,
203        })
204    }
205}
206
207fn parse_class_field(input: ParseStream) -> Result<ClassField> {
208    let attributes = Attribute::parse_outer(input)?;
209    let visibility = input.parse::<Visibility>()?;
210    let is_reference = if input.peek(Token![ref]) {
211        input.parse::<Token![ref]>()?;
212        true
213    } else {
214        false
215    };
216    let name = input.parse::<Ident>()?;
217    input.parse::<Token![:]>()?;
218    let type_annotation = input.parse::<Type>()?;
219    input.parse::<Token![=]>()?;
220    let default_value = input.parse::<Expr>()?;
221
222    Ok(ClassField {
223        attributes,
224        visibility,
225        is_reference,
226        name,
227        type_annotation,
228        default_value,
229    })
230}
231
232fn parse_class_constructor(input: ParseStream) -> Result<ClassConstructor> {
233    let attributes = Attribute::parse_outer(input)?;
234    let visibility = input.parse::<Visibility>()?;
235    input.parse::<Token![fn]>()?;
236    let id = input.parse::<Ident>()?;
237    if id.to_string() != "constructor" {
238        id.span().unwrap().error("Identifier must be equals \"constructor\"").emit();
239    }
240    let mut generics = input.parse::<Generics>()?;
241
242    let parens_content;
243    parenthesized!(parens_content in input);
244    let inputs = parens_content.parse_terminated(FnArg::parse, Comma)?;
245
246    generics.where_clause = if input.peek(Token![where]) { Some(input.parse::<WhereClause>()?) } else { None };
247
248    let braced_content;
249    let _ = braced!(braced_content in input);
250    braced_content.parse::<Token![super]>()?;
251
252    let paren_content;
253    let _ = parenthesized!(paren_content in braced_content);
254    let super_arguments = paren_content.parse_terminated(Expr::parse, Comma)?;
255    braced_content.parse::<Token![;]>()?;
256
257    let mut statements = vec![];
258    while !braced_content.is_empty() {
259        statements.push(braced_content.parse::<Stmt>()?);
260    }
261
262    Ok(ClassConstructor {
263        attributes,
264        visibility,
265        generics,
266        inputs,
267        super_arguments,
268        statements,
269    })
270}
271
272fn parse_class_oop_inheritance_crate_ref(input: ParseStream) -> Result<Path> {
273    input.parse::<Token![use]>()?;
274    let id = input.parse::<Ident>()?;
275    if id.to_string() != "oop_inheritance" {
276        id.span().unwrap().error("Identifier must be equals \"oop_inheritance\"").emit();
277    }
278    input.parse::<Token![=]>()?;
279    let path = Path::parse_mod_style(input)?;
280    input.parse::<Token![;]>()?;
281    Ok(path)
282}
283
284/// Defines a class.
285/// 
286/// # Syntax
287/// 
288/// ```ignore
289/// use oop_inheritance::Node;
290///
291/// class! {
292///     struct MyClass: SuperClass1 < SuperClassN < Node {
293///         // fn x() -> f64
294///         // fn set_x(x: f64) -> Self
295///         x: f64 = 0.0,
296///         // fn y() -> Arc<f64>
297///         // fn set_y(y: Arc<f64>) -> Self
298///         ref y: f64 = 0.0,
299///     }
300///     // fn new() -> Self
301///     fn constructor() {
302///         super();
303///     }
304/// }
305/// ```
306/// 
307/// # Topmost super class
308/// 
309/// The topmost super class of a class defined by `class!`
310/// must be `oop_inheritance::Node`; otherwise it is undefined behavior.
311/// 
312/// # Reference parameter
313/// 
314/// If it is desired to receive a parameter as a specific class
315/// or any subclass, take a parameter implementing `AsRef<C>`:
316/// 
317/// ```ignore
318/// fn my_function(object: impl AsRef<MyClass>) {
319///     let object = object.as_ref();
320///     // object: &MyClass
321/// }
322/// ```
323#[proc_macro]
324pub fn class(input: TokenStream) -> TokenStream {
325    let Class {
326        oop_inheritance_crate, attributes, visibility, name, inherited, fields,
327        constructor
328    } = parse_macro_input!(input as Class);
329
330    let super_type = inherited[0].clone();
331    let component_name = Ident::new(&(name.to_string() + "Component"), name.span().clone());
332    let oop_inheritance_crate = oop_inheritance_crate.unwrap_or(quote! {::oop_inheritance});
333
334    let mut expanded = TokenStream::new();
335
336    let mut constructor_tokens = proc_macro2::TokenStream::new();
337    {
338        let ClassConstructor {
339            attributes,
340            visibility,
341            generics,
342            inputs,
343            super_arguments,
344            statements,
345        } = constructor;
346
347        let mut generics_p = proc_macro2::TokenStream::new();
348        let mut generics_w = proc_macro2::TokenStream::new();
349        if !generics.params.is_empty() {
350            let param_seq = generics.params;
351            generics_p.extend::<proc_macro2::TokenStream>(quote! { <#param_seq> }.try_into().unwrap());
352        }
353        if let Some(w) = generics.where_clause {
354            generics_w.extend::<proc_macro2::TokenStream>(quote! { #w }.try_into().unwrap());
355        }
356
357        constructor_tokens.extend::<proc_macro2::TokenStream>(quote! {
358            #(#attributes)*
359            #visibility fn new #generics_p (#inputs) -> Self #generics_w {
360                let this = Self(#super_type::new(#super_arguments).set(#component_name::default()).try_into().unwrap());
361                #(#statements)*
362                this
363            }
364        }.try_into().unwrap());
365    }
366
367    let mut component_fields = proc_macro2::TokenStream::new();
368    let mut component_field_defaults = proc_macro2::TokenStream::new();
369    let mut field_methods = proc_macro2::TokenStream::new();
370
371    for field in fields {
372        let ClassField {
373            attributes,
374            visibility,
375            is_reference,
376            name,
377            type_annotation,
378            default_value,
379        } = field;
380        let setter_name = Ident::new(&("set_".to_owned() + &name.to_string()), name.span().clone());
381
382        if is_reference {
383            component_fields.extend::<proc_macro2::TokenStream>(quote! {
384                #name: ::std::sync::RwLock<::std::sync::Arc<#type_annotation>>,
385            }.try_into().unwrap());
386            component_field_defaults.extend::<proc_macro2::TokenStream>(quote! {
387                #name: ::std::sync::RwLock::new(::std::sync::Arc::new(#default_value)),
388            }.try_into().unwrap());
389            field_methods.extend::<proc_macro2::TokenStream>(quote! {
390                #(#attributes)*
391                #visibility fn #name(&self) -> ::std::sync::Arc<#type_annotation> {
392                    ::std::sync::Arc::clone(&*self.get::<#component_name>().unwrap().#name.read().unwrap())
393                }
394                #(#attributes)*
395                #visibility fn #setter_name(&self, value: ::std::sync::Arc<#type_annotation>) -> Self {
396                    *self.get::<#component_name>().unwrap().#name.write().unwrap() = value;
397                    self.clone()
398                }
399            }.try_into().unwrap());
400        } else {
401            component_fields.extend::<proc_macro2::TokenStream>(quote! {
402                #name: ::std::sync::RwLock<#type_annotation>,
403            }.try_into().unwrap());
404            component_field_defaults.extend::<proc_macro2::TokenStream>(quote! {
405                #name: ::std::sync::RwLock::new(#default_value),
406            }.try_into().unwrap());
407            field_methods.extend::<proc_macro2::TokenStream>(quote! {
408                #(#attributes)*
409                #visibility fn #name(&self) -> #type_annotation {
410                    self.get::<#component_name>().unwrap().#name.read().unwrap().clone()
411                }
412                #(#attributes)*
413                #visibility fn #setter_name(&self, value: #type_annotation) -> Self {
414                    *self.get::<#component_name>().unwrap().#name.write().unwrap() = value;
415                    self.clone()
416                }
417            }.try_into().unwrap());
418        }
419    }
420
421    expanded.extend::<TokenStream>(quote! {
422        #(#attributes)*
423        #visibility struct #name(#super_type);
424
425        #oop_inheritance_crate::class_extends!(#name < #(#inherited)<*, use #component_name, #oop_inheritance_crate);
426
427        impl #name {
428            #constructor_tokens
429            #field_methods
430        }
431
432        struct #component_name {
433            #component_fields
434        }
435
436        impl Default for #component_name {
437            fn default() -> Self {
438                Self {
439                    #component_field_defaults
440                }
441            }
442        }
443    }.try_into().unwrap());
444
445    expanded
446}