micromegas_tracing/
property_set.rs1use crate::{dyn_deps::static_ref_str, static_string_ref::StaticStringRef};
5use internment::Intern;
6use micromegas_transit::{HeterogeneousQueue, StaticStringDependency, UserDefinedType, prelude::*};
7use rustc_hash::FxHashSet;
8use std::{
9 borrow::Cow,
10 hash::Hash,
11 sync::{Arc, OnceLock},
12};
13
14lazy_static::lazy_static! {
15 pub static ref PROPERTY_SET_DEP_TYPE_NAME: Arc<String> = Arc::new("PropertySetDependency".into());
16}
17
18#[derive(Debug, Eq, PartialEq, Hash, Clone, TransitReflect)]
19pub struct Property {
20 pub name: StaticStringRef,
21 pub value: StaticStringRef,
22}
23
24impl Property {
25 pub fn new(name: &'static str, value: &'static str) -> Self {
26 Self {
27 name: name.into(),
28 value: value.into(),
29 }
30 }
31}
32
33#[derive(Debug, Clone, Copy)]
44pub struct DynProperty<'a> {
45 name: &'a str,
46 value: &'a str,
47 static_name: bool,
49}
50
51impl<'a> DynProperty<'a> {
52 pub const fn new(name: &'static str, value: &'a str) -> Self {
53 Self {
54 name,
55 value,
56 static_name: true,
57 }
58 }
59
60 pub const fn with_dyn_name(name: &'a str, value: &'a str) -> Self {
61 Self {
62 name,
63 value,
64 static_name: false,
65 }
66 }
67
68 pub fn name(&self) -> &'a str {
69 self.name
70 }
71
72 pub fn value(&self) -> &'a str {
73 self.value
74 }
75
76 pub(crate) fn is_static_name(&self) -> bool {
77 self.static_name
78 }
79}
80
81pub fn callsite_set(
86 cell: &'static OnceLock<&'static PropertySet>,
87 pairs: &'static [(&'static str, &'static str)],
88) -> &'static PropertySet {
89 cell.get_or_init(|| {
90 let mut properties: Vec<Property> = Vec::with_capacity(pairs.len());
91 apply_pairs(&mut properties, pairs.iter().copied());
92 PropertySet::find_or_create(properties)
93 })
94}
95
96pub fn apply_pairs(
99 properties: &mut Vec<Property>,
100 pairs: impl IntoIterator<Item = (&'static str, &'static str)>,
101) {
102 for (name, value) in pairs {
103 properties.retain(|p| !p.name.as_str().eq_ignore_ascii_case(name));
104 properties.push(Property::new(name, value));
105 }
106}
107
108#[inline(always)]
111pub fn static_value(v: &'static str) -> &'static str {
112 v
113}
114
115pub fn dyn_property_get<'a>(properties: &[DynProperty<'a>], name: &str) -> Option<&'a str> {
116 properties
117 .iter()
118 .find(|p| p.name.eq_ignore_ascii_case(name))
119 .map(|p| p.value)
120}
121
122pub fn property_get<'a>(properties: &'a [Property], name: &str) -> Option<&'a str> {
123 properties.iter().find_map(|p| {
124 if p.name.as_str().eq_ignore_ascii_case(name) {
125 Some(p.value.as_str())
126 } else {
127 None
128 }
129 })
130}
131
132#[derive(Debug, Clone)]
133pub struct PropertySet {
134 pub(crate) properties: Vec<Property>,
135 dyn_view: Box<[DynProperty<'static>]>,
137}
138
139impl PartialEq for PropertySet {
141 fn eq(&self, other: &Self) -> bool {
142 self.properties == other.properties
143 }
144}
145
146impl Eq for PropertySet {}
147
148impl Hash for PropertySet {
149 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
150 self.properties.hash(state);
151 }
152}
153
154pub(crate) fn sort_properties(properties: &mut [Property]) {
156 properties.sort_by(|a, b| b.name.as_str().cmp(a.name.as_str()));
157}
158
159pub(crate) fn cmp_dyn_properties(a: &DynProperty<'_>, b: &DynProperty<'_>) -> std::cmp::Ordering {
161 b.name.cmp(a.name)
162}
163
164impl PropertySet {
165 pub fn find_or_create(mut properties: Vec<Property>) -> &'static Self {
166 sort_properties(&mut properties);
167 let dyn_view = properties
170 .iter()
171 .map(|p| unsafe { DynProperty::new(static_ref_str(&p.name), static_ref_str(&p.value)) })
172 .collect();
173 let set = PropertySet {
174 properties,
175 dyn_view,
176 };
177 Intern::<PropertySet>::new(set).as_ref()
178 }
179
180 pub fn empty() -> &'static Self {
182 lazy_static::lazy_static! {
183 static ref EMPTY: &'static PropertySet = PropertySet::find_or_create(vec![]);
184 }
185 *EMPTY
186 }
187
188 pub fn get_properties(&self) -> &[Property] {
189 &self.properties
190 }
191
192 pub fn dyn_properties(&'static self) -> &'static [DynProperty<'static>] {
193 &self.dyn_view
194 }
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200#[repr(transparent)]
201pub struct PropertySetId(pub(crate) u64);
202
203const _: () = assert!(std::mem::align_of::<PropertySet>() >= 2);
205
206impl PropertySetId {
207 pub fn interned(set: &'static PropertySet) -> Self {
208 Self(set as *const PropertySet as u64)
209 }
210
211 pub fn as_interned(self) -> Option<&'static PropertySet> {
213 if self.0 & 1 != 0 {
214 return None;
215 }
216 Some(unsafe { &*(self.0 as *const PropertySet) })
218 }
219}
220
221pub trait StringDepsQueue: HeterogeneousQueue {
223 fn push_string(&mut self, dep: StaticStringDependency);
224}
225
226pub trait PropertyDepsQueue: StringDepsQueue {
228 fn push_set(&mut self, dep: PropertySetDependency);
229}
230
231#[derive(Debug)]
232pub struct PropertySetDependency {
233 pub id: u64,
234 pub properties: Cow<'static, [Property]>,
235}
236
237pub(crate) fn record_properties<D: PropertyDepsQueue>(
239 set: &'static PropertySet,
240 recorded_deps: &mut FxHashSet<u64>,
241 deps: &mut D,
242) {
243 let id = PropertySetId::interned(set).0;
244 if recorded_deps.insert(id) {
245 for prop in set.get_properties() {
246 if recorded_deps.insert(prop.name.id()) {
247 deps.push_string(prop.name.into_dependency());
248 }
249 if recorded_deps.insert(prop.value.id()) {
250 deps.push_string(prop.value.into_dependency());
251 }
252 }
253 deps.push_set(PropertySetDependency {
254 id,
255 properties: Cow::Borrowed(set.get_properties()),
256 });
257 }
258}
259
260impl Reflect for PropertySetDependency {
261 fn reflect() -> UserDefinedType {
262 UserDefinedType {
263 name: PROPERTY_SET_DEP_TYPE_NAME.clone(),
264 size: 0,
265 members: vec![],
266 is_reference: false,
267 secondary_udts: vec![Property::reflect()],
268 }
269 }
270}
271
272impl InProcSerialize for PropertySetDependency {
273 const IN_PROC_SIZE: InProcSize = InProcSize::Dynamic;
274
275 fn get_value_size(&self) -> Option<u32> {
276 let header_size: u32 = std::mem::size_of::<u64>() as u32 + std::mem::size_of::<u32>() as u32; let container_size: u32 =
279 self.properties.len() as u32 * std::mem::size_of::<Property>() as u32;
280 let size = header_size + container_size;
281 Some(size)
282 }
283
284 fn write_value(&self, buffer: &mut Vec<u8>) {
285 write_any(buffer, &self.id);
286 let nb_properties: u32 = self.properties.len() as u32;
287 write_any(buffer, &nb_properties);
288 for prop in self.properties.iter() {
289 write_any(buffer, prop);
290 }
291 }
292
293 unsafe fn read_value(mut _window: &[u8]) -> Self {
294 unimplemented!();
296 }
297}