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}