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(&self) -> RawAttachmentRef<'_> {
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(
166 self,
167 report_formatting_function: FormattingFunction,
168 ) -> AttachmentFormattingStyle {
169 let vtable = self.vtable();
170 unsafe { vtable.preferred_formatting_style(self, report_formatting_function) }
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use alloc::string::String;
180
181 use super::*;
182 use crate::handlers::AttachmentHandler;
183
184 struct HandlerI32;
185 impl AttachmentHandler<i32> for HandlerI32 {
186 fn display(value: &i32, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187 core::fmt::Display::fmt(value, formatter)
188 }
189
190 fn debug(value: &i32, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191 core::fmt::Debug::fmt(value, formatter)
192 }
193 }
194
195 struct HandlerString;
196 impl AttachmentHandler<String> for HandlerString {
197 fn display(value: &String, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198 core::fmt::Display::fmt(value, formatter)
199 }
200 fn debug(value: &String, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
201 core::fmt::Debug::fmt(value, formatter)
202 }
203 }
204
205 #[test]
206 fn test_raw_attachment_size() {
207 assert_eq!(
208 core::mem::size_of::<RawAttachment>(),
209 core::mem::size_of::<usize>()
210 );
211 assert_eq!(
212 core::mem::size_of::<Option<RawAttachment>>(),
213 core::mem::size_of::<usize>()
214 );
215 assert_eq!(
216 core::mem::size_of::<Result<(), RawAttachment>>(),
217 core::mem::size_of::<usize>()
218 );
219 assert_eq!(
220 core::mem::size_of::<Result<String, RawAttachment>>(),
221 core::mem::size_of::<String>()
222 );
223 assert_eq!(
224 core::mem::size_of::<Option<Option<RawAttachment>>>(),
225 core::mem::size_of::<Option<usize>>()
226 );
227
228 assert_eq!(
229 core::mem::size_of::<RawAttachmentRef<'_>>(),
230 core::mem::size_of::<usize>()
231 );
232 assert_eq!(
233 core::mem::size_of::<Option<RawAttachmentRef<'_>>>(),
234 core::mem::size_of::<usize>()
235 );
236 assert_eq!(
237 core::mem::size_of::<Result<(), RawAttachmentRef<'_>>>(),
238 core::mem::size_of::<usize>()
239 );
240 assert_eq!(
241 core::mem::size_of::<Result<String, RawAttachmentRef<'_>>>(),
242 core::mem::size_of::<String>()
243 );
244 assert_eq!(
245 core::mem::size_of::<Option<Option<RawAttachmentRef<'_>>>>(),
246 core::mem::size_of::<Option<usize>>()
247 );
248 }
249
250 #[test]
251 fn test_raw_attachment_get_refs() {
252 let attachment = RawAttachment::new::<i32, HandlerI32>(100);
253 let attachment_ref = attachment.as_ref();
254
255 let ptr1 = attachment_ref.as_ptr();
257 let ptr2 = attachment_ref.as_ptr();
258 assert_eq!(ptr1, ptr2);
259 }
260
261 #[test]
262 fn test_raw_attachment_downcast() {
263 let int_attachment = RawAttachment::new::<i32, HandlerI32>(42);
264 let string_attachment = RawAttachment::new::<String, HandlerString>(String::from("test"));
265
266 let int_ref = int_attachment.as_ref();
267 let string_ref = string_attachment.as_ref();
268
269 assert_eq!(int_ref.attachment_type_id(), TypeId::of::<i32>());
271 assert_eq!(string_ref.attachment_type_id(), TypeId::of::<String>());
272
273 assert!(!core::ptr::eq(int_ref.vtable(), string_ref.vtable()));
275
276 assert!(int_ref.attachment_downcast::<String>().is_none());
278 assert!(string_ref.attachment_downcast::<i32>().is_none());
279
280 assert_eq!(int_ref.attachment_downcast::<i32>().unwrap(), &42);
282 assert_eq!(string_ref.attachment_downcast::<String>().unwrap(), "test");
283 }
284
285 #[test]
286 fn test_raw_attachment_display_debug() {
287 use alloc::format;
288
289 let int_attachment = RawAttachment::new::<i32, HandlerI32>(42);
290 let string_attachment = RawAttachment::new::<String, HandlerString>(String::from("test"));
291
292 let int_ref = int_attachment.as_ref();
293 let string_ref = string_attachment.as_ref();
294
295 let display_int = format!(
297 "{}",
298 TestDisplayFormatter::new(|f| int_ref.attachment_display(f))
299 );
300 let display_string = format!(
301 "{}",
302 TestDisplayFormatter::new(|f| string_ref.attachment_display(f))
303 );
304
305 assert_eq!(display_int, "42");
306 assert_eq!(display_string, "test");
307
308 let debug_int = format!(
310 "{}",
311 TestDisplayFormatter::new(|f| int_ref.attachment_debug(f))
312 );
313 let debug_string = format!(
314 "{}",
315 TestDisplayFormatter::new(|f| string_ref.attachment_debug(f))
316 );
317
318 assert_eq!(debug_int, "42");
319 assert_eq!(debug_string, "\"test\"");
320 }
321
322 struct TestDisplayFormatter<F> {
324 formatter_fn: F,
325 }
326
327 impl<F> TestDisplayFormatter<F>
328 where
329 F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
330 {
331 fn new(formatter_fn: F) -> Self {
332 Self { formatter_fn }
333 }
334 }
335
336 impl<F> core::fmt::Display for TestDisplayFormatter<F>
337 where
338 F: Fn(&mut core::fmt::Formatter<'_>) -> core::fmt::Result,
339 {
340 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
341 (self.formatter_fn)(f)
342 }
343 }
344}