iota_util_mem_derive/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5// Copyright 2020 Parity Technologies
6//
7// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10// option. This file may not be copied, modified, or distributed
11// except according to those terms.
12
13//! A crate for deriving the MallocSizeOf trait.
14//!
15//! This is a copy of Servo malloc_size_of_derive code, modified to work with
16//! our `iota_util_mem` library
17
18#![allow(clippy::all)]
19
20extern crate proc_macro2;
21#[macro_use]
22extern crate syn;
23#[macro_use]
24extern crate synstructure;
25
26decl_derive!([MallocSizeOf, attributes(ignore_malloc_size_of)] => malloc_size_of_derive);
27
28fn malloc_size_of_derive(s: synstructure::Structure) -> proc_macro2::TokenStream {
29    let match_body = s.each(|binding| {
30        let ignore = binding
31            .ast()
32            .attrs
33            .iter()
34            .any(|attr| match attr.parse_meta().unwrap() {
35                syn::Meta::Path(ref path) | syn::Meta::List(syn::MetaList { ref path, .. })
36                    if path.is_ident("ignore_malloc_size_of") =>
37                {
38                    panic!(
39                        "#[ignore_malloc_size_of] should have an explanation, \
40					 e.g. #[ignore_malloc_size_of = \"because reasons\"]"
41                    );
42                }
43                syn::Meta::NameValue(syn::MetaNameValue { ref path, .. })
44                    if path.is_ident("ignore_malloc_size_of") =>
45                {
46                    true
47                }
48                _ => false,
49            });
50        if ignore {
51            None
52        } else if let syn::Type::Array(..) = binding.ast().ty {
53            Some(quote! {
54                for item in #binding.iter() {
55                    sum += iota_util_mem::MallocSizeOf::size_of(item, ops);
56                }
57            })
58        } else {
59            Some(quote! {
60                sum += iota_util_mem::MallocSizeOf::size_of(#binding, ops);
61            })
62        }
63    });
64
65    let ast = s.ast();
66    let name = &ast.ident;
67    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
68    let mut where_clause = where_clause.unwrap_or(&parse_quote!(where)).clone();
69    for param in ast.generics.type_params() {
70        let ident = &param.ident;
71        where_clause
72            .predicates
73            .push(parse_quote!(#ident: iota_util_mem::MallocSizeOf));
74    }
75
76    let tokens = quote! {
77        impl #impl_generics iota_util_mem::MallocSizeOf for #name #ty_generics #where_clause {
78            #[inline]
79            #[expect(unused_variables, unused_mut, unreachable_code)]
80            fn size_of(&self, ops: &mut iota_util_mem::MallocSizeOfOps) -> usize {
81                let mut sum = 0;
82                match *self {
83                    #match_body
84                }
85                sum
86            }
87        }
88    };
89
90    tokens
91}