risingwave_common_proc_macro/
estimate_size.rs

1// Copyright 2025 RisingWave Labs
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
15// Copyright (c) 2022 Denis Kerp
16//
17// Permission is hereby granted, free of charge, to any person obtaining a copy
18// of this software and associated documentation files (the "Software"), to deal
19// in the Software without restriction, including without limitation the rights
20// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21// copies of the Software, and to permit persons to whom the Software is
22// furnished to do so, subject to the following conditions:
23//
24// The above copyright notice and this permission notice shall be included in all
25// copies or substantial portions of the Software.
26//
27// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33// SOFTWARE.
34
35fn has_nested_flag_attribute(
36    attr: &syn::Attribute,
37    name: &'static str,
38    flag: &'static str,
39) -> bool {
40    if let Ok(meta) = attr.parse_meta() {
41        if let Some(ident) = meta.path().get_ident() {
42            if *ident == name {
43                if let syn::Meta::List(list) = meta {
44                    for nested in &list.nested {
45                        if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested {
46                            let path = path
47                                .get_ident()
48                                .expect("Invalid attribute syntax! (no ident)")
49                                .to_string();
50                            if path == flag {
51                                return true;
52                            }
53                        }
54                    }
55                }
56            }
57        }
58    }
59
60    false
61}
62
63pub fn has_nested_flag_attribute_list(
64    list: &[syn::Attribute],
65    name: &'static str,
66    flag: &'static str,
67) -> bool {
68    for attr in list {
69        if has_nested_flag_attribute(attr, name, flag) {
70            return true;
71        }
72    }
73
74    false
75}
76
77pub fn extract_ignored_generics_list(list: &[syn::Attribute]) -> Vec<String> {
78    let mut collection = Vec::new();
79
80    for attr in list {
81        let mut list = extract_ignored_generics(attr);
82
83        collection.append(&mut list);
84    }
85
86    collection
87}
88
89pub fn extract_ignored_generics(attr: &syn::Attribute) -> Vec<String> {
90    let mut collection = Vec::new();
91
92    if let Ok(meta) = attr.parse_meta() {
93        if let Some(ident) = meta.path().get_ident() {
94            if &ident.to_string() != "get_size" {
95                return collection;
96            }
97            if let syn::Meta::List(list) = meta {
98                for nested in &list.nested {
99                    if let syn::NestedMeta::Meta(nmeta) = nested {
100                        let ident = nmeta
101                            .path()
102                            .get_ident()
103                            .expect("Invalid attribute syntax! (no iden)");
104                        if &ident.to_string() != "ignore" {
105                            panic!(
106                                "Invalid attribute syntax! Unknown name {:?}",
107                                ident.to_string()
108                            );
109                        }
110
111                        if let syn::Meta::List(list) = nmeta {
112                            for nested in &list.nested {
113                                if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested {
114                                    let path = path
115                                        .get_ident()
116                                        .expect("Invalid attribute syntax! (no ident)")
117                                        .to_string();
118                                    collection.push(path);
119                                }
120                            }
121                        }
122                    }
123                }
124            }
125        }
126    }
127
128    collection
129}
130
131// Add a bound `T: EstimateSize` to every type parameter T, unless we ignore it.
132pub fn add_trait_bounds(mut generics: syn::Generics, ignored: &[String]) -> syn::Generics {
133    for param in &mut generics.params {
134        if let syn::GenericParam::Type(type_param) = param {
135            let name = type_param.ident.to_string();
136            let mut found = false;
137            for ignored in ignored {
138                if ignored == &name {
139                    found = true;
140                    break;
141                }
142            }
143            if found {
144                continue;
145            }
146            // type_param.bounds.push(syn::parse_quote!(EstimateSize));
147        }
148    }
149    generics
150}