allocative/allocative_trait.rs
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under both the MIT license found in the
5 * LICENSE-MIT file in the root directory of this source tree and the Apache
6 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
7 * of this source tree.
8 */
9
10use crate::Visitor;
11
12/// This trait allows traversal of object graph.
13///
14/// # Proc macro
15///
16/// Typically implemented with proc macro. Like this:
17///
18/// ```
19/// use allocative::Allocative;
20///
21/// #[derive(Allocative)]
22/// struct Foo {
23/// x: u32,
24/// y: String,
25/// }
26/// ```
27///
28/// Proc macro supports two attributes: `#[allocative(skip)]` and
29/// `#[allocative(bound = "...")]`.
30///
31/// ## `#[allocative(skip)]`
32///
33/// `#[allocative(skip)]` can be used to skip field from traversal (for example,
34/// to skip fields which are not `Allocative`, and can be skipped because they
35/// are cheap).
36///
37/// ```
38/// use allocative::Allocative;
39///
40/// /// This does not implement `Allocative`.
41/// struct Unsupported;
42///
43/// #[derive(Allocative)]
44/// struct Bar {
45/// #[allocative(skip)]
46/// unsupported: Unsupported,
47/// }
48/// ```
49///
50/// ## `#[allocative(bound = "...")]`
51///
52/// `#[allocative(bound = "...")]` can be used to overwrite the bounds that are
53/// added to the generics of the implementation.
54///
55/// An empty string (`#[allocative(bound = "")]`) simply erases all bounds. It
56/// adds all type variables found in the type to the list of generics but with
57/// an empty bound. As an example
58///
59///
60/// ```
61/// use std::marker::PhantomData;
62///
63/// use allocative::Allocative;
64///
65/// struct Unsupported;
66///
67/// #[derive(Allocative)]
68/// #[allocative(bound = "")]
69/// struct Baz<T> {
70/// _marker: PhantomData<T>,
71/// }
72/// ```
73///
74/// Would generate an instance
75///
76/// ```ignore
77/// impl<T> Allocative for Baz<T> { ... }
78/// ```
79///
80/// Alternatively you can use the string to provide custom bounds. The string in
81/// this case is used *verbatim* as the bounds, which affords great flexibility,
82/// but also necessitates that all type variables must be mentioned or will be
83/// unbound (compile error). As an example we may derive a size of a `HashMap`
84/// by ignoring the hasher type.
85///
86///
87/// ```ignore
88/// #[allocative(bound = "K: Allocative, V:Allocative, S")]
89/// struct HashMap<K, V, S = RandomState> {
90/// ...
91/// }
92/// ```
93///
94/// Which generates
95///
96/// ```ignore
97/// impl<K: Allocative, V:Allocative, S> Allocative for HashMap<K, V, S> {
98/// ...
99/// }
100/// ```
101///
102/// ## `#[allocative(visit = ...)]`
103///
104/// This annotation is used to provide a custom visit method for a given field. This
105/// is especially useful if the type of the field does not implement `Allocative`.
106///
107/// The annotation takes the path to a method with a signature `for<'a, 'b>(&T, &'a
108/// mut allocative::Visitor<'b>)` where `T` is the type of the field. The function
109/// you provide is basically the same as if you implemented [`Allocative::visit`].
110///
111/// As an example
112///
113/// ```
114/// use allocative::Allocative;
115/// use allocative::Key;
116/// use allocative::Visitor;
117/// // use third_party_lib::Unsupported;
118/// # struct Unsupported<T>(T);
119/// # impl<T> Unsupported<T> {
120/// # fn iter_elems(&self) -> &[T] { &[] }
121/// # }
122///
123/// #[derive(Allocative)]
124/// struct Bar {
125/// #[allocative(visit = visit_unsupported)]
126/// unsupported: Unsupported<usize>,
127/// }
128///
129/// fn visit_unsupported<'a, 'b>(u: &Unsupported<usize>, visitor: &'a mut Visitor<'b>) {
130/// const ELEM_KEY: Key = Key::new("elements");
131/// let mut visitor = visitor.enter_self(u);
132/// for element in u.iter_elems() {
133/// visitor.visit_field(ELEM_KEY, element);
134/// }
135/// visitor.exit()
136/// }
137/// ```
138pub trait Allocative {
139 fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>);
140}