general_structs/
lib.rs

1// Copyright 2024 Dmitriy Mayorov
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7//     http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15extern crate proc_macro;
16
17use proc_macro2::{TokenTree, TokenStream, Delimiter, Group};
18
19#[derive(Debug, Clone, Default)]
20struct TypeStruct {
21    pub signature: Vec<TokenTree>,
22    pub group: Vec<TokenTree>, 
23}
24
25#[proc_macro]
26pub fn general_structs(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
27    let ast = TokenStream::from(item);
28    
29    let mut metadata = Vec::<TokenTree>::new();
30    let mut types = Vec::<TypeStruct>::new();
31    let mut general_body = TokenTree::from(Group::new(Delimiter::Brace, TokenStream::new()));
32    
33    let mut mut_types = Vec::<TypeStruct>::new();
34    
35    let mut bracket_stack = 0;
36    let mut is_struct = false;
37    let mut is_mut_struct = false;
38    let mut is_body_general_group = false;
39    
40    let mut current_type_struct = TypeStruct::default();
41    for token in ast.into_iter() {
42        if let TokenTree::Ident(ident) = &token {
43            if ident.to_string() == "struct" {
44                is_struct = true;
45                continue;
46            }
47        }
48        
49        if is_struct {
50            if let TokenTree::Punct(punct) = &token {
51                if punct.as_char() == '<' {
52                    bracket_stack += 1;
53                } else if punct.as_char() == '>'{
54                    bracket_stack -= 1;
55                } else if punct.as_char() == '+' && bracket_stack == 0 {
56                    types.push(current_type_struct);
57                    current_type_struct = TypeStruct::default();
58                    continue;
59                }
60            } else if let TokenTree::Group(group) = &token {
61                if let Delimiter::Brace = group.delimiter() {
62                    types.push(current_type_struct);
63                    current_type_struct = TypeStruct::default();
64                    is_struct = false;
65                    is_body_general_group = true;
66                }
67            }
68            
69            if is_struct {
70                current_type_struct.signature.push(token.clone());
71            } else {
72                current_type_struct = TypeStruct::default();
73            }
74        }
75        
76        if is_body_general_group {
77            if let TokenTree::Group(group) = &token {
78                general_body = TokenTree::Group(group.clone());
79                is_body_general_group = false;
80                continue;
81            }
82        }
83        
84        if let TokenTree::Ident(_) = &token {
85            if !is_struct && !is_body_general_group {
86                is_mut_struct = true;
87            }
88        }
89        
90        if is_mut_struct {
91            if let TokenTree::Punct(punct) = &token {
92                if punct.as_char() == '<' {
93                    bracket_stack += 1;
94                } else if punct.as_char() == '>'{
95                    bracket_stack -= 1;
96                } else if punct.as_char() == '+' && bracket_stack == 0 {
97                    types.push(current_type_struct);
98                    current_type_struct = TypeStruct::default();
99                    continue;
100                }
101            } else if let TokenTree::Group(group) = &token {
102                if let Delimiter::Brace = group.delimiter() {
103                    current_type_struct.group.push(TokenTree::Group(group.clone()));
104                    mut_types.push(current_type_struct);
105                    
106                    current_type_struct = TypeStruct::default();
107                    continue;
108                }
109            }
110
111            current_type_struct.signature.push(token.clone());
112        }
113
114        if !is_struct && !is_mut_struct && !is_body_general_group {
115            metadata.push(token.clone());
116            continue;
117        }
118    }
119    
120    let mut res = String::new();
121    
122    for type_struct in types.iter() {
123        res.push_str(format!("{} ", TokenStream::from_iter(metadata.clone())).as_str());
124        
125        let type_name = TokenStream::from_iter(type_struct.signature.clone()).to_string();
126        res.push_str(format!("struct {} {{", type_name).as_str());
127        
128        if let TokenTree::Group(general_group) = &general_body {
129            res.push_str(format!("{}", general_group.stream().to_string()).as_str());
130            
131            for type_mut_struct in mut_types.iter() {
132                let mut_type_name = TokenStream::from_iter(type_mut_struct.signature.clone()).to_string();
133                if mut_type_name == type_name {
134                    if let TokenTree::Group(add_group) = &type_mut_struct.group[0] {
135                        res.push_str(format!("{}", add_group.stream().to_string()).as_str());
136                    }
137                }
138            }
139        }
140
141        res.push_str(format!("}} ").as_str());
142    }
143    
144    res.as_str().parse().unwrap()
145}