Skip to main content

micromegas_tracing/
static_string_ref.rs

1//! StaticStringRef points to a string dependency keeping track of the codec.
2//! Necessary for unreal instrumentation where ansi and wide strings can coexist.
3//! In cases where the event format does not have to be compatible with unreal, StringId can be used.
4use micromegas_transit::{
5    Member, StaticStringDependency, UserDefinedType, prelude::*, string_codec::StringCodec,
6};
7use std::{
8    hash::{Hash, Hasher},
9    sync::Arc,
10};
11
12#[derive(Eq, PartialEq, Debug, Clone)]
13pub struct StaticStringRef {
14    pub ptr: u64,
15    pub len: u32,
16    pub codec: StringCodec,
17}
18
19impl Hash for StaticStringRef {
20    fn hash<H: Hasher>(&self, state: &mut H) {
21        self.ptr.hash(state);
22    }
23}
24
25impl Reflect for StaticStringRef {
26    fn reflect() -> UserDefinedType {
27        lazy_static::lazy_static! {
28            static ref TYPE_NAME: Arc<String> = Arc::new("StaticStringRef".into());
29            static ref ID: Arc<String> = Arc::new("id".into());
30        }
31        UserDefinedType {
32            name: TYPE_NAME.clone(),
33            size: std::mem::size_of::<Self>(),
34            members: vec![Member {
35                name: ID.clone(),
36                type_name: "usize".to_string(),
37                offset: memoffset::offset_of!(Self, ptr),
38                size: std::mem::size_of::<*const u8>(),
39                is_reference: true,
40            }],
41            is_reference: true,
42            secondary_udts: vec![],
43        }
44    }
45}
46
47impl StaticStringRef {
48    pub fn id(&self) -> u64 {
49        self.ptr
50    }
51
52    pub fn into_dependency(&self) -> StaticStringDependency {
53        StaticStringDependency {
54            id: self.ptr,
55            codec: self.codec,
56            len: self.len,
57            ptr: self.ptr as *const u8,
58        }
59    }
60
61    /// Builds a ref to `src` without requiring `'static`.
62    ///
63    /// # Safety
64    /// `src` must outlive every use of the returned ref.
65    pub(crate) unsafe fn from_str_unchecked(src: &str) -> Self {
66        Self {
67            len: src.len() as u32,
68            ptr: src.as_ptr() as u64,
69            codec: StringCodec::Utf8,
70        }
71    }
72
73    pub fn as_str(&self) -> &str {
74        unsafe {
75            let slice = std::slice::from_raw_parts(self.ptr as *const u8, self.len as usize);
76            std::str::from_utf8_unchecked(slice)
77        }
78    }
79}
80
81impl std::convert::From<&'static str> for StaticStringRef {
82    fn from(src: &'static str) -> Self {
83        Self {
84            len: src.len() as u32,
85            ptr: src.as_ptr() as u64,
86            codec: StringCodec::Utf8,
87        }
88    }
89}
90
91/// Reference to a string record in the block's dynamic dependency queue. It has the layout and
92/// the reflection of `StaticStringRef`, so the wire format is the same, but it can't be
93/// dereferenced: `id` is only meaningful to the `DynDeps` of its block.
94#[derive(Eq, PartialEq, Debug, Clone, Copy)]
95pub struct BlockStringRef {
96    pub id: u64,
97    pub len: u32,
98    pub codec: StringCodec,
99}
100
101const _: () = {
102    use std::mem::{offset_of, size_of};
103    assert!(size_of::<BlockStringRef>() == size_of::<StaticStringRef>());
104    assert!(offset_of!(BlockStringRef, id) == offset_of!(StaticStringRef, ptr));
105    assert!(offset_of!(BlockStringRef, len) == offset_of!(StaticStringRef, len));
106    assert!(offset_of!(BlockStringRef, codec) == offset_of!(StaticStringRef, codec));
107};
108
109impl Reflect for BlockStringRef {
110    fn reflect() -> UserDefinedType {
111        StaticStringRef::reflect()
112    }
113}