fxprof_processed_profile/
category.rs

1use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
2
3use super::category_color::CategoryColor;
4
5/// A profiling category, can be set on stack frames and markers as part of a [`CategoryPairHandle`].
6///
7/// Categories can be created with [`Profile::add_category`](crate::Profile::add_category).
8#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
9pub struct CategoryHandle(pub(crate) u16);
10
11impl CategoryHandle {
12    /// The "Other" category. All profiles have this category.
13    pub const OTHER: Self = CategoryHandle(0);
14}
15
16impl Serialize for CategoryHandle {
17    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
18        self.0.serialize(serializer)
19    }
20}
21
22/// A profiling subcategory, can be set on stack frames and markers as part of a [`CategoryPairHandle`].
23///
24/// Subategories can be created with [`Profile::add_subcategory`](crate::Profile::add_subcategory).
25#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
26pub struct SubcategoryIndex(pub u8);
27
28/// A profiling category pair, consisting of a category and an optional subcategory. Can be set on stack frames and markers.
29///
30/// Category pairs can be created with [`Profile::add_subcategory`](crate::Profile::add_subcategory)
31/// and from a [`CategoryHandle`].
32#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
33pub struct CategoryPairHandle(
34    pub(crate) CategoryHandle,
35    pub(crate) Option<SubcategoryIndex>,
36);
37
38impl From<CategoryHandle> for CategoryPairHandle {
39    fn from(category: CategoryHandle) -> Self {
40        CategoryPairHandle(category, None)
41    }
42}
43
44/// The information about a category.
45#[derive(Debug)]
46pub struct Category {
47    pub name: String,
48    pub color: CategoryColor,
49    pub subcategories: Vec<String>,
50}
51
52impl Category {
53    /// Add a subcategory to this category.
54    pub fn add_subcategory(&mut self, subcategory_name: String) -> SubcategoryIndex {
55        let subcategory_index = SubcategoryIndex(u8::try_from(self.subcategories.len()).unwrap());
56        self.subcategories.push(subcategory_name);
57        subcategory_index
58    }
59}
60
61impl Serialize for Category {
62    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63        let mut subcategories = self.subcategories.clone();
64        subcategories.push("Other".to_string());
65
66        let mut map = serializer.serialize_map(None)?;
67        map.serialize_entry("name", &self.name)?;
68        map.serialize_entry("color", &self.color)?;
69        map.serialize_entry("subcategories", &subcategories)?;
70        map.end()
71    }
72}
73
74#[derive(Debug, Clone)]
75pub enum Subcategory {
76    Normal(SubcategoryIndex),
77    Other(CategoryHandle),
78}
79
80pub struct SerializableSubcategoryColumn<'a>(pub &'a [Subcategory], pub &'a [Category]);
81
82impl<'a> Serialize for SerializableSubcategoryColumn<'a> {
83    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
84        let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
85        for subcategory in self.0 {
86            match subcategory {
87                Subcategory::Normal(index) => seq.serialize_element(&index.0)?,
88                Subcategory::Other(category) => {
89                    // There is an implicit "Other" subcategory at the end of each category's
90                    // subcategory list.
91                    let subcategory_count = self.1[category.0 as usize].subcategories.len();
92                    seq.serialize_element(&subcategory_count)?
93                }
94            }
95        }
96        seq.end()
97    }
98}