1
+ use std:: hash:: Hash ;
2
+
3
+ use indexmap:: Equivalent ;
1
4
use serde:: ser:: { Serialize , SerializeMap , Serializer } ;
2
5
6
+ use crate :: Profile ;
7
+
3
8
use super :: category_color:: CategoryColor ;
9
+ use super :: fast_hash_map:: FastIndexSet ;
10
+
11
+ /// Implemented by [`Category`], [`Subcategory`], [`CategoryHandle`] and [`SubcategoryHandle`].
12
+ pub trait IntoSubcategoryHandle {
13
+ /// Returns the corresponding [`SubcategoryHandle`].
14
+ fn into_subcategory_handle ( self , profile : & mut Profile ) -> SubcategoryHandle ;
15
+ }
16
+
17
+ /// A profiling category. Has a name and a color.
18
+ ///
19
+ /// Used to categorize stack frames and markers in the front-end. The category's
20
+ /// color is used in the activity graph and in the call tree, and in a few other places.
21
+ #[ derive( Debug , Clone , Copy , PartialOrd , Ord , PartialEq , Eq , Hash ) ]
22
+ pub struct Category < ' a > ( pub & ' a str , pub CategoryColor ) ;
23
+
24
+ impl IntoSubcategoryHandle for Category < ' _ > {
25
+ fn into_subcategory_handle ( self , profile : & mut Profile ) -> SubcategoryHandle {
26
+ let category_handle = profile. handle_for_category ( self ) ;
27
+ category_handle. into ( )
28
+ }
29
+ }
4
30
5
- /// A profiling category, can be set on stack frames and markers as part of a [`CategoryPairHandle`] .
31
+ /// The handle for a [`Category`], obtained from [`Profile::handle_for_category`](crate::Profile::handle_for_category) .
6
32
///
7
- /// Categories can be created with [`Profile::add_category`](crate::Profile::add_category).
33
+ /// Storing and reusing the handle avoids repeated lookups and can improve performance.
34
+ ///
35
+ /// The handle is specific to a [`Profile`] instance and cannot be reused across profiles.
8
36
#[ derive( Debug , Clone , Copy , PartialOrd , Ord , PartialEq , Eq , Hash ) ]
9
37
pub struct CategoryHandle ( pub ( crate ) u16 ) ;
10
38
@@ -13,15 +41,33 @@ impl CategoryHandle {
13
41
pub const OTHER : Self = CategoryHandle ( 0 ) ;
14
42
}
15
43
44
+ impl IntoSubcategoryHandle for CategoryHandle {
45
+ fn into_subcategory_handle ( self , _profile : & mut Profile ) -> SubcategoryHandle {
46
+ self . into ( )
47
+ }
48
+ }
49
+
16
50
impl Serialize for CategoryHandle {
17
51
fn serialize < S : Serializer > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error > {
18
52
self . 0 . serialize ( serializer)
19
53
}
20
54
}
21
55
22
- /// A profiling subcategory, can be set on stack frames and markers as part of a [`CategoryPairHandle`] .
56
+ /// A named subcategory of a [`Category`], for fine-grained annotation of stack frames .
23
57
///
24
- /// Subategories can be created with [`Profile::add_subcategory`](crate::Profile::add_subcategory).
58
+ /// If you don't need named subcategories, you can just pass a [`Category`] or a
59
+ /// [`CategoryHandle`] in any place where an [`IntoSubcategoryHandle`] is expected;
60
+ /// this will give you the category's default subcategory.
61
+ pub struct Subcategory < ' a > ( pub Category < ' a > , pub & ' a str ) ;
62
+
63
+ impl IntoSubcategoryHandle for Subcategory < ' _ > {
64
+ fn into_subcategory_handle ( self , profile : & mut Profile ) -> SubcategoryHandle {
65
+ let Subcategory ( category, subcategory_name) = self ;
66
+ let category_handle = profile. handle_for_category ( category) ;
67
+ profile. handle_for_subcategory ( category_handle, subcategory_name)
68
+ }
69
+ }
70
+
25
71
#[ derive( Debug , Clone , Copy , PartialOrd , Ord , PartialEq , Eq , Hash ) ]
26
72
pub struct SubcategoryIndex ( pub u16 ) ;
27
73
@@ -30,16 +76,30 @@ impl SubcategoryIndex {
30
76
pub const OTHER : Self = SubcategoryIndex ( 0 ) ;
31
77
}
32
78
33
- /// A profiling category pair, consisting of a category and an optional subcategory. Can be set on stack frames and markers.
79
+ /// A handle for a [`Subcategory`], or for the default subcategory of a [`CategoryHandle`].
80
+ ///
81
+ /// Used to annotate stack frames.
82
+ ///
83
+ /// Every [`CategoryHandle`] can be turned into a [`SubcategoryHandle`] by calling `.into()` -
84
+ /// this will give you the default subcategory of that category.
34
85
///
35
- /// Category pairs can be created with [`Profile::add_subcategory`](crate::Profile::add_subcategory)
36
- /// and from a [`CategoryHandle`].
86
+ /// Subcategory handles for named subcategories can be obtained from
87
+ /// [`Profile::handle_for_subcategory`](crate::Profile::handle_for_subcategory).
88
+ /// Storing and reusing the handle avoids repeated lookups and can improve performance.
89
+ ///
90
+ /// The handle is specific to a Profile instance and cannot be reused across profiles.
37
91
#[ derive( Debug , Clone , Copy , PartialOrd , Ord , PartialEq , Eq , Hash ) ]
38
- pub struct CategoryPairHandle ( pub ( crate ) CategoryHandle , pub ( crate ) SubcategoryIndex ) ;
92
+ pub struct SubcategoryHandle ( pub ( crate ) CategoryHandle , pub ( crate ) SubcategoryIndex ) ;
39
93
40
- impl From < CategoryHandle > for CategoryPairHandle {
94
+ impl IntoSubcategoryHandle for SubcategoryHandle {
95
+ fn into_subcategory_handle ( self , _profile : & mut Profile ) -> SubcategoryHandle {
96
+ self
97
+ }
98
+ }
99
+
100
+ impl From < CategoryHandle > for SubcategoryHandle {
41
101
fn from ( category : CategoryHandle ) -> Self {
42
- CategoryPairHandle ( category, SubcategoryIndex :: OTHER )
102
+ SubcategoryHandle ( category, SubcategoryIndex :: OTHER )
43
103
}
44
104
}
45
105
@@ -48,24 +108,61 @@ impl From<CategoryHandle> for CategoryPairHandle {
48
108
pub struct InternalCategory {
49
109
name : String ,
50
110
color : CategoryColor ,
51
- subcategories : Vec < String > ,
111
+ subcategories : FastIndexSet < String > ,
112
+ }
113
+
114
+ impl Hash for InternalCategory {
115
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
116
+ self . as_category ( ) . hash ( state)
117
+ }
118
+ }
119
+
120
+ impl Equivalent < Category < ' _ > > for InternalCategory {
121
+ fn equivalent ( & self , key : & Category < ' _ > ) -> bool {
122
+ & self . as_category ( ) == key
123
+ }
52
124
}
53
125
126
+ impl Equivalent < InternalCategory > for Category < ' _ > {
127
+ fn equivalent ( & self , key : & InternalCategory ) -> bool {
128
+ self == & key. as_category ( )
129
+ }
130
+ }
131
+
132
+ impl PartialEq for InternalCategory {
133
+ fn eq ( & self , other : & Self ) -> bool {
134
+ self . as_category ( ) == other. as_category ( )
135
+ }
136
+ }
137
+
138
+ impl Eq for InternalCategory { }
139
+
54
140
impl InternalCategory {
55
- pub fn new ( name : String , color : CategoryColor ) -> Self {
56
- let subcategories = vec ! [ "Other" . to_string( ) ] ;
141
+ pub fn new ( name : & str , color : CategoryColor ) -> Self {
142
+ let mut subcategories = FastIndexSet :: default ( ) ;
143
+ subcategories. insert ( "Other" . to_string ( ) ) ;
57
144
Self {
58
- name,
145
+ name : name . to_string ( ) ,
59
146
color,
60
147
subcategories,
61
148
}
62
149
}
63
150
64
- /// Add a subcategory to this category.
65
- pub fn add_subcategory ( & mut self , subcategory_name : String ) -> SubcategoryIndex {
66
- let subcategory_index = SubcategoryIndex ( u16:: try_from ( self . subcategories . len ( ) ) . unwrap ( ) ) ;
67
- self . subcategories . push ( subcategory_name) ;
68
- subcategory_index
151
+ /// Get or create a subcategory to this category.
152
+ pub fn index_for_subcategory ( & mut self , subcategory_name : & str ) -> SubcategoryIndex {
153
+ let index = self
154
+ . subcategories
155
+ . get_index_of ( subcategory_name)
156
+ . unwrap_or_else ( || {
157
+ self . subcategories
158
+ . insert_full ( subcategory_name. to_owned ( ) )
159
+ . 0
160
+ } ) ;
161
+ SubcategoryIndex ( u16:: try_from ( index) . unwrap ( ) )
162
+ }
163
+
164
+ pub fn as_category ( & self ) -> Category < ' _ > {
165
+ Category ( & self . name , self . color )
69
166
}
70
167
}
71
168
0 commit comments