4 个版本
0.1.3 | 2023 年 6 月 23 日 |
---|---|
0.1.2 | 2023 年 1 月 3 日 |
0.1.1 | 2022 年 2 月 27 日 |
0.1.0 | 2022 年 2 月 27 日 |
303 在 缓存
307,390 每月下载量
用于 45 个 Crates(13 个直接使用)
20KB
195 行
get-size-derive
为结构和枚举派生 GetSize
。
该派生宏将为 get_heap_size
方法提供一个自定义实现,该方法将简单地对所有包含的值调用 get_heap_size
并将值相加。这意味着默认情况下,结构体或枚举中包含的所有值都必须实现 GetSize
特性。
请注意,派生宏 不支持联合。您必须手动为它们实现。
示例
为结构派生 GetSize
use get_size::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);
}
为枚举派生 GetSize
use get_size::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);
}
该派生宏还与泛型一起工作。生成的特性实现将默认要求所有泛型类型都实现 GetSize
,但此 可进行更改。
use get_size::GetSize;
#[derive(GetSize)]
struct TestStructGenerics<A, B> {
value1: A,
value2: B,
}
#[derive(GetSize)]
enum TestEnumGenerics<A, B> {
Variant1(A),
Variant2(B),
}
fn main() {
let test: TestStructGenerics<String, u64> = TestStructGenerics {
value1: "Hello".into(),
value2: 123,
};
assert_eq!(test.get_heap_size(), 5);
let test = String::from("Hello");
let test: TestEnumGenerics<String, u64> = TestEnumGenerics::Variant1(test);
assert_eq!(test.get_heap_size(), 5);
let test: TestEnumGenerics<String, u64> = TestEnumGenerics::Variant2(100);
assert_eq!(test.get_heap_size(), 0);
}
处理不实现 GetSize 的外部类型
如果您的数据结构中包含的任何类型都实现了 GetSize
,则派生 GetSize
是直接的,但情况并不总是如此。因此,派生宏提供了一些助手以帮助您处理这种情况。
请注意,这些助手目前仅适用于常规结构,即它们不支持元组结构体或枚举。
忽略某些值
您可以通过将 ignore
属性添加到它们来告诉派生宏忽略某些结构体字段。然后生成的 get_heap_size
实现将简单地跳过此字段。
示例
此辅助程序的使用场景是如果您使用共享所有权并且不希望您的数据被计算两次。
use std::sync::Arc;
use get_size::GetSize;
#[derive(GetSize)]
struct PrimaryStore {
id: u64,
shared_data: Arc<Vec<u8>>,
}
#[derive(GetSize)]
struct SecondaryStore {
id: u64,
#[get_size(ignore)]
shared_data: Arc<Vec<u8>>,
}
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::<u8>::get_stack_size() + 1024);
assert_eq!(secondary_data.get_heap_size(), 0);
}
示例
但是您也可以将其用作临时修补,如果某个结构体字段的类型没有实现 GetSize
。
请注意,这会导致返回不正确的结果的实现,除非该类型的堆大小始终为零,因此可以忽略。因此,建议使用以下两种辅助选项之一。
use get_size::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);
}
返回固定值
在某些情况下,您可能正在处理在堆上分配固定字节数的外部类型。在这种情况下,您可以使用 size
属性始终以固定值计算给定的字段。
use get_size::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);
}
使用辅助函数
在某些情况下,您可能正在处理外部数据结构,您知道如何使用其公共方法计算其堆大小。在这种情况下,您可以直接为它实现 GetSize
,或者您可以使用 size_fn
属性,该属性将调用给定函数以计算字段的堆大小。
后者特别有用,如果您可以充分利用某个特质来计算多个类型的堆大小。
注意,与其他crate不同,要调用的函数名称 不 被双引号 ("") 封装,而是直接给出。
use get_size::GetSize;
#[derive(GetSize)]
struct TestStruct {
id: u64,
#[get_size(size_fn = vec_alike_helper)]
buffer: ExternalVecAlike<u8>,
}
// NOTE: We assume that slice.len()==slice.capacity()
fn vec_alike_helper<V, T>(slice: &V) -> usize
where
V: AsRef<[T]>,
{
std::mem::size_of::<T>() * slice.as_ref().len()
}
fn main() {
let buffer = vec![0u8; 512];
let buffer: ExternalVecAlike<u8> = buffer.into();
let test = TestStruct {
id: 1,
buffer,
};
assert_eq!(test.get_heap_size(), 512);
}
忽略某些泛型类型
如果您的结构体使用泛型,但这些字段被忽略或由辅助器处理,因为泛型没有实现 GetSize
,您将必须使用特殊的结构级别 ignore
属性标记这些泛型。否则,派生的 GetSize
实现仍然需要这些泛型实现 GetSize
,尽管实际上不需要。
use get_size::GetSize;
#[derive(GetSize)]
#[get_size(ignore(B, C, D))]
struct TestStructHelpers<A, B, C, D> {
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<C>(_value: &C) -> usize {
50
}
fn main() {
let test: TestStructHelpers<String, NoGS, NoGS, u64> = TestStructHelpers {
value1: "Hello".into(),
value2: NoGS {},
value3: NoGS {},
value4: 123,
};
assert_eq!(test.get_heap_size(), 5 + 100 + 50);
}
恐慌
如果用于联合体,派生宏将引发恐慌,因为目前不支持联合体。
请注意,如果遇到的不(忽略的)值之一没有实现 GetSize
特质,则将出现编译错误。
许可
本库采用 MIT 许可证。
贡献
除非您明确说明,否则您提交的任何有意包含在本库中的贡献,都应按照 MIT 许可,不附加任何额外条款或条件。
依赖关系
~0.7–1.2MB
~25K SLoC