1use crate::field::Field;
30use crate::util::Location;
31use std::num::{NonZeroU32, NonZeroU64};
32use std::sync::OnceLock;
33
34#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
35#[repr(transparent)]
36pub struct Id(NonZeroU64);
37
38impl Id {
39 pub fn new(callsite: NonZeroU32, instance: NonZeroU32) -> Self {
40 Self(unsafe {
41 NonZeroU64::new_unchecked((callsite.get() as u64) << 32 | instance.get() as u64)
42 })
43 }
44
45 pub fn from_raw(id: NonZeroU64) -> Self {
46 Self(id)
47 }
48
49 pub fn into_raw(self) -> NonZeroU64 {
50 self.0
51 }
52
53 pub fn get_callsite(&self) -> NonZeroU32 {
54 unsafe { NonZeroU32::new_unchecked((self.0.get() >> 32) as u32) }
55 }
56
57 pub fn get_instance(&self) -> NonZeroU32 {
58 unsafe { NonZeroU32::new_unchecked(self.0.get() as u32) }
59 }
60}
61
62pub struct Callsite {
63 name: &'static str,
64 location: Location,
65 id: OnceLock<NonZeroU32>,
66}
67
68impl Callsite {
69 pub const fn new(name: &'static str, location: Location) -> Self {
70 Self {
71 name,
72 location,
73 id: OnceLock::new(),
74 }
75 }
76
77 pub fn location(&self) -> &Location {
78 &self.location
79 }
80
81 pub fn name(&self) -> &'static str {
82 self.name
83 }
84
85 pub fn get_id(&'static self) -> &'static NonZeroU32 {
86 self.id
87 .get_or_init(|| crate::engine::get().register_callsite(self))
88 }
89}
90
91pub struct Entered {
92 id: Id,
93}
94
95impl Drop for Entered {
96 fn drop(&mut self) {
97 crate::engine::get().span_exit(self.id);
98 }
99}
100
101pub struct Span {
102 id: Id,
103}
104
105impl Span {
106 pub fn with_fields(callsite: &'static Callsite, fields: &[Field]) -> Self {
107 let callsite = *callsite.get_id();
108 let instance = crate::engine::get().span_create(callsite, fields);
109 Self {
110 id: Id::new(callsite, instance),
111 }
112 }
113
114 pub fn new(callsite: &'static Callsite) -> Self {
115 let callsite = *callsite.get_id();
116 let instance = crate::engine::get().span_create(callsite, &[]);
117 Self {
118 id: Id::new(callsite, instance),
119 }
120 }
121
122 pub fn record(&self, fields: &[Field]) {
123 crate::engine::get().span_record(self.id, fields);
124 }
125
126 pub fn enter(&self) -> Entered {
127 Entered { id: self.id }
128 }
129}
130
131impl Drop for Span {
132 fn drop(&mut self) {
133 crate::engine::get().span_destroy(self.id);
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use crate::profiler::section::Level;
140 use crate::{fields, span};
141
142 #[test]
143 fn api_test() {
144 let value = 32;
145 let str = "this is a test";
146 let lvl = Level::Event;
147 let _span = span!(API_TEST);
148 let span = span!(API_TEST2, {value} {str} {?lvl} {test=value});
149 span.record(fields!({ test2 = str }).as_ref());
150 let _entered = span.enter();
151 }
152}