1use smallvec::SmallVec;
2
3use 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.
19pub 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)]
25pub struct EventId(StringId);
26
27impl 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
58pub struct EventIdBuilder<'p> {
59 profiler: &'p Profiler,
60}
61
62impl<'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