use std::any::TypeId; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::ptr::NonNull; use std::sync::atomic::{self, AtomicUsize, Ordering}; use typst_syntax::Span; use typst_utils::{fat, HashLock, SmallBitSet}; use super::vtable; use crate::foundations::{Element, Label, NativeElement, Packed}; use crate::introspection::Location; /// The raw, low-level implementation of content. /// /// The `ptr` + `elem` fields implement a fat pointer setup similar to an /// `Arc>`, but in a manual way, allowing us to have a custom /// [vtable]. pub struct RawContent { /// A type-erased pointer to an allocation containing two things: /// - A header that is the same for all elements /// - Element-specific `data` that holds the specific element /// /// This pointer is valid for both a `Header` and an `Inner` where /// `E::ELEM == self.elem` and can be freely cast between both. This is /// possible because /// - `Inner` is `repr(C)` /// - The first field of `Inner` is `Header` /// - ISO/IEC 9899:TC2 C standard ยง 6.7.2.1 - 13 states that a pointer to a /// structure "points to its initial member" with no padding at the start ptr: NonNull
, /// Describes which kind of element this content holds. This is used for /// /// - Direct comparisons, e.g. `is::()` /// - Behavior: An `Element` is just a pointer to a `ContentVtable` /// containing not just data, but also function pointers for various /// element-specific operations that can be performed /// /// It is absolutely crucial that `elem == ::ELEM` for /// `Inner` pointed to by `ptr`. Otherwise, things will go very wrong /// since we'd be using the wrong vtable. elem: Element, /// The content's span. span: Span, } /// The allocated part of an element's representation. /// /// This is `repr(C)` to ensure that a pointer to the whole structure may be /// cast to a pointer to its first field. #[repr(C)] struct Inner { /// It is crucial that this is the first field because we cast between /// pointers to `Inner` and pointers to `Header`. See the documentation /// of `RawContent::ptr` for more details. header: Header, /// The element struct. E.g. `E = HeadingElem`. data: E, } /// The header that is shared by all elements. struct Header { /// The element's reference count. This works just like for `Arc`. /// Unfortunately, we have to reimplement reference counting because we /// have a custom fat pointer and `Arc` wouldn't know how to drop its /// contents. Something with `ManuallyDrop>` might also work, but at /// that point we're not gaining much and with the way it's implemented now /// we can also skip the unnecessary weak reference count. refs: AtomicUsize, /// Metadata for the element. meta: Meta, /// A cell for memoizing the hash of just the `data` part of the content. hash: HashLock, } /// Metadata that elements can hold. #[derive(Clone, Hash)] pub(super) struct Meta { /// An optional label attached to the element. pub label: Option