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        && let Some(ident) = meta.path().get_ident()
42        && *ident == name
43        && let syn::Meta::List(list) = meta
44    {
45        for nested in &list.nested {
46            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested
47                && let path = path
48                    .get_ident()
49                    .expect("Invalid attribute syntax! (no ident)")
50                    .to_string()
51                && path == flag
52            {
53                return true;
54            }
55        }
56    }
57    false
58}
59
60pub fn has_nested_flag_attribute_list(
61    list: &[syn::Attribute],
62    name: &'static str,
63    flag: &'static str,
64) -> bool {
65    for attr in list {
66        if has_nested_flag_attribute(attr, name, flag) {
67            return true;
68        }
69    }
70
71    false
72}
73
74pub fn extract_ignored_generics_list(list: &[syn::Attribute]) -> Vec<String> {
75    let mut collection = Vec::new();
76
77    for attr in list {
78        let mut list = extract_ignored_generics(attr);
79
80        collection.append(&mut list);
81    }
82
83    collection
84}
85
86pub fn extract_ignored_generics(attr: &syn::Attribute) -> Vec<String> {
87    let mut collection = Vec::new();
88
89    if let Ok(meta) = attr.parse_meta()
90        && let Some(ident) = meta.path().get_ident()
91    {
92        if &ident.to_string() != "get_size" {
93            return collection;
94        }
95        if let syn::Meta::List(list) = meta {
96            for nested in &list.nested {
97                if let syn::NestedMeta::Meta(nmeta) = nested {
98                    let ident = nmeta
99                        .path()
100                        .get_ident()
101                        .expect("Invalid attribute syntax! (no iden)");
102                    if &ident.to_string() != "ignore" {
103                        panic!(
104                            "Invalid attribute syntax! Unknown name {:?}",
105                            ident.to_string()
106                        );
107                    }
108
109                    if let syn::Meta::List(list) = nmeta {
110                        for nested in &list.nested {
111                            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested {
112                                let path = path
113                                    .get_ident()
114                                    .expect("Invalid attribute syntax! (no ident)")
115                                    .to_string();
116                                collection.push(path);
117                            }
118                        }
119                    }
120                }
121            }
122        }
123    }
124
125    collection
126}
127
128// Add a bound `T: EstimateSize` to every type parameter T, unless we ignore it.
129pub fn add_trait_bounds(mut generics: syn::Generics, ignored: &[String]) -> syn::Generics {
130    for param in &mut generics.params {
131        if let syn::GenericParam::Type(type_param) = param {
132            let name = type_param.ident.to_string();
133            let mut found = false;
134            for ignored in ignored {
135                if ignored == &name {
136                    found = true;
137                    break;
138                }
139            }
140            if found {
141                continue;
142            }
143            // type_param.bounds.push(syn::parse_quote!(EstimateSize));
144        }
145    }
146    generics
147}