rootcause_internals/attachment/
raw.rs1use alloc::boxed::Box;
7use core::{any::TypeId, marker::PhantomData, ptr::NonNull};
8
9use crate::{
10 attachment::data::AttachmentData,
11 handlers::{AttachmentFormattingStyle, AttachmentHandler, FormattingFunction},
12 util::{CastTo, Erased},
13};
14
15#[repr(transparent)]
26pub struct RawAttachment {
27 ptr: NonNull<AttachmentData<Erased>>,
28 _marker: core::marker::PhantomData<AttachmentData<Erased>>,
29}
30
31impl RawAttachment {
32 pub fn new<A, H>(attachment: A) -> Self
34 where
35 A: 'static,
36 H: AttachmentHandler<A>,
37 {
38 let ptr = Box::new(AttachmentData::new::<H>(attachment));
39 let ptr: *const AttachmentData<A> = Box::into_raw(ptr);
40 let ptr: *mut AttachmentData<Erased> = ptr as _;
41
42 let ptr: NonNull<AttachmentData<Erased>> = unsafe { NonNull::new_unchecked(ptr) };
44
45 Self {
46 ptr,
47 _marker: PhantomData,
48 }
49 }
50
51 pub fn as_ref<'a>(&'a self) -> RawAttachmentRef<'a> {
53 RawAttachmentRef {
54 ptr: self.ptr,
55 _marker: core::marker::PhantomData,
56 }
57 }
58}
59
60impl core::ops::Drop for RawAttachment {
61 fn drop(&mut self) {
62 let vtable = self.as_ref().vtable();
63
64 unsafe {
74 vtable.drop(self.ptr);
75 }
76 }
77}
78
79#[derive(Clone, Copy)]
88#[repr(transparent)]
89pub struct RawAttachmentRef<'a> {
90 ptr: NonNull<AttachmentData<Erased>>,
91 _marker: core::marker::PhantomData<&'a AttachmentData<Erased>>,
92}
93
94impl<'a> RawAttachmentRef<'a> {
95 pub(super) unsafe fn cast_inner<A: CastTo>(self) -> &'a AttachmentData<A::Target> {
101 debug_assert_eq!(self.vtable().type_id(), TypeId::of::<A>());
103
104 let this = self.ptr.cast::<AttachmentData<A::Target>>();
105 unsafe { this.as_ref() }
108 }
109
110 pub(super) fn as_ptr(self) -> *const AttachmentData<Erased> {
112 self.ptr.as_ptr()
113 }
114
115 pub fn attachment_type_id(self) -> TypeId {
117 self.vtable().type_id()
118 }
119
120 pub fn attachment_handler_type_id(self) -> TypeId {
122 self.vtable().handler_type_id()
123 }
124
125 pub fn attachment_downcast<A: 'static>(self) -> Option<&'a A> {
127 if self.attachment_type_id() == core::any::TypeId::of::<A>() {
128 unsafe { Some(self.attachment_downcast_unchecked::<A>()) }
131 } else {
132 None
133 }
134 }
135
136 pub fn attachment_display(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
139 let vtable = self.vtable();
140 unsafe { vtable.display(self, formatter) }
144 }
145
146 pub fn attachment_debug(self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149 let vtable = self.vtable();
150 unsafe { vtable.debug(self, formatter) }
154 }
155
156 pub fn preferred_formatting_style(
168 self,
169 report_formatting_function: FormattingFunction,
170 report_formatting_alternate: bool,
171 ) -> AttachmentFormattingStyle {
172 let vtable = self.vtable();
173 unsafe {
177 vtable.preferred_formatting_style(
178 self,
179 report_formatting_function,
180 report_formatting_alternate,
181 )
182 }
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use alloc::string::String;
189
190 use super::*;
191 use crate::handlers::AttachmentHandler;
192
193 struct HandlerI32;
194 impl AttachmentHandler<i32> for HandlerI32 {
195 fn display(value: &i32, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
196 core::fmt::Display::fmt(value, formatter)
197 }
198
199 fn debug(value: &i32, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200 core::fmt::Debug::fmt(value, formatter)
201 }
202 }
203
204 struct HandlerString;
205 impl AttachmentHandler<String> for HandlerString {
206 fn display(value: &String, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
207 core::fmt::Display::fmt(value, formatter)
208 }
209 fn debug(value: &String, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
210 core::fmt::Debug::fmt(value, formatter)
211 }
212 }
213
214 #[test]
215 fn test_raw_attachment_size() {
216 assert_eq!(
217 core::mem::size_of::<RawAttachment>(),
218 core::mem::size_of::<usize>()
219 );
220 assert_eq!(
221 core::mem::size_of::<Option<RawAttachment>>(),
222 core::mem::size_of::<usize>()
223 );
224 assert_eq!(
225 core::mem::size_of::<Result<(), RawAttachment>>(),
226 core::mem::size_of::<usize>()
227 );
228 assert_eq!(
229 core::mem::size_of::<Result<String, RawAttachment>>(),
230 core::mem::size_of::<String>()
231 );
232 assert_eq!(
233 core::mem::size_of::<Option<Option<RawAttachment>>>(),
234 core::mem::size_of::<Option<usize>>()
235 );
236
237 assert_eq!(
238 core::mem::size_of::<RawAttachmentRef<'_>>(),
239 core::mem::size_of::<usize>()
240 );
241 assert_eq!(
242 core::mem::size_of::<Option<RawAttachmentRef<'_>>>(),
243 core::mem::size_of::<usize>()
244 );
245 assert_eq!(
246 core::mem::size_of::<Result<(), RawAttachmentRef<'_>>>(),
247 core::mem::size_of::<usize>()
248 );
249 assert_eq!(
250 core::mem::size_of::<Result<String, RawAttachmentRef<'_>>>(),
251 core::mem::size_of::<String>()
252 );
253 assert_eq!(
254 core::mem::size_of::<Option<Option<RawAttachmentRef<'_>>>>(),
255 core::mem::size_of::<Option<usize>>()
256 );
257 }
258
259 #[test]
260 fn test_raw_attachment_get_refs() {
261 let attachment = RawAttachment::new::<i32, HandlerI32>(100);
262 let attachment_ref = attachment.as_ref();
263
264 let ptr1 = attachment_ref.as_ptr();
266 let ptr2 = attachment_ref.as_ptr();
267 assert_eq!(ptr1, ptr2);
268 }
269
270 #[test]
271 fn test_raw_attachment_downcast() {
272 let int_attachment = RawAttachment::new::<i32, HandlerI32>(42);
273 let string_attachment = RawAttachment::new::<String, HandlerString>(String::from("test"));
274
275 let int_ref = int_attachment.as_ref();
276 let string_ref = string_attachment.as_ref();
277
278 assert_eq!(int_ref.attachment_type_id(), TypeId::of::<i32>());
280 assert_eq!(string_ref.attachment_type_id(), TypeId::of::<String>());
281
282 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
284
285 assert!(int_ref.attachment_downcast::<String>().is_none());
287 assert!(string_ref.attachment_downcast::<i32>().is_none());
288
289 assert_eq!(int_ref.attachment_downcast::<i32>().unwrap(), &42);
291 assert_eq!(string_ref.attachment_downcast::<String>().unwrap(), "test");
292 }
293
294 #[test]
295 fn test_raw_attachment_display_debug() {
296 use alloc::format;
297
298 let int_attachment = RawAttachment::new::<i32, HandlerI32>(42);
299 let string_attachment = RawAttachment::new::<String, HandlerString>(String::from("test"));
300
301 let int_ref = int_attachment.as_ref();
302 let string_ref = string_attachment.as_ref();
303
304 let display_int = format!(
306 "{}",
307 TestDisplayFormatter::new(|f| int_ref.attachment_display(f))
308 );
309 let display_string = format!(
310 "{}",
311 TestDisplayFormatter::new(|f| string_ref.attachment_display(f))
312 );
313
314 assert_eq!(display_int, "42");
315 assert_eq!(display_string, "test");
316
317 let debug_int = format!(
319 "{}",
320 TestDisplayFormatter::new(|f| int_ref.attachment_debug(f))
321 );
322 let debug_string = format!(
323 "{}",
324 TestDisplayFormatter::new(|f| string_ref.attachment_debug(f))
325 );
326
327 assert_eq!(debug_int, "42");
328 assert_eq!(debug_string, "\"test\"");
329 }
330
331 struct TestDisplayFormatter<F> {
333 formatter_fn: F,
334 }
335
336 impl<F> TestDisplayFormatter<F>
337 where
338 F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
339 {
340 fn new(formatter_fn: F) -> Self {
341 Self { formatter_fn }
342 }
343 }
344
345 impl<F> core::fmt::Display for TestDisplayFormatter<F>
346 where
347 F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
348 {
349 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
350 (self.formatter_fn)(f)
351 }
352 }
353}