typst_library/foundations/content/
packed.rs

1use std::fmt::{self, Debug, Formatter};
2use std::hash::{Hash, Hasher};
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5
6use typst_syntax::Span;
7
8use crate::foundations::{Content, Label, NativeElement};
9use crate::introspection::Location;
10
11/// A packed element of a static type.
12#[derive(Clone)]
13#[repr(transparent)]
14pub struct Packed<T: NativeElement>(
15    /// Invariant: Must be of type `T`.
16    Content,
17    PhantomData<T>,
18);
19
20impl<T: NativeElement> Packed<T> {
21    /// Pack element while retaining its static type.
22    pub fn new(element: T) -> Self {
23        // Safety: The element is known to be of type `T`.
24        Packed(element.pack(), PhantomData)
25    }
26
27    /// Try to cast type-erased content into a statically known packed element.
28    pub fn from_ref(content: &Content) -> Option<&Self> {
29        if content.is::<T>() {
30            // Safety:
31            // - We have checked the type.
32            // - Packed<T> is repr(transparent).
33            return Some(unsafe { std::mem::transmute::<&Content, &Packed<T>>(content) });
34        }
35        None
36    }
37
38    /// Try to cast type-erased content into a statically known packed element.
39    pub fn from_mut(content: &mut Content) -> Option<&mut Self> {
40        if content.is::<T>() {
41            // Safety:
42            // - We have checked the type.
43            // - Packed<T> is repr(transparent).
44            return Some(unsafe {
45                std::mem::transmute::<&mut Content, &mut Packed<T>>(content)
46            });
47        }
48        None
49    }
50
51    /// Try to cast type-erased content into a statically known packed element.
52    pub fn from_owned(content: Content) -> Result<Self, Content> {
53        if content.is::<T>() {
54            // Safety:
55            // - We have checked the type.
56            // - Packed<T> is repr(transparent).
57            return Ok(unsafe { std::mem::transmute::<Content, Packed<T>>(content) });
58        }
59        Err(content)
60    }
61
62    /// Pack back into content.
63    pub fn pack(self) -> Content {
64        self.0
65    }
66
67    /// Pack back into a reference to content.
68    pub fn pack_ref(&self) -> &Content {
69        &self.0
70    }
71
72    /// Pack back into a mutable reference to content.
73    pub fn pack_mut(&mut self) -> &mut Content {
74        &mut self.0
75    }
76
77    /// Extract the raw underlying element.
78    pub fn unpack(self) -> T {
79        // This function doesn't yet need owned self, but might in the future.
80        (*self).clone()
81    }
82
83    /// The element's span.
84    pub fn span(&self) -> Span {
85        self.0.span()
86    }
87
88    /// Set the span of the element.
89    pub fn spanned(self, span: Span) -> Self {
90        Self(self.0.spanned(span), PhantomData)
91    }
92
93    /// Accesses the label of the element.
94    pub fn label(&self) -> Option<Label> {
95        self.0.label()
96    }
97
98    /// Accesses the location of the element.
99    pub fn location(&self) -> Option<Location> {
100        self.0.location()
101    }
102
103    /// Sets the location of the element.
104    pub fn set_location(&mut self, location: Location) {
105        self.0.set_location(location);
106    }
107}
108
109impl<T: NativeElement> AsRef<T> for Packed<T> {
110    fn as_ref(&self) -> &T {
111        self
112    }
113}
114
115impl<T: NativeElement> AsMut<T> for Packed<T> {
116    fn as_mut(&mut self) -> &mut T {
117        self
118    }
119}
120
121impl<T: NativeElement> Deref for Packed<T> {
122    type Target = T;
123
124    fn deref(&self) -> &Self::Target {
125        // Safety: Packed<T> guarantees that the content is of element type `T`.
126        unsafe { (self.0).0.data::<T>() }
127    }
128}
129
130impl<T: NativeElement> DerefMut for Packed<T> {
131    fn deref_mut(&mut self) -> &mut Self::Target {
132        // Safety: Packed<T> guarantees that the content is of element type `T`.
133        unsafe { (self.0).0.data_mut::<T>() }
134    }
135}
136
137impl<T: NativeElement + Debug> Debug for Packed<T> {
138    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
139        self.0.fmt(f)
140    }
141}
142
143impl<T: NativeElement> PartialEq for Packed<T> {
144    fn eq(&self, other: &Self) -> bool {
145        self.0 == other.0
146    }
147}
148
149impl<T: NativeElement> Hash for Packed<T> {
150    fn hash<H: Hasher>(&self, state: &mut H) {
151        self.0.hash(state);
152    }
153}