rootcause_internals/attachment/
raw.rs1use alloc::boxed::Box;
9use core::{any::TypeId, ptr::NonNull};
10
11use crate::{
12 attachment::data::AttachmentData,
13 handlers::{AttachmentFormattingStyle, AttachmentHandler, FormattingFunction},
14 util::{CastTo, Erased},
15};
16
17#[repr(transparent)]
29pub struct RawAttachment {
30 ptr: NonNull<AttachmentData<Erased>>,
32}
33
34impl RawAttachment {
35 #[inline]
38 pub fn new<A, H>(attachment: A) -> Self
39 where
40 A: 'static,
41 H: AttachmentHandler<A>,
42 {
43 let ptr = Box::new(AttachmentData::new::<H>(attachment));
44 let ptr: *const AttachmentData<A> = Box::into_raw(ptr);
45 let ptr: *mut AttachmentData<Erased> = ptr as _;
46
47 let ptr: NonNull<AttachmentData<Erased>> = unsafe { NonNull::new_unchecked(ptr) };
49
50 Self { ptr }
51 }
52
53 #[inline]
55 pub fn as_ref(&self) -> RawAttachmentRef<'_> {
56 RawAttachmentRef {
57 ptr: self.ptr,
58 _marker: core::marker::PhantomData,
59 }
60 }
61}
62
63impl core::ops::Drop for RawAttachment {
64 #[inline]
65 fn drop(&mut self) {
66 let vtable = self.as_ref().vtable();
67
68 unsafe {
80 vtable.drop(self.ptr);
81 }
82 }
83}
84
85#[derive(Clone, Copy)]
94#[repr(transparent)]
95pub struct RawAttachmentRef<'a> {
96 ptr: NonNull<AttachmentData<Erased>>,
98 _marker: core::marker::PhantomData<&'a AttachmentData<Erased>>,
101}
102
103impl<'a> RawAttachmentRef<'a> {
104 #[inline]
111 pub(super) unsafe fn cast_inner<A: CastTo>(self) -> &'a AttachmentData<A::Target> {
112 debug_assert_eq!(self.vtable().type_id(), TypeId::of::<A>());
114
115 let this = self.ptr.cast::<AttachmentData<A::Target>>();
116 unsafe { this.as_ref() }
120 }
121
122 #[inline]
124 pub(super) fn as_ptr(self) -> *const AttachmentData<Erased> {
125 self.ptr.as_ptr()
126 }
127
128 #[inline]
130 pub fn attachment_type_id(self) -> TypeId {
131 self.vtable().type_id()
132 }
133
134 #[inline]
136 pub fn attachment_handler_type_id(self) -> TypeId {
137 self.vtable().handler_type_id()
138 }
139
140 #[inline]
143 pub fn attachment_downcast<A: 'static>(self) -> Option<&'a A> {
144 if self.attachment_type_id() == core::any::TypeId::of::<A>() {
145 unsafe { Some(self.attachment_downcast_unchecked::<A>()) }
149 } else {
150 None
151 }
152 }
153
154 #[inline]
158 pub fn attachment_display(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
159 let vtable = self.vtable();
160 unsafe { vtable.display(self, formatter) }
165 }
166
167 #[inline]
170 pub fn attachment_debug(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
171 let vtable = self.vtable();
172 unsafe { vtable.debug(self, formatter) }
177 }
178
179 #[inline]
191 pub fn preferred_formatting_style(
192 self,
193 report_formatting_function: FormattingFunction,
194 ) -> AttachmentFormattingStyle {
195 let vtable = self.vtable();
196 unsafe { vtable.preferred_formatting_style(self, report_formatting_function) }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use alloc::string::String;
207
208 use super::*;
209 use crate::handlers::AttachmentHandler;
210
211 struct HandlerI32;
212 impl AttachmentHandler<i32> for HandlerI32 {
213 fn display(value: &i32, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
214 core::fmt::Display::fmt(value, formatter)
215 }
216
217 fn debug(value: &i32, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
218 core::fmt::Debug::fmt(value, formatter)
219 }
220 }
221
222 struct HandlerString;
223 impl AttachmentHandler<String> for HandlerString {
224 fn display(value: &String, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
225 core::fmt::Display::fmt(value, formatter)
226 }
227
228 fn debug(value: &String, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
229 core::fmt::Debug::fmt(value, formatter)
230 }
231 }
232
233 #[test]
234 fn test_raw_attachment_size() {
235 assert_eq!(
236 core::mem::size_of::<RawAttachment>(),
237 core::mem::size_of::<usize>()
238 );
239 assert_eq!(
240 core::mem::size_of::<Option<RawAttachment>>(),
241 core::mem::size_of::<usize>()
242 );
243 assert_eq!(
244 core::mem::size_of::<Result<(), RawAttachment>>(),
245 core::mem::size_of::<usize>()
246 );
247 assert_eq!(
248 core::mem::size_of::<Result<String, RawAttachment>>(),
249 core::mem::size_of::<String>()
250 );
251 assert_eq!(
252 core::mem::size_of::<Option<Option<RawAttachment>>>(),
253 core::mem::size_of::<Option<usize>>()
254 );
255
256 assert_eq!(
257 core::mem::size_of::<RawAttachmentRef<'_>>(),
258 core::mem::size_of::<usize>()
259 );
260 assert_eq!(
261 core::mem::size_of::<Option<RawAttachmentRef<'_>>>(),
262 core::mem::size_of::<usize>()
263 );
264 assert_eq!(
265 core::mem::size_of::<Result<(), RawAttachmentRef<'_>>>(),
266 core::mem::size_of::<usize>()
267 );
268 assert_eq!(
269 core::mem::size_of::<Result<String, RawAttachmentRef<'_>>>(),
270 core::mem::size_of::<String>()
271 );
272 assert_eq!(
273 core::mem::size_of::<Option<Option<RawAttachmentRef<'_>>>>(),
274 core::mem::size_of::<Option<usize>>()
275 );
276 }
277
278 #[test]
279 fn test_raw_attachment_get_refs() {
280 let attachment = RawAttachment::new::<i32, HandlerI32>(100);
281 let attachment_ref = attachment.as_ref();
282
283 let ptr1 = attachment_ref.as_ptr();
285 let ptr2 = attachment_ref.as_ptr();
286 assert_eq!(ptr1, ptr2);
287 }
288
289 #[test]
290 fn test_raw_attachment_downcast() {
291 let int_attachment = RawAttachment::new::<i32, HandlerI32>(42);
292 let string_attachment = RawAttachment::new::<String, HandlerString>(String::from("test"));
293
294 let int_ref = int_attachment.as_ref();
295 let string_ref = string_attachment.as_ref();
296
297 assert_eq!(int_ref.attachment_type_id(), TypeId::of::<i32>());
299 assert_eq!(string_ref.attachment_type_id(), TypeId::of::<String>());
300
301 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
303
304 assert!(int_ref.attachment_downcast::<String>().is_none());
306 assert!(string_ref.attachment_downcast::<i32>().is_none());
307
308 assert_eq!(int_ref.attachment_downcast::<i32>().unwrap(), &42);
310 assert_eq!(string_ref.attachment_downcast::<String>().unwrap(), "test");
311 }
312
313 #[test]
314 fn test_raw_attachment_display_debug() {
315 use alloc::format;
316
317 let int_attachment = RawAttachment::new::<i32, HandlerI32>(42);
318 let string_attachment = RawAttachment::new::<String, HandlerString>(String::from("test"));
319
320 let int_ref = int_attachment.as_ref();
321 let string_ref = string_attachment.as_ref();
322
323 let display_int = format!(
325 "{}",
326 TestDisplayFormatter::new(|f| int_ref.attachment_display(f))
327 );
328 let display_string = format!(
329 "{}",
330 TestDisplayFormatter::new(|f| string_ref.attachment_display(f))
331 );
332
333 assert_eq!(display_int, "42");
334 assert_eq!(display_string, "test");
335
336 let debug_int = format!(
338 "{}",
339 TestDisplayFormatter::new(|f| int_ref.attachment_debug(f))
340 );
341 let debug_string = format!(
342 "{}",
343 TestDisplayFormatter::new(|f| string_ref.attachment_debug(f))
344 );
345
346 assert_eq!(debug_int, "42");
347 assert_eq!(debug_string, "\"test\"");
348 }
349
350 struct TestDisplayFormatter<F> {
352 formatter_fn: F,
353 }
354
355 impl<F> TestDisplayFormatter<F>
356 where
357 F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
358 {
359 fn new(formatter_fn: F) -> Self {
360 Self { formatter_fn }
361 }
362 }
363
364 impl<F> core::fmt::Display for TestDisplayFormatter<F>
365 where
366 F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
367 {
368 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
369 (self.formatter_fn)(f)
370 }
371 }
372
373 #[test]
374 fn test_send_sync() {
375 static_assertions::assert_not_impl_any!(RawAttachment: Send, Sync);
376 static_assertions::assert_not_impl_any!(RawAttachmentRef<'_>: Send, Sync);
377 }
378}