1 | use smallvec::SmallVec; |
2 | |
3 | use crate::{Profiler, StringComponent, StringId}; |
4 | |
5 | /// Event IDs are strings conforming to the following grammar: |
6 | /// |
7 | /// ```ignore |
8 | /// <event_id> = <label> {<argument>} |
9 | /// <label> = <text> |
10 | /// <argument> = ' \x1E' <text> |
11 | /// <text> = regex([[[:^cntrl:]][[:space:]]]+) // Anything but ASCII control characters except for whitespace. |
12 | /// ``` |
13 | /// |
14 | /// This means there's always a "label", followed by an optional list of |
15 | /// arguments. Future versions may support other optional suffixes (with a tag |
16 | /// other than '\x11' after the '\x1E' separator), such as a "category". |
17 | |
18 | /// The byte used to separate arguments from the label and each other. |
19 | pub const SEPARATOR_BYTE: &str = " \x1E" ; |
20 | |
21 | /// An `EventId` is a `StringId` with the additional guarantee that the |
22 | /// corresponding string conforms to the event_id grammar. |
23 | #[derive (Clone, Copy, Eq, PartialEq, Hash, Debug)] |
24 | #[repr (C)] |
25 | pub struct EventId(StringId); |
26 | |
27 | impl EventId { |
28 | pub const INVALID: EventId = EventId(StringId::INVALID); |
29 | |
30 | #[inline ] |
31 | pub fn to_string_id(self) -> StringId { |
32 | self.0 |
33 | } |
34 | |
35 | #[inline ] |
36 | pub fn as_u64(self) -> u64 { |
37 | self.0.as_u64() |
38 | } |
39 | |
40 | #[inline ] |
41 | pub fn from_label(label: StringId) -> Self { |
42 | EventId(label) |
43 | } |
44 | |
45 | #[inline ] |
46 | pub fn from_virtual(virtual_id: StringId) -> Self { |
47 | EventId(virtual_id) |
48 | } |
49 | |
50 | /// Create an EventId from a raw u64 value. Only used internally for |
51 | /// deserialization. |
52 | #[inline ] |
53 | pub fn from_u64(raw_id: u64) -> Self { |
54 | EventId(StringId::new(raw_id)) |
55 | } |
56 | } |
57 | |
58 | pub struct EventIdBuilder<'p> { |
59 | profiler: &'p Profiler, |
60 | } |
61 | |
62 | impl<'p> EventIdBuilder<'p> { |
63 | pub fn new(profiler: &Profiler) -> EventIdBuilder<'_> { |
64 | EventIdBuilder { profiler } |
65 | } |
66 | |
67 | #[inline ] |
68 | pub fn from_label(&self, label: StringId) -> EventId { |
69 | // Just forward the string ID, a single identifier is a valid event_id |
70 | EventId::from_label(label) |
71 | } |
72 | |
73 | pub fn from_label_and_arg(&self, label: StringId, arg: StringId) -> EventId { |
74 | EventId(self.profiler.alloc_string(&[ |
75 | // Label |
76 | StringComponent::Ref(label), |
77 | // Seperator and start tag for arg |
78 | StringComponent::Value(SEPARATOR_BYTE), |
79 | // Arg string id |
80 | StringComponent::Ref(arg), |
81 | ])) |
82 | } |
83 | |
84 | pub fn from_label_and_args(&self, label: StringId, args: &[StringId]) -> EventId { |
85 | // Store up to 7 components on the stack: 1 label + 3 arguments + 3 argument separators |
86 | let mut parts = SmallVec::<[StringComponent<'_>; 7]>::with_capacity(1 + args.len() * 2); |
87 | |
88 | parts.push(StringComponent::Ref(label)); |
89 | |
90 | for arg in args { |
91 | parts.push(StringComponent::Value(SEPARATOR_BYTE)); |
92 | parts.push(StringComponent::Ref(*arg)); |
93 | } |
94 | |
95 | EventId(self.profiler.alloc_string(&parts[..])) |
96 | } |
97 | } |
98 | |