get-size-derive2-0.7.2/.cargo_vcs_info.json 0000644 00000000165 00000000001 0014131 0 ustar {
"git": {
"sha1": "28b42d90d34f29f1b19f9c5010c4d79345d7af1c"
},
"path_in_vcs": "crates/get-size-derive2"
} get-size-derive2-0.7.2/Cargo.lock 0000644 00000007533 00000000001 0012112 0 ustar # This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "attribute-derive"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77"
dependencies = [
"attribute-derive-macro",
"derive-where",
"manyhow",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "attribute-derive-macro"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61"
dependencies = [
"collection_literals",
"interpolator",
"manyhow",
"proc-macro-utils",
"proc-macro2",
"quote",
"quote-use",
"syn",
]
[[package]]
name = "collection_literals"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084"
[[package]]
name = "derive-where"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "get-size-derive2"
version = "0.7.2"
dependencies = [
"attribute-derive",
"quote",
"syn",
]
[[package]]
name = "interpolator"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8"
[[package]]
name = "manyhow"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
dependencies = [
"manyhow-macros",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "manyhow-macros"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
dependencies = [
"proc-macro-utils",
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-utils"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071"
dependencies = [
"proc-macro2",
"quote",
"smallvec",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "quote-use"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e"
dependencies = [
"quote",
"quote-use-macros",
]
[[package]]
name = "quote-use-macros"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35"
dependencies = [
"proc-macro-utils",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "syn"
version = "2.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
get-size-derive2-0.7.2/Cargo.toml 0000644 00000005436 00000000001 0012135 0 ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2024"
name = "get-size-derive2"
version = "0.7.2"
authors = [
"Denis Kerp",
"Nicolas",
]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Derives the GetSize trait."
readme = "README.md"
keywords = [
"size",
"heap",
"ram",
"memory",
"get-size",
]
categories = [
"memory-management",
"caching",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/bircni/get-size2/tree/main/crates/get-size-derive2"
resolver = "2"
[lib]
name = "get_size_derive2"
path = "src/lib.rs"
proc-macro = true
[dependencies.attribute-derive]
version = "0.10"
[dependencies.quote]
version = "1"
[dependencies.syn]
version = "2"
features = [
"derive",
"parsing",
]
[dev-dependencies]
[lints.clippy]
allow_attributes = "warn"
allow_attributes_without_reason = "warn"
assertions_on_result_states = "warn"
cast_possible_truncation = "allow"
cast_precision_loss = "allow"
cast_sign_loss = "allow"
clone_on_ref_ptr = "warn"
create_dir = "warn"
expect_used = "allow"
implicit_hasher = "allow"
missing_assert_message = "warn"
module_name_repetitions = "allow"
needless_doctest_main = "allow"
panic_in_result_fn = "warn"
str_to_string = "warn"
todo = "warn"
too_many_lines = "allow"
unimplemented = "warn"
unwrap_used = "warn"
wildcard_enum_match_arm = "warn"
[lints.clippy.all]
level = "warn"
priority = -1
[lints.clippy.complexity]
level = "warn"
priority = -1
[lints.clippy.correctness]
level = "warn"
priority = -1
[lints.clippy.pedantic]
level = "warn"
priority = -1
[lints.clippy.perf]
level = "warn"
priority = -1
[lints.clippy.style]
level = "warn"
priority = -1
[lints.clippy.suspicious]
level = "warn"
priority = -1
[lints.rust]
deprecated = "warn"
elided_lifetimes_in_paths = "warn"
rust_2021_prelude_collisions = "warn"
semicolon_in_expressions_from_macros = "warn"
trivial_casts = "allow"
trivial_numeric_casts = "warn"
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "warn"
unused_extern_crates = "warn"
unused_import_braces = "warn"
unused_lifetimes = "warn"
unused_qualifications = "allow"
[lints.rust.future_incompatible]
level = "warn"
priority = -1
[lints.rust.nonstandard_style]
level = "warn"
priority = -1
[lints.rust.rust_2018_idioms]
level = "warn"
priority = -1
[lints.rustdoc]
all = "warn"
missing_crate_level_docs = "warn"
get-size-derive2-0.7.2/Cargo.toml.orig 0000644 0000000 0000000 00000001247 10461020230 0015612 0 ustar 0000000 0000000 [package]
name = "get-size-derive2"
description = "Derives the GetSize trait."
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
readme = "README.md"
repository = "https://github.com/bircni/get-size2/tree/main/crates/get-size-derive2"
keywords = ["size", "heap", "ram", "memory", "get-size"]
categories = ["memory-management", "caching"]
[lib]
proc-macro = true
[dependencies]
syn = { workspace = true, features = ["derive", "parsing"] }
quote.workspace = true
attribute-derive.workspace = true
[dev-dependencies]
get-size2 = { path = "../get-size2", features = ["derive"] }
[lints]
workspace = true
get-size-derive2-0.7.2/LICENSE 0000644 0000000 0000000 00000002100 10461020230 0013715 0 ustar 0000000 0000000 MIT License
Copyright (c) 2022 Denis Kerp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
get-size-derive2-0.7.2/README.md 0000644 0000000 0000000 00000021540 10461020230 0014200 0 ustar 0000000 0000000 # get-size-derive
[](https://crates.io/crates/get-size-derive2)
[](https://docs.rs/get-size-derive2)
[](https://github.com/bircni/get-size2/blob/main/get-size-derive2/LICENSE)
Derives [`GetSize`] for structs and enums.
The derive macro will provide a custom implementation of the [`get_heap_size`] method, which will simply call [`get_heap_size`] on all contained values and add the values up. This implies that by default all values contained in the struct or enum most implement the [`GetSize`] trait themselves.
Note that the derive macro _does not support unions_. You have to manually implement it for them.
## Examples
Deriving [`GetSize`] for a struct:
```rust
use get_size2::GetSize;
#[derive(GetSize)]
pub struct OwnStruct {
value1: String,
value2: u64,
}
fn main() {
let test = OwnStruct {
value1: "Hello".into(),
value2: 123,
};
assert_eq!(test.get_heap_size(), 5);
}
```
Deriving [`GetSize`] for an enum:
```rust
use get_size2::GetSize;
#[derive(GetSize)]
pub enum TestEnum {
Variant1(u8, u16, u32),
Variant2(String),
Variant3,
Variant4{x: String, y: String},
}
#[derive(GetSize)]
pub enum TestEnumNumber {
Zero = 0,
One = 1,
Two = 2,
}
fn main() {
let test = TestEnum::Variant1(1, 2, 3);
assert_eq!(test.get_heap_size(), 0);
let test = TestEnum::Variant2("Hello".into());
assert_eq!(test.get_heap_size(), 5);
let test = TestEnum::Variant3;
assert_eq!(test.get_heap_size(), 0);
let test = TestEnum::Variant4{x: "Hello".into(), y: "world".into()};
assert_eq!(test.get_heap_size(), 5 + 5);
let test = TestEnumNumber::One;
assert_eq!(test.get_heap_size(), 0);
}
```
The derive macro does also work with generics. The generated trait implementation will by default require all generic types to implement [`GetSize`] themselves, but this [can be changed](#ignoring-certain-generic-types).
```rust
use get_size2::GetSize;
#[derive(GetSize)]
struct TestStructGenerics {
value1: A,
value2: B,
}
#[derive(GetSize)]
enum TestEnumGenerics {
Variant1(A),
Variant2(B),
}
fn main() {
let test: TestStructGenerics = TestStructGenerics {
value1: "Hello".into(),
value2: 123,
};
assert_eq!(test.get_heap_size(), 5);
let test = String::from("Hello");
let test: TestEnumGenerics = TestEnumGenerics::Variant1(test);
assert_eq!(test.get_heap_size(), 5);
let test: TestEnumGenerics = TestEnumGenerics::Variant2(100);
assert_eq!(test.get_heap_size(), 0);
}
```
### Dealing with external types which do not implement GetSize
Deriving [`GetSize`] is straight forward if all the types contained in your data structure implement [`GetSize`] themselves, but this might not always be the case. For that reason the derive macro offers some helpers to assist you in that case.
Note that the helpers are currently only available for regular structs, that is they do neither support tuple structs nor enums.
#### Ignoring certain values
You can tell the derive macro to ignore certain struct fields by adding the `ignore` attribute to them. The generated implementation of [`get_heap_size`] will then simple skip this field.
##### Example
The idiomatic use case for this helper is if you use shared ownership and do not want your data to be counted twice.
```rust
use std::sync::Arc;
use get_size2::GetSize;
#[derive(GetSize)]
struct PrimaryStore {
id: u64,
shared_data: Arc>,
}
#[derive(GetSize)]
struct SecondaryStore {
id: u64,
#[get_size(ignore)]
shared_data: Arc>,
}
fn main() {
let shared_data = Arc::new(Vec::with_capacity(1024));
let primary_data = PrimaryStore {
id: 1,
shared_data: Arc::clone(&shared_data),
};
let secondary_data = SecondaryStore {
id: 2,
shared_data,
};
// Note that Arc does also store the Vec's stack data on the heap.
assert_eq!(primary_data.get_heap_size(), Vec::::get_stack_size() + 1024);
assert_eq!(secondary_data.get_heap_size(), 0);
}
```
##### Example
But you may also use this as a band aid, if a certain struct fields type does not implement [`GetSize`].
Be aware though that this will result in an implementation which will return incorrect results, unless the heap size of that type is indeed always zero and can thus be ignored. It is therefor advisable to use one of the next two helper options instead.
```rust
use get_size2::GetSize;
// Does not implement GetSize!
struct TestStructNoGetSize {
value: String,
}
// Implements GetSize, even through one field's type does not implement it.
#[derive(GetSize)]
struct TestStruct {
name: String,
#[get_size(ignore)]
ignored_value: TestStructNoGetSize,
}
fn main() {
let ignored_value = TestStructNoGetSize {
value: "Hello world!".into(),
};
let test = TestStruct {
name: "Adam".into(),
ignored_value,
};
// Note that the result is lower then it should be.
assert_eq!(test.get_heap_size(), 4);
}
```
#### Returning a fixed value
In same cases you may be dealing with external types which allocate a fixed amount of bytes at the heap. In this case you may use the `size` attribute to always account the given field with a fixed value.
```rust
use get_size2::GetSize;
#[derive(GetSize)]
struct TestStruct {
id: u64,
#[get_size(size = 1024)]
buffer: Buffer1024, // Always allocates exactly 1KB at the heap.
}
fn main() {
let test = TestStruct {
id: 1,
buffer: Buffer1024::new(),
};
assert_eq!(test.get_heap_size(), 1024);
}
```
#### Using a helper function
In same cases you may be dealing with an external data structure for which you know how to calculate its heap size using its public methods. In that case you may either use the newtype pattern to implement [`GetSize`] for it directly, or you can use the `size_fn` attribute, which will call the given function in order to calculate the fields heap size.
The latter is especially useful if you can make use of a certain trait to calculate the heap size for multiple types.
Note that unlike in other crates, the name of the function to be called is **not** encapsulated by double-quotes ("), but rather given directly.
```rust
use get_size2::GetSize;
#[derive(GetSize)]
struct TestStruct {
id: u64,
#[get_size(size_fn = vec_alike_helper)]
buffer: ExternalVecAlike,
}
// NOTE: We assume that slice.len()==slice.capacity()
fn vec_alike_helper(slice: &V) -> usize
where
V: AsRef<[T]>,
{
std::mem::size_of::() * slice.as_ref().len()
}
fn main() {
let buffer = vec![0u8; 512];
let buffer: ExternalVecAlike = buffer.into();
let test = TestStruct {
id: 1,
buffer,
};
assert_eq!(test.get_heap_size(), 512);
}
```
#### Ignoring certain generic types
If your struct uses generics, but the fields at which they are stored are ignored or get handled by helpers because the generic does not implement [`GetSize`], you will have to mark these generics with a special struct level `ignore` attribute. Otherwise the derived [`GetSize`] implementation would still require these generics to implement [`GetSize`], even through there is no need for it.
```rust
use get_size2::GetSize;
#[derive(GetSize)]
#[get_size(ignore(B, C, D))]
struct TestStructHelpers {
value1: A,
#[get_size(size = 100)]
value2: B,
#[get_size(size_fn = get_size_helper)]
value3: C,
#[get_size(ignore)]
value4: D,
}
// Does not implement GetSize
struct NoGS {}
fn get_size_helper(_value: &C) -> usize {
50
}
fn main() {
let test: TestStructHelpers = TestStructHelpers {
value1: "Hello".into(),
value2: NoGS {},
value3: NoGS {},
value4: 123,
};
assert_eq!(test.get_heap_size(), 5 + 100 + 50);
}
```
## Panics
The derive macro will panic if used on unions since these are currently not supported.
Note that there will be a compilation error if one of the (not ignored) values encountered does not implement the [`GetSize`] trait.
## License
This library is licensed under the [MIT license](http://opensource.org/licenses/MIT).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this library by you, shall be licensed as MIT, without any additional terms or conditions.
[`GetSize`]: https://docs.rs/get-size2/latest/get_size2/trait.GetSize.html
[`get_heap_size`]: https://docs.rs/get-size2/latest/get_size2/trait.GetSize.html#method.get_heap_size
get-size-derive2-0.7.2/src/lib.md 0000644 0000000 0000000 00000020473 10461020230 0014604 0 ustar 0000000 0000000 Derives [`GetSize`] for structs and enums.
The derive macro will provide a custom implementation of the [`get_heap_size`] method, which will simply call [`get_heap_size`] on all contained values and add the values up. This implies that by default all values contained in the struct or enum must implement the [`GetSize`] trait themselves.
Note that the derive macro _does not support unions_. You have to manually implement it for them.
### Examples
Deriving [`GetSize`] for a struct:
```rust
use get_size2::GetSize;
#[derive(GetSize)]
pub struct OwnStruct {
value1: String,
value2: u64,
}
fn main() {
let test = OwnStruct {
value1: "Hello".into(),
value2: 123,
};
assert_eq!(test.get_heap_size(), 5);
}
```
Deriving [`GetSize`] for an enum:
```rust
use get_size2::GetSize;
#[derive(GetSize)]
pub enum TestEnum {
Variant1(u8, u16, u32),
Variant2(String),
Variant3,
Variant4{x: String, y: String},
}
#[derive(GetSize)]
pub enum TestEnumNumber {
Zero = 0,
One = 1,
Two = 2,
}
fn main() {
let test = TestEnum::Variant1(1, 2, 3);
assert_eq!(test.get_heap_size(), 0);
let test = TestEnum::Variant2("Hello".into());
assert_eq!(test.get_heap_size(), 5);
let test = TestEnum::Variant3;
assert_eq!(test.get_heap_size(), 0);
let test = TestEnum::Variant4{x: "Hello".into(), y: "world".into()};
assert_eq!(test.get_heap_size(), 5 + 5);
let test = TestEnumNumber::One;
assert_eq!(test.get_heap_size(), 0);
}
```
The derive macro does also work with generics. The generated trait implementation will by default require all generic types to implement [`GetSize`] themselves, but this [can be changed](#ignoring-certain-generic-types).
```rust
use get_size2::GetSize;
#[derive(GetSize)]
struct TestStructGenerics {
value1: A,
value2: B,
}
#[derive(GetSize)]
enum TestEnumGenerics {
Variant1(A),
Variant2(B),
}
fn main() {
let test: TestStructGenerics = TestStructGenerics {
value1: "Hello".into(),
value2: 123,
};
assert_eq!(test.get_heap_size(), 5);
let test = String::from("Hello");
let test: TestEnumGenerics = TestEnumGenerics::Variant1(test);
assert_eq!(test.get_heap_size(), 5);
let test: TestEnumGenerics = TestEnumGenerics::Variant2(100);
assert_eq!(test.get_heap_size(), 0);
}
```
## Dealing with external types which do not implement `GetSize`
Deriving [`GetSize`] is straight forward if all the types contained in your data structure implement [`GetSize`] themselves, but this might not always be the case. For that reason the derive macro offers some helpers to assist you in that case.
Note that the helpers are currently only available for regular structs, that is they do neither support tuple structs nor enums.
### Ignoring certain values
You can tell the derive macro to ignore certain struct fields by adding the `ignore` attribute to them. The generated implementation of [`get_heap_size`] will then simple skip this field.
#### Example
The idiomatic use case for this helper is if you use shared ownership and do not want your data to be counted twice.
```rust
use std::sync::Arc;
use get_size2::GetSize;
#[derive(GetSize)]
struct PrimaryStore {
id: u64,
shared_data: Arc>,
}
#[derive(GetSize)]
struct SecondaryStore {
id: u64,
#[get_size(ignore)]
shared_data: Arc>,
}
fn main() {
let shared_data = Arc::new(Vec::with_capacity(1024));
let primary_data = PrimaryStore {
id: 1,
shared_data: Arc::clone(&shared_data),
};
let secondary_data = SecondaryStore {
id: 2,
shared_data,
};
// Note that Arc does also store the Vec's stack data on the heap.
assert_eq!(primary_data.get_heap_size(), Vec::::get_stack_size() + 1024);
assert_eq!(secondary_data.get_heap_size(), 0);
}
```
#### Example
But you may also use this as a band aid, if a certain struct fields type does not implement [`GetSize`].
Be aware though that this will result in an implementation which will return incorrect results, unless the heap size of that type is indeed always zero and can thus be ignored. It is therefor advisable to use one of the next two helper options instead.
```rust
use get_size2::GetSize;
// Does not implement GetSize!
struct TestStructNoGetSize {
value: String,
}
// Implements GetSize, even through one field's type does not implement it.
#[derive(GetSize)]
struct TestStruct {
name: String,
#[get_size(ignore)]
ignored_value: TestStructNoGetSize,
}
fn main() {
let ignored_value = TestStructNoGetSize {
value: "Hello world!".into(),
};
let test = TestStruct {
name: "Adam".into(),
ignored_value,
};
// Note that the result is lower then it should be.
assert_eq!(test.get_heap_size(), 4);
}
```
### Returning a fixed value
In same cases you may be dealing with external types which allocate a fixed amount of bytes at the heap. In this case you may use the `size` attribute to always account the given field with a fixed value.
```rust
use get_size2::GetSize;
#
# struct Buffer1024 {}
#
# impl Buffer1024 {
# fn new() -> Self {
# Self {}
# }
# }
#[derive(GetSize)]
struct TestStruct {
id: u64,
#[get_size(size = 1024)]
buffer: Buffer1024, // Always allocates exactly 1KB at the heap.
}
fn main() {
let test = TestStruct {
id: 1,
buffer: Buffer1024::new(),
};
assert_eq!(test.get_heap_size(), 1024);
}
```
### Using a helper function
In same cases you may be dealing with an external data structure for which you know how to calculate its heap size using its public methods. In that case you may either use the newtype pattern to implement [`GetSize`] for it directly, or you can use the `size_fn` attribute, which will call the given function in order to calculate the fields heap size.
The latter is especially useful if you can make use of a certain trait to calculate the heap size for multiple types.
Note that unlike in other crates, the name of the function to be called is **not** encapsulated by double-quotes ("), but rather given directly.
```rust
use get_size2::GetSize;
#
# type ExternalVecAlike = Vec;
#[derive(GetSize)]
struct TestStruct {
id: u64,
#[get_size(size_fn = vec_alike_helper)]
buffer: ExternalVecAlike,
}
// NOTE: We assume that slice.len()==slice.capacity()
fn vec_alike_helper(slice: &V) -> usize
where
V: AsRef<[T]>,
{
std::mem::size_of::() * slice.as_ref().len()
}
fn main() {
let buffer = vec![0u8; 512];
let buffer: ExternalVecAlike = buffer.into();
let test = TestStruct {
id: 1,
buffer,
};
assert_eq!(test.get_heap_size(), 512);
}
```
### Ignoring certain generic types
If your struct uses generics, but the fields at which they are stored are ignored or get handled by helpers because the generic does not implement [`GetSize`], you will have to mark these generics with a special struct level `ignore` attribute. Otherwise the derived [`GetSize`] implementation would still require these generics to implement [`GetSize`], even through there is no need for it.
```rust
use get_size2::GetSize;
#[derive(GetSize)]
#[get_size(ignore(B, C, D))]
struct TestStructHelpers {
value1: A,
#[get_size(size = 100)]
value2: B,
#[get_size(size_fn = get_size_helper)]
value3: C,
#[get_size(ignore)]
value4: D,
}
// Does not implement GetSize
struct NoGS {}
fn get_size_helper(_value: &C) -> usize {
50
}
fn main() {
let test: TestStructHelpers = TestStructHelpers {
value1: "Hello".into(),
value2: NoGS {},
value3: NoGS {},
value4: 123,
};
assert_eq!(test.get_heap_size(), 5 + 100 + 50);
}
```
# Panics
The derive macro will panic if used on unions since these are currently not supported.
Note that there will be a compilation error if one of the (not ignored) values encountered does not implement the [`GetSize`] trait.
[`GetSize`]: https://docs.rs/get-size/latest/get_size/trait.GetSize.html
[`get_heap_size`]: https://docs.rs/get-size/latest/get_size/trait.GetSize.html#method.get_heap_size
get-size-derive2-0.7.2/src/lib.rs 0000644 0000000 0000000 00000030611 10461020230 0014623 0 ustar 0000000 0000000 #![doc = include_str!("./lib.md")]
use attribute_derive::{Attribute, FromAttr};
use proc_macro::TokenStream;
use quote::quote;
#[derive(FromAttr, Default, Debug)]
#[attribute(ident = get_size)]
struct StructFieldAttribute {
#[attribute(conflicts = [size_fn, ignore])]
size: Option,
#[attribute(conflicts = [size, ignore])]
size_fn: Option,
#[attribute(conflicts = [size, size_fn])]
ignore: bool,
}
fn extract_ignored_generics_list(list: &Vec) -> Vec {
let mut collection = Vec::new();
for attr in list {
let mut list = extract_ignored_generics(attr);
collection.append(&mut list);
}
collection
}
fn extract_ignored_generics(attr: &syn::Attribute) -> Vec {
let mut collection = Vec::new();
// Skip all attributes which do not belong to us.
if !attr.meta.path().is_ident("get_size") {
return collection;
}
// Make sure it is a list: #[get_size(...)]
let Ok(list) = attr.meta.require_list() else {
return collection;
};
// Parse the nested meta: #[get_size(ignore(...))] or #[get_size(ignore)]
let _ = list.parse_nested_meta(|meta| {
// Only handle `ignore`
if !meta.path.is_ident("ignore") {
return Ok(()); // Skip unrelated
}
// Handle the flag case: #[get_size(ignore)]
if meta.input.is_empty() {
// Do nothing – valid empty ignore
return Ok(());
}
// Handle the list case: #[get_size(ignore(A, B))]
meta.parse_nested_meta(|meta| {
for segment in meta.path.segments {
collection.push(segment);
}
Ok(())
})?;
Ok(())
});
collection
}
fn collect_all_ignored_generics(ast: &syn::DeriveInput) -> Vec {
let mut ignored = extract_ignored_generics_list(&ast.attrs);
match &ast.data {
syn::Data::Struct(data_struct) => {
for field in &data_struct.fields {
ignored.extend(extract_ignored_generics_list(&field.attrs));
}
}
syn::Data::Enum(data_enum) => {
for variant in &data_enum.variants {
ignored.extend(extract_ignored_generics_list(&variant.attrs));
for field in &variant.fields {
ignored.extend(extract_ignored_generics_list(&field.attrs));
}
}
}
syn::Data::Union(_) => {}
}
ignored
}
// Add a bound `T: GetSize` to every type parameter T, unless we ignore it.
fn add_trait_bounds(mut generics: syn::Generics, ignored: &Vec) -> syn::Generics {
for param in &mut generics.params {
if let syn::GenericParam::Type(type_param) = param {
let mut found = false;
for ignored in ignored {
if ignored.ident == type_param.ident {
found = true;
break;
}
}
if found {
continue;
}
type_param
.bounds
.push(syn::parse_quote!(::get_size2::GetSize));
}
}
generics
}
#[expect(
clippy::too_many_lines,
clippy::missing_panics_doc,
reason = "Needs refactoring"
)]
#[proc_macro_derive(GetSize, attributes(get_size))]
pub fn derive_get_size(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast: syn::DeriveInput = syn::parse(input).expect("Could not parse tokens");
// The name of the struct.
let name = &ast.ident;
// Extract all generics we shall ignore.
// let ignored = extract_ignored_generics_list(&ast.attrs);
let ignored = collect_all_ignored_generics(&ast);
// Add a bound `T: GetSize` to every type parameter T.
let generics = add_trait_bounds(ast.generics, &ignored);
// Extract the generics of the struct/enum.
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
// Traverse the parsed data to generate the individual parts of the function.
match ast.data {
syn::Data::Enum(data_enum) => {
if data_enum.variants.is_empty() {
// Empty enums are easy to implement.
let generated = quote! {
impl ::get_size2::GetSize for #name {}
};
return generated.into();
}
let mut cmds = Vec::with_capacity(data_enum.variants.len());
for variant in data_enum.variants {
let ident = &variant.ident;
match &variant.fields {
syn::Fields::Unnamed(unnamed_fields) => {
let num_fields = unnamed_fields.unnamed.len();
let mut field_idents = Vec::with_capacity(num_fields);
for i in 0..num_fields {
let field_ident = String::from("v") + &i.to_string();
let field_ident = syn::parse_str::(&field_ident)
.expect("Could not parse string to ident.");
field_idents.push(field_ident);
}
let mut field_cmds = Vec::with_capacity(num_fields);
for (i, _field) in unnamed_fields.unnamed.iter().enumerate() {
let field_ident = String::from("v") + &i.to_string();
let field_ident = syn::parse_str::(&field_ident)
.expect("Could not parse string to ident.");
field_cmds.push(quote! {
let (total_add, tracker) = ::get_size2::GetSize::get_heap_size_with_tracker(#field_ident, tracker);
total += total_add;
});
}
cmds.push(quote! {
Self::#ident(#(#field_idents,)*) => {
let mut total = 0;
#(#field_cmds)*;
(total, tracker)
}
});
}
syn::Fields::Named(named_fields) => {
let mut field_idents = Vec::new();
let mut field_cmds = Vec::new();
let mut skipped_field = false;
for field in &named_fields.named {
let field_ident =
field.ident.as_ref().expect("Could not get field ident.");
let attr = StructFieldAttribute::from_attributes(&field.attrs)
.expect("Could not parse field attributes.");
if attr.ignore {
skipped_field = true;
continue;
}
field_idents.push(field_ident);
field_cmds.push(quote! {
let (total_add, tracker) = ::get_size2::GetSize::get_heap_size_with_tracker(#field_ident, tracker);
total += total_add;
});
}
let pattern = if skipped_field {
quote! { Self::#ident { #(#field_idents,)* .. } }
} else {
quote! { Self::#ident { #(#field_idents,)* } }
};
cmds.push(quote! {
#pattern => {
let mut total = 0;
#(#field_cmds)*
(total, tracker)
}
});
}
syn::Fields::Unit => {
cmds.push(quote! {
Self::#ident => (0, tracker),
});
}
}
}
// Build the trait implementation
let generated = quote! {
impl #impl_generics ::get_size2::GetSize for #name #ty_generics #where_clause {
fn get_heap_size(&self) -> usize {
let tracker = get_size2::StandardTracker::default();
let (total, _) = ::get_size2::GetSize::get_heap_size_with_tracker(self, tracker);
total
}
fn get_heap_size_with_tracker(
&self,
tracker: TRACKER,
) -> (usize, TRACKER) {
match self {
#(#cmds)*
}
}
}
};
generated.into()
}
syn::Data::Union(_data_union) => {
panic!("Deriving GetSize for unions is currently not supported.")
}
syn::Data::Struct(data_struct) => {
if data_struct.fields.is_empty() {
// Empty structs are easy to implement.
let generated = quote! {
impl ::get_size2::GetSize for #name {}
};
return generated.into();
}
let mut cmds = Vec::with_capacity(data_struct.fields.len());
let mut unidentified_fields_count = 0; // For newtypes
for field in &data_struct.fields {
// Parse all relevant attributes.
let attr = StructFieldAttribute::from_attributes(&field.attrs)
.expect("Could not parse attributes.");
// NOTE There will be no attributes if this is a tuple struct.
if let Some(size) = attr.size {
cmds.push(quote! {
total += #size;
});
continue;
} else if let Some(size_fn) = attr.size_fn {
let ident = field.ident.as_ref().expect("Could not get field ident.");
cmds.push(quote! {
total += #size_fn(&self.#ident);
});
continue;
} else if attr.ignore {
continue;
}
if let Some(ident) = field.ident.as_ref() {
cmds.push(quote! {
let (total_add, tracker) = ::get_size2::GetSize::get_heap_size_with_tracker(&self.#ident, tracker);
total += total_add;
});
} else {
let current_index = syn::Index::from(unidentified_fields_count);
cmds.push(quote! {
let (total_add, tracker) = ::get_size2::GetSize::get_heap_size_with_tracker(&self.#current_index, tracker);
total += total_add;
});
unidentified_fields_count += 1;
}
}
// Build the trait implementation
let generated = quote! {
impl #impl_generics ::get_size2::GetSize for #name #ty_generics #where_clause {
fn get_heap_size(&self) -> usize {
let tracker = get_size2::StandardTracker::default();
let (total, _) = ::get_size2::GetSize::get_heap_size_with_tracker(self, tracker);
total
}
fn get_heap_size_with_tracker(
&self,
tracker: TRACKER,
) -> (usize, TRACKER) {
let mut total = 0;
#(#cmds)*;
(total, tracker)
}
}
};
generated.into()
}
}
}