summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst-macros/src/elem.rs413
-rw-r--r--crates/typst-pdf/src/outline.rs26
-rw-r--r--crates/typst/src/foundations/cast.rs35
-rw-r--r--crates/typst/src/foundations/content.rs454
-rw-r--r--crates/typst/src/foundations/element.rs136
-rw-r--r--crates/typst/src/foundations/styles.rs7
-rw-r--r--crates/typst/src/introspection/counter.rs16
-rw-r--r--crates/typst/src/introspection/locate.rs8
-rw-r--r--crates/typst/src/introspection/metadata.rs8
-rw-r--r--crates/typst/src/introspection/mod.rs5
-rw-r--r--crates/typst/src/introspection/state.rs12
-rw-r--r--crates/typst/src/layout/align.rs6
-rw-r--r--crates/typst/src/layout/columns.rs6
-rw-r--r--crates/typst/src/layout/container.rs6
-rw-r--r--crates/typst/src/layout/flow.rs18
-rw-r--r--crates/typst/src/layout/grid/mod.rs16
-rw-r--r--crates/typst/src/layout/hide.rs4
-rw-r--r--crates/typst/src/layout/inline/mod.rs8
-rw-r--r--crates/typst/src/layout/layout.rs8
-rw-r--r--crates/typst/src/layout/pad.rs4
-rw-r--r--crates/typst/src/layout/page.rs10
-rw-r--r--crates/typst/src/layout/place.rs8
-rw-r--r--crates/typst/src/layout/repeat.rs4
-rw-r--r--crates/typst/src/layout/spacing.rs14
-rw-r--r--crates/typst/src/layout/stack.rs4
-rw-r--r--crates/typst/src/layout/transform.rs8
-rw-r--r--crates/typst/src/math/accent.rs4
-rw-r--r--crates/typst/src/math/align.rs4
-rw-r--r--crates/typst/src/math/attach.rs22
-rw-r--r--crates/typst/src/math/cancel.rs4
-rw-r--r--crates/typst/src/math/class.rs4
-rw-r--r--crates/typst/src/math/ctx.rs8
-rw-r--r--crates/typst/src/math/equation.rs59
-rw-r--r--crates/typst/src/math/frac.rs6
-rw-r--r--crates/typst/src/math/lr.rs11
-rw-r--r--crates/typst/src/math/matrix.rs10
-rw-r--r--crates/typst/src/math/op.rs4
-rw-r--r--crates/typst/src/math/root.rs6
-rw-r--r--crates/typst/src/math/style.rs32
-rw-r--r--crates/typst/src/math/underover.rs14
-rw-r--r--crates/typst/src/model/bibliography.rs51
-rw-r--r--crates/typst/src/model/cite.rs21
-rw-r--r--crates/typst/src/model/document.rs5
-rw-r--r--crates/typst/src/model/emph.rs4
-rw-r--r--crates/typst/src/model/enum.rs13
-rw-r--r--crates/typst/src/model/figure.rs98
-rw-r--r--crates/typst/src/model/footnote.rs32
-rw-r--r--crates/typst/src/model/heading.rs67
-rw-r--r--crates/typst/src/model/link.rs4
-rw-r--r--crates/typst/src/model/list.rs15
-rw-r--r--crates/typst/src/model/outline.rs18
-rw-r--r--crates/typst/src/model/par.rs6
-rw-r--r--crates/typst/src/model/quote.rs21
-rw-r--r--crates/typst/src/model/reference.rs56
-rw-r--r--crates/typst/src/model/strong.rs4
-rw-r--r--crates/typst/src/model/table.rs18
-rw-r--r--crates/typst/src/model/terms.rs8
-rw-r--r--crates/typst/src/realize/mod.rs57
-rw-r--r--crates/typst/src/text/deco.rs12
-rw-r--r--crates/typst/src/text/linebreak.rs4
-rw-r--r--crates/typst/src/text/mod.rs3
-rw-r--r--crates/typst/src/text/raw.rs58
-rw-r--r--crates/typst/src/text/shift.rs6
-rw-r--r--crates/typst/src/text/space.rs10
-rw-r--r--crates/typst/src/visualize/image/mod.rs12
-rw-r--r--crates/typst/src/visualize/line.rs4
-rw-r--r--crates/typst/src/visualize/path.rs4
-rw-r--r--crates/typst/src/visualize/polygon.rs8
-rw-r--r--crates/typst/src/visualize/shape.rs10
69 files changed, 1012 insertions, 1049 deletions
diff --git a/crates/typst-macros/src/elem.rs b/crates/typst-macros/src/elem.rs
index 2199ec92..6ab437cd 100644
--- a/crates/typst-macros/src/elem.rs
+++ b/crates/typst-macros/src/elem.rs
@@ -311,6 +311,8 @@ fn create(element: &Elem) -> Result<TokenStream> {
settable.clone().map(|field| create_set_field_method(element, field));
// Trait implementations.
+ let fields_impl = create_fields_impl(element);
+ let capable_impl = create_capable_impl(element);
let native_element_impl = create_native_elem_impl(element);
let construct_impl =
element.unless_capability("Construct", || create_construct_impl(element));
@@ -321,23 +323,11 @@ fn create(element: &Elem) -> Result<TokenStream> {
element.unless_capability("PartialEq", || create_partial_eq_impl(element));
let repr_impl = element.unless_capability("Repr", || create_repr_impl(element));
- let label_and_location = element.unless_capability("Unlabellable", || {
- quote! {
- location: Option<::typst::introspection::Location>,
- label: Option<#foundations::Label>,
- prepared: bool,
- }
- });
-
Ok(quote! {
#[doc = #docs]
#[derive(Debug, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
#vis struct #ident {
- span: ::typst::syntax::Span,
- #label_and_location
- guards: ::std::vec::Vec<#foundations::Guard>,
-
#(#fields,)*
}
@@ -353,6 +343,8 @@ fn create(element: &Elem) -> Result<TokenStream> {
}
#native_element_impl
+ #fields_impl
+ #capable_impl
#construct_impl
#set_impl
#locatable_impl
@@ -406,6 +398,8 @@ fn create_fields_enum(element: &Elem) -> TokenStream {
quote! { #enum_ident }
});
+ let enum_repr = (!fields.is_empty()).then(|| quote! { #[repr(u8)] });
+
quote! {
// To hide the private type
const _: () = {
@@ -414,10 +408,9 @@ fn create_fields_enum(element: &Elem) -> TokenStream {
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
- #[repr(u8)]
+ #enum_repr
pub enum #enum_ident {
#(#definitions,)*
- Label = 255,
}
impl #enum_ident {
@@ -425,7 +418,6 @@ fn create_fields_enum(element: &Elem) -> TokenStream {
pub fn to_str(self) -> &'static str {
match self {
#(Self::#field_variants => #field_names,)*
- Self::Label => "label",
}
}
}
@@ -437,7 +429,6 @@ fn create_fields_enum(element: &Elem) -> TokenStream {
#(const #field_consts: u8 = #enum_ident::#field_variants as u8;)*
match value {
#(#field_consts => Ok(Self::#field_variants),)*
- 255 => Ok(Self::Label),
_ => Err(()),
}
}
@@ -455,7 +446,6 @@ fn create_fields_enum(element: &Elem) -> TokenStream {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#(#field_names => Ok(Self::#field_variants),)*
- "label" => Ok(Self::Label),
_ => Err(()),
}
}
@@ -495,21 +485,10 @@ fn create_new_func(element: &Elem) -> TokenStream {
}
});
- let label_and_location = element.unless_capability("Unlabellable", || {
- quote! {
- location: None,
- label: None,
- prepared: false,
- }
- });
-
quote! {
/// Create a new element.
pub fn new(#(#params),*) -> Self {
Self {
- span: ::typst::syntax::Span::detached(),
- #label_and_location
- guards: ::std::vec::Vec::with_capacity(0),
#(#required,)*
#(#defaults,)*
#(#default_synthesized,)*
@@ -700,7 +679,6 @@ fn create_style_chain_access(
fn create_native_elem_impl(element: &Elem) -> TokenStream {
let Elem { name, ident, title, scope, keywords, docs, .. } = element;
- let vtable_func = create_vtable_func(element);
let params = element
.fields
.iter()
@@ -713,30 +691,48 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream {
quote! { #foundations::Scope::new() }
};
- // Fields that can be accessed using the `field` method.
- let field_matches = element.visible_fields().map(|field| {
- let elem = &element.ident;
- let name = &field.enum_ident;
- let field_ident = &field.ident;
+ let local_name = element
+ .if_capability(
+ "LocalName",
+ || quote! { Some(<#foundations::Packed<#ident> as ::typst::text::LocalName>::local_name) },
+ )
+ .unwrap_or_else(|| quote! { None });
- if field.ghost {
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#name => None,
- }
- } else if field.inherent() || (field.synthesized && field.default.is_some()) {
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#name => Some(
- #foundations::IntoValue::into_value(self.#field_ident.clone())
- ),
- }
- } else {
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#name => {
- self.#field_ident.clone().map(#foundations::IntoValue::into_value)
- }
+ let data = quote! {
+ #foundations::NativeElementData {
+ name: #name,
+ title: #title,
+ docs: #docs,
+ keywords: &[#(#keywords),*],
+ construct: <#ident as #foundations::Construct>::construct,
+ set: <#ident as #foundations::Set>::set,
+ vtable: <#ident as #foundations::Capable>::vtable,
+ field_id: |name|
+ <
+ <#ident as #foundations::ElementFields>::Fields as ::std::str::FromStr
+ >::from_str(name).ok().map(|id| id as u8),
+ field_name: |id|
+ <
+ <#ident as #foundations::ElementFields>::Fields as ::std::convert::TryFrom<u8>
+ >::try_from(id).ok().map(<#ident as #foundations::ElementFields>::Fields::to_str),
+ local_name: #local_name,
+ scope: #foundations::Lazy::new(|| #scope),
+ params: #foundations::Lazy::new(|| ::std::vec![#(#params),*])
+ }
+ };
+
+ quote! {
+ impl #foundations::NativeElement for #ident {
+ fn data() -> &'static #foundations::NativeElementData {
+ static DATA: #foundations::NativeElementData = #data;
+ &DATA
}
}
- });
+ }
+}
+
+fn create_fields_impl(element: &Elem) -> TokenStream {
+ let Elem { ident, .. } = element;
// Fields that can be checked using the `has` method.
let field_has_matches = element.visible_fields().map(|field| {
@@ -759,80 +755,6 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream {
}
});
- // Fields that can be set using the `set_field` method.
- let field_set_matches = element
- .visible_fields()
- .filter(|field| field.settable() && !field.synthesized && !field.ghost)
- .map(|field| {
- let elem = &element.ident;
- let name = &field.enum_ident;
- let field_ident = &field.ident;
-
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#name => {
- self.#field_ident = Some(#foundations::FromValue::from_value(value)?);
- return Ok(());
- }
- }
- });
-
- // Fields that are inherent.
- let field_inherent_matches = element
- .visible_fields()
- .filter(|field| field.inherent() && !field.ghost)
- .map(|field| {
- let elem = &element.ident;
- let name = &field.enum_ident;
- let field_ident = &field.ident;
-
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#name => {
- self.#field_ident = #foundations::FromValue::from_value(value)?;
- return Ok(());
- }
- }
- });
-
- // Fields that cannot be set or are internal create an error.
- let field_not_set_matches = element
- .real_fields()
- .filter(|field| field.internal || field.synthesized || field.ghost)
- .map(|field| {
- let elem = &element.ident;
- let ident = &field.enum_ident;
- let field_name = &field.name;
- if field.internal {
- // Internal fields create an error that they are unknown.
- let unknown_field = format!("unknown field `{field_name}` on `{name}`");
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#ident => ::typst::diag::bail!(#unknown_field),
- }
- } else {
- // Fields that cannot be set create an error that they are not settable.
- let not_settable = format!("cannot set `{field_name}` on `{name}`");
- quote! {
- <#elem as #foundations::ElementFields>::Fields::#ident => ::typst::diag::bail!(#not_settable),
- }
- }
- });
-
- // Statistically compute whether we need preparation or not.
- let needs_preparation = element
- .unless_capability("Unlabellable", || {
- element
- .capabilities
- .iter()
- .any(|capability| capability == "Locatable" || capability == "Synthesize")
- .then(|| quote! { !self.prepared })
- .unwrap_or_else(|| quote! { self.label().is_some() && !self.prepared })
- })
- .unwrap_or_else(|| {
- assert!(element.capabilities.iter().all(|capability| capability
- != "Locatable"
- && capability != "Synthesize"));
- quote! { false }
- });
-
// Creation of the fields dictionary for inherent fields.
let field_dict = element
.inherent_fields()
@@ -878,226 +800,58 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream {
}
});
- let location = element
- .unless_capability("Unlabellable", || quote! { self.location })
- .unwrap_or_else(|| quote! { None });
+ // Fields that can be accessed using the `field` method.
+ let field_matches = element.visible_fields().map(|field| {
+ let elem = &element.ident;
+ let name = &field.enum_ident;
+ let field_ident = &field.ident;
- let set_location = element
- .unless_capability("Unlabellable", || {
+ if field.ghost {
quote! {
- self.location = Some(location);
+ <#elem as #foundations::ElementFields>::Fields::#name => None,
}
- })
- .unwrap_or_else(|| quote! { drop(location) });
-
- let label = element
- .unless_capability("Unlabellable", || quote! { self.label })
- .unwrap_or_else(|| quote! { None });
-
- let set_label = element
- .unless_capability("Unlabellable", || {
+ } else if field.inherent() || (field.synthesized && field.default.is_some()) {
quote! {
- self.label = Some(label);
+ <#elem as #foundations::ElementFields>::Fields::#name => Some(
+ #foundations::IntoValue::into_value(self.#field_ident.clone())
+ ),
}
- })
- .unwrap_or_else(|| quote! { drop(label) });
-
- let label_field = element
- .unless_capability("Unlabellable", || {
+ } else {
quote! {
- self.label().map(#foundations::Value::Label)
- }
- })
- .unwrap_or_else(|| quote! { None });
-
- let label_has_field = element
- .unless_capability("Unlabellable", || quote! { self.label().is_some() })
- .unwrap_or_else(|| quote! { false });
-
- let label_field_dict = element.unless_capability("Unlabellable", || {
- quote! {
- if let Some(label) = self.label() {
- fields.insert(
- "label".into(),
- #foundations::IntoValue::into_value(label)
- );
+ <#elem as #foundations::ElementFields>::Fields::#name => {
+ self.#field_ident.clone().map(#foundations::IntoValue::into_value)
+ }
}
}
});
- let mark_prepared = element
- .unless_capability("Unlabellable", || quote! { self.prepared = true; })
- .unwrap_or_else(|| quote! {});
-
- let prepared = element
- .unless_capability("Unlabellable", || quote! { self.prepared })
- .unwrap_or_else(|| quote! { true });
-
- let local_name = element
- .if_capability(
- "LocalName",
- || quote! { Some(<#ident as ::typst::text::LocalName>::local_name) },
- )
- .unwrap_or_else(|| quote! { None });
-
- let unknown_field = format!("unknown field {{}} on {name}");
- let label_error = format!("cannot set label on {name}");
- let data = quote! {
- #foundations::NativeElementData {
- name: #name,
- title: #title,
- docs: #docs,
- keywords: &[#(#keywords),*],
- construct: <#ident as #foundations::Construct>::construct,
- set: <#ident as #foundations::Set>::set,
- vtable: #vtable_func,
- field_id: |name|
- <
- <#ident as #foundations::ElementFields>::Fields as ::std::str::FromStr
- >::from_str(name).ok().map(|id| id as u8),
- field_name: |id|
- <
- <#ident as #foundations::ElementFields>::Fields as ::std::convert::TryFrom<u8>
- >::try_from(id).ok().map(<#ident as #foundations::ElementFields>::Fields::to_str),
- local_name: #local_name,
- scope: #foundations::Lazy::new(|| #scope),
- params: #foundations::Lazy::new(|| ::std::vec![#(#params),*])
- }
- };
-
quote! {
- impl #foundations::NativeElement for #ident {
- fn data() -> &'static #foundations::NativeElementData {
- static DATA: #foundations::NativeElementData = #data;
- &DATA
- }
-
- fn dyn_elem(&self) -> #foundations::Element {
- #foundations::Element::of::<Self>()
- }
-
- fn dyn_hash(&self, mut state: &mut dyn ::std::hash::Hasher) {
- // Also hash the TypeId since values with different types but
- // equal data should be different.
- ::std::hash::Hash::hash(&::std::any::TypeId::of::<Self>(), &mut state);
- ::std::hash::Hash::hash(self, &mut state);
- }
-
- fn dyn_eq(&self, other: &#foundations::Content) -> bool {
- if let Some(other) = other.to::<Self>() {
- <Self as ::std::cmp::PartialEq>::eq(self, other)
- } else {
- false
- }
- }
-
- fn dyn_clone(&self) -> ::std::sync::Arc<dyn #foundations::NativeElement> {
- ::std::sync::Arc::new(Clone::clone(self))
- }
-
- fn as_any(&self) -> &dyn ::std::any::Any {
- self
- }
-
- fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any {
- self
- }
-
- fn into_any(self: ::std::sync::Arc<Self>) -> ::std::sync::Arc<dyn ::std::any::Any + Send + Sync> {
- self
- }
-
- fn span(&self) -> ::typst::syntax::Span {
- self.span
- }
+ impl #foundations::Fields for #ident {
+ fn has(&self, id: u8) -> bool {
+ let Ok(id) = <#ident as #foundations::ElementFields>::Fields::try_from(id) else {
+ return false;
+ };
- fn set_span(&mut self, span: ::typst::syntax::Span) {
- if self.span().is_detached() {
- self.span = span;
+ match id {
+ #(#field_has_matches)*
+ _ => false,
}
}
- fn label(&self) -> Option<#foundations::Label> {
- #label
- }
-
- fn set_label(&mut self, label: #foundations::Label) {
- #set_label
- }
-
- fn location(&self) -> Option<::typst::introspection::Location> {
- #location
- }
-
- fn set_location(&mut self, location: ::typst::introspection::Location) {
- #set_location
- }
-
- fn push_guard(&mut self, guard: #foundations::Guard) {
- self.guards.push(guard);
- }
-
- fn is_guarded(&self, guard: #foundations::Guard) -> bool {
- self.guards.contains(&guard)
- }
-
- fn is_pristine(&self) -> bool {
- self.guards.is_empty()
- }
-
- fn mark_prepared(&mut self) {
- #mark_prepared
- }
-
- fn needs_preparation(&self) -> bool {
- #needs_preparation
- }
-
- fn is_prepared(&self) -> bool {
- #prepared
- }
-
fn field(&self, id: u8) -> Option<#foundations::Value> {
let id = <#ident as #foundations::ElementFields>::Fields::try_from(id).ok()?;
match id {
- <#ident as #foundations::ElementFields>::Fields::Label => #label_field,
#(#field_matches)*
_ => None,
}
}
- fn has(&self, id: u8) -> bool {
- let Ok(id) = <#ident as #foundations::ElementFields>::Fields::try_from(id) else {
- return false;
- };
-
- match id {
- <#ident as #foundations::ElementFields>::Fields::Label => #label_has_field,
- #(#field_has_matches)*
- _ => false,
- }
- }
-
fn fields(&self) -> #foundations::Dict {
let mut fields = #foundations::Dict::new();
- #label_field_dict
#(#field_dict)*
#(#field_opt_dict)*
fields
}
-
- fn set_field(&mut self, id: u8, value: #foundations::Value) -> ::typst::diag::StrResult<()> {
- let id = <#ident as #foundations::ElementFields>::Fields::try_from(id)
- .map_err(|_| ::ecow::eco_format!(#unknown_field, id))?;
- match id {
- #(#field_set_matches)*
- #(#field_inherent_matches)*
- #(#field_not_set_matches)*
- <#ident as #foundations::ElementFields>::Fields::Label => {
- ::typst::diag::bail!(#label_error);
- }
- }
- }
}
}
}
@@ -1182,7 +936,7 @@ fn create_set_impl(element: &Elem) -> TokenStream {
/// Creates the element's `Locatable` implementation.
fn create_locatable_impl(element: &Elem) -> TokenStream {
let ident = &element.ident;
- quote! { impl ::typst::introspection::Locatable for #ident {} }
+ quote! { impl ::typst::introspection::Locatable for #foundations::Packed<#ident> {} }
}
/// Creates the element's `PartialEq` implementation.
@@ -1208,7 +962,7 @@ fn create_repr_impl(element: &Elem) -> TokenStream {
quote! {
impl #foundations::Repr for #ident {
fn repr(&self) -> ::ecow::EcoString {
- let fields = #foundations::NativeElement::fields(self).into_iter()
+ let fields = #foundations::Fields::fields(self).into_iter()
.map(|(name, value)| ::ecow::eco_format!("{}: {}", name, value.repr()))
.collect::<Vec<_>>();
::ecow::eco_format!(#repr_format, #foundations::repr::pretty_array_like(&fields, false))
@@ -1218,9 +972,9 @@ fn create_repr_impl(element: &Elem) -> TokenStream {
}
/// Creates the element's casting vtable.
-fn create_vtable_func(element: &Elem) -> TokenStream {
+fn create_capable_impl(element: &Elem) -> TokenStream {
// Forbidden capabilities (i.e capabilities that are not object safe).
- const FORBIDDEN: &[&str] = &["Construct", "PartialEq", "Hash", "LocalName"];
+ const FORBIDDEN: &[&str] = &["Construct", "PartialEq", "Hash", "LocalName", "Repr"];
let ident = &element.ident;
let relevant = element
@@ -1229,20 +983,23 @@ fn create_vtable_func(element: &Elem) -> TokenStream {
.filter(|&ident| !FORBIDDEN.contains(&(&ident.to_string() as &str)));
let checks = relevant.map(|capability| {
quote! {
- if id == ::std::any::TypeId::of::<dyn #capability>() {
- let vtable = unsafe {
- let dangling = ::std::ptr::NonNull::<#ident>::dangling().as_ptr() as *const dyn #capability;
- ::typst::util::fat::vtable(dangling)
- };
- return Some(vtable);
+ if capability == ::std::any::TypeId::of::<dyn #capability>() {
+ // Safety: The vtable function doesn't require initialized
+ // data, so it's fine to use a dangling pointer.
+ return Some(unsafe {
+ ::typst::util::fat::vtable(dangling as *const dyn #capability)
+ });
}
}
});
quote! {
- |id| {
- #(#checks)*
- None
+ unsafe impl #foundations::Capable for #ident {
+ fn vtable(capability: ::std::any::TypeId) -> ::std::option::Option<*const ()> {
+ let dangling = ::std::ptr::NonNull::<#foundations::Packed<#ident>>::dangling().as_ptr();
+ #(#checks)*
+ None
+ }
}
}
}
diff --git a/crates/typst-pdf/src/outline.rs b/crates/typst-pdf/src/outline.rs
index 78698cf8..172f6d3c 100644
--- a/crates/typst-pdf/src/outline.rs
+++ b/crates/typst-pdf/src/outline.rs
@@ -1,7 +1,7 @@
use std::num::NonZeroUsize;
use pdf_writer::{Finish, Ref, TextStr};
-use typst::foundations::{Content, NativeElement, Smart};
+use typst::foundations::{NativeElement, Packed, StyleChain};
use typst::layout::Abs;
use typst::model::HeadingElem;
@@ -17,8 +17,10 @@ pub(crate) fn write_outline(ctx: &mut PdfContext) -> Option<Ref> {
// Therefore, its next descendant must be added at its level, which is
// enforced in the manner shown below.
let mut last_skipped_level = None;
- for heading in ctx.document.introspector.query(&HeadingElem::elem().select()).iter() {
- let leaf = HeadingNode::leaf((**heading).clone());
+ let elements = ctx.document.introspector.query(&HeadingElem::elem().select());
+ for elem in elements.iter() {
+ let heading = elem.to::<HeadingElem>().unwrap();
+ let leaf = HeadingNode::leaf(heading);
if leaf.bookmarked {
let mut children = &mut tree;
@@ -103,21 +105,21 @@ pub(crate) fn write_outline(ctx: &mut PdfContext) -> Option<Ref> {
/// A heading in the outline panel.
#[derive(Debug, Clone)]
-struct HeadingNode {
- element: Content,
+struct HeadingNode<'a> {
+ element: &'a Packed<HeadingElem>,
level: NonZeroUsize,
bookmarked: bool,
- children: Vec<HeadingNode>,
+ children: Vec<HeadingNode<'a>>,
}
-impl HeadingNode {
- fn leaf(element: Content) -> Self {
+impl<'a> HeadingNode<'a> {
+ fn leaf(element: &'a Packed<HeadingElem>) -> Self {
HeadingNode {
- level: element.expect_field_by_name::<NonZeroUsize>("level"),
+ level: element.level(StyleChain::default()),
// 'bookmarked' set to 'auto' falls back to the value of 'outlined'.
bookmarked: element
- .expect_field_by_name::<Smart<bool>>("bookmarked")
- .unwrap_or_else(|| element.expect_field_by_name::<bool>("outlined")),
+ .bookmarked(StyleChain::default())
+ .unwrap_or_else(|| element.outlined(StyleChain::default())),
element,
children: Vec::new(),
}
@@ -157,7 +159,7 @@ fn write_outline_item(
outline.count(-(node.children.len() as i32));
}
- let body = node.element.expect_field_by_name::<Content>("body");
+ let body = node.element.body();
outline.title(TextStr(body.plain_text().trim()));
let loc = node.element.location().unwrap();
diff --git a/crates/typst/src/foundations/cast.rs b/crates/typst/src/foundations/cast.rs
index e3b7dd01..2f7e1dad 100644
--- a/crates/typst/src/foundations/cast.rs
+++ b/crates/typst/src/foundations/cast.rs
@@ -9,7 +9,7 @@ use smallvec::SmallVec;
use unicode_math_class::MathClass;
use crate::diag::{At, SourceResult, StrResult};
-use crate::foundations::{repr, Repr, Type, Value};
+use crate::foundations::{repr, NativeElement, Packed, Repr, Type, Value};
use crate::syntax::{Span, Spanned};
#[rustfmt::skip]
@@ -84,6 +84,20 @@ impl<T: Reflect> Reflect for Spanned<T> {
}
}
+impl<T: NativeElement + Reflect> Reflect for Packed<T> {
+ fn input() -> CastInfo {
+ T::input()
+ }
+
+ fn output() -> CastInfo {
+ T::output()
+ }
+
+ fn castable(value: &Value) -> bool {
+ T::castable(value)
+ }
+}
+
impl<T: Reflect> Reflect for Prehashed<T> {
fn input() -> CastInfo {
T::input()
@@ -174,6 +188,12 @@ impl<T: IntoValue + Clone> IntoValue for Cow<'_, T> {
}
}
+impl<T: NativeElement + IntoValue> IntoValue for Packed<T> {
+ fn into_value(self) -> Value {
+ Value::Content(self.pack())
+ }
+}
+
impl<T: IntoValue> IntoValue for Spanned<T> {
fn into_value(self) -> Value {
self.v.into_value()
@@ -233,6 +253,19 @@ impl FromValue for Value {
}
}
+impl<T: NativeElement + FromValue> FromValue for Packed<T> {
+ fn from_value(mut value: Value) -> StrResult<Self> {
+ if let Value::Content(content) = value {
+ match content.to_packed::<T>() {
+ Ok(packed) => return Ok(packed),
+ Err(content) => value = Value::Content(content),
+ }
+ }
+ let val = T::from_value(value)?;
+ Ok(Packed::new(val))
+ }
+}
+
impl<T: FromValue + Hash + 'static> FromValue for Prehashed<T> {
fn from_value(value: Value) -> StrResult<Self> {
Ok(Self::new(T::from_value(value)?))
diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs
index a0cb45cf..3ba458af 100644
--- a/crates/typst/src/foundations/content.rs
+++ b/crates/typst/src/foundations/content.rs
@@ -1,7 +1,9 @@
use std::any::TypeId;
use std::fmt::{self, Debug, Formatter};
+use std::hash::{Hash, Hasher};
use std::iter::{self, Sum};
-use std::ops::{Add, AddAssign};
+use std::marker::PhantomData;
+use std::ops::{Add, AddAssign, Deref, DerefMut};
use std::sync::Arc;
use comemo::Prehashed;
@@ -12,10 +14,10 @@ use smallvec::smallvec;
use crate::diag::{SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- elem, func, scope, ty, Dict, Element, FromValue, Guard, IntoValue, Label,
- NativeElement, Recipe, Repr, Selector, Str, Style, Styles, Value,
+ elem, func, scope, ty, Dict, Element, Fields, Guard, IntoValue, Label, NativeElement,
+ Recipe, Repr, Selector, Str, Style, Styles, Synthesize, Value,
};
-use crate::introspection::{Location, Meta, MetaElem};
+use crate::introspection::{Locatable, Location, Meta, MetaElem};
use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
use crate::model::{Destination, EmphElem, StrongElem};
use crate::syntax::Span;
@@ -68,12 +70,34 @@ use crate::util::fat;
#[ty(scope, cast)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
-pub struct Content(Arc<dyn NativeElement>);
+pub struct Content {
+ inner: Arc<Inner<dyn Bounds>>,
+ span: Span,
+}
+
+/// The inner representation behind the `Arc`.
+#[derive(Hash)]
+struct Inner<T: ?Sized> {
+ label: Option<Label>,
+ location: Option<Location>,
+ prepared: bool,
+ guards: Vec<Guard>,
+ elem: T,
+}
impl Content {
/// Creates a new content from an element.
- pub fn new<E: NativeElement>(elem: E) -> Self {
- Self(Arc::new(elem))
+ pub fn new<T: NativeElement>(elem: T) -> Self {
+ Self {
+ inner: Arc::new(Inner {
+ label: None,
+ location: None,
+ prepared: false,
+ guards: vec![],
+ elem,
+ }),
+ span: Span::detached(),
+ }
}
/// Creates a new empty sequence content.
@@ -83,65 +107,70 @@ impl Content {
/// Get the element of this content.
pub fn elem(&self) -> Element {
- self.0.dyn_elem()
+ self.inner.elem.dyn_elem()
}
/// Get the span of the content.
pub fn span(&self) -> Span {
- self.0.span()
+ self.span
}
/// Set the span of the content.
pub fn spanned(mut self, span: Span) -> Self {
- self.make_mut().set_span(span);
+ if self.span.is_detached() {
+ self.span = span;
+ }
self
}
/// Get the label of the content.
pub fn label(&self) -> Option<Label> {
- self.0.label()
+ self.inner.label
}
/// Set the label of the content.
pub fn labelled(mut self, label: Label) -> Self {
- self.make_mut().set_label(label);
+ self.make_mut().label = Some(label);
self
}
/// Set the location of the content.
pub fn set_location(&mut self, location: Location) {
- self.make_mut().set_location(location);
+ self.make_mut().location = Some(location);
}
/// Disable a show rule recipe.
pub fn guarded(mut self, guard: Guard) -> Self {
- self.make_mut().push_guard(guard);
- self.0.into()
+ self.make_mut().guards.push(guard);
+ self
}
/// Whether the content needs to be realized specially.
pub fn needs_preparation(&self) -> bool {
- self.0.needs_preparation()
+ (self.can::<dyn Locatable>()
+ || self.can::<dyn Synthesize>()
+ || self.label().is_some())
+ && !self.inner.prepared
}
/// Check whether a show rule recipe is disabled.
pub fn is_guarded(&self, guard: Guard) -> bool {
- self.0.is_guarded(guard)
+ self.inner.guards.contains(&guard)
}
/// Whether no show rule was executed for this content so far.
pub fn is_pristine(&self) -> bool {
- self.0.is_pristine()
+ self.inner.guards.is_empty()
}
/// Whether this content has already been prepared.
pub fn is_prepared(&self) -> bool {
- self.0.is_prepared()
+ self.inner.prepared
}
/// Mark this content as prepared.
pub fn mark_prepared(&mut self) {
- self.make_mut().mark_prepared();
+ self.make_mut().prepared = true;
}
/// Get a field by ID.
@@ -150,7 +179,12 @@ impl Content {
/// if you have set the field IDs yourself or are using the field IDs
/// generated by the `#[elem]` macro.
pub fn get(&self, id: u8) -> Option<Value> {
- self.0.field(id)
+ if id == 255 {
+ if let Some(label) = self.label() {
+ return Some(label.into_value());
+ }
+ }
+ self.inner.elem.field(id)
}
/// Get a field by name.
@@ -158,6 +192,11 @@ impl Content {
/// If you have access to the field IDs of the element, use [`Self::get`]
/// instead.
pub fn get_by_name(&self, name: &str) -> Option<Value> {
+ if name == "label" {
+ if let Some(label) = self.label() {
+ return Some(label.into_value());
+ }
+ }
let id = self.elem().field_id(name)?;
self.get(id)
}
@@ -178,26 +217,7 @@ impl Content {
/// If you have access to the field IDs of the element, use [`Self::field`]
/// instead.
pub fn field_by_name(&self, name: &str) -> StrResult<Value> {
- let id = self.elem().field_id(name).ok_or_else(|| missing_field(name))?;
- self.field(id)
- }
-
- /// Expect a field on the content to exist as a specified type.
- #[track_caller]
- pub fn expect_field<T: FromValue>(&self, id: u8) -> T {
- self.field(id).unwrap().cast().unwrap()
- }
-
- /// Expect a field on the content to exist as a specified type.
- #[track_caller]
- pub fn expect_field_by_name<T: FromValue>(&self, name: &str) -> T {
- self.field_by_name(name).unwrap().cast().unwrap()
- }
-
- /// Set a field to the content.
- pub fn with_field(mut self, id: u8, value: impl IntoValue) -> Self {
- self.make_mut().set_field(id, value.into_value()).unwrap();
- self
+ self.get_by_name(name).ok_or_else(|| missing_field(name))
}
/// Create a new sequence element from multiples elements.
@@ -214,18 +234,34 @@ impl Content {
.into()
}
- /// Access the children if this is a sequence.
- pub fn to_sequence(&self) -> Option<impl Iterator<Item = &Prehashed<Content>>> {
- let Some(sequence) = self.to::<SequenceElem>() else {
- return None;
- };
+ /// Whether the contained element is of type `T`.
+ pub fn is<T: NativeElement>(&self) -> bool {
+ self.inner.elem.dyn_type_id() == TypeId::of::<T>()
+ }
- Some(sequence.children.iter())
+ /// Downcasts the element to a packed value.
+ pub fn to<T: NativeElement>(&self) -> Option<&Packed<T>> {
+ Packed::from_ref(self)
}
- /// Whether the contained element is of type `T`.
- pub fn is<T: NativeElement>(&self) -> bool {
- self.elem() == T::elem()
+ /// Downcasts the element to a mutable packed value.
+ pub fn to_mut<T: NativeElement>(&mut self) -> Option<&mut Packed<T>> {
+ Packed::from_mut(self)
+ }
+
+ /// Downcasts the element into an owned packed value.
+ pub fn to_packed<T: NativeElement>(self) -> Result<Packed<T>, Self> {
+ Packed::from_owned(self)
+ }
+
+ /// Makes sure the content is not shared and returns a mutable reference to
+ /// the inner data.
+ fn make_mut(&mut self) -> &mut Inner<dyn Bounds> {
+ let arc = &mut self.inner;
+ if Arc::strong_count(arc) > 1 || Arc::weak_count(arc) > 0 {
+ *self = arc.elem.dyn_clone(arc, self.span);
+ }
+ Arc::get_mut(&mut self.inner).unwrap()
}
/// Whether the contained element has the given capability.
@@ -236,20 +272,18 @@ impl Content {
self.elem().can::<C>()
}
- /// Whether the contained element has the given capability where the
- /// capability is given by a `TypeId`.
- pub fn can_type_id(&self, type_id: TypeId) -> bool {
- self.elem().can_type_id(type_id)
- }
-
/// Cast to a trait object if the contained element has the given
/// capability.
pub fn with<C>(&self) -> Option<&C>
where
C: ?Sized + 'static,
{
+ // Safety: The vtable comes from the `Capable` implementation which
+ // guarantees to return a matching vtable for `Packed<T>` and `C`.
+ // Since any `Packed<T>` is a repr(transparent) `Content`, we can also
+ // use a `*const Content` pointer.
let vtable = self.elem().vtable()(TypeId::of::<C>())?;
- let data = Arc::as_ptr(&self.0) as *const ();
+ let data = self as *const Content as *const ();
Some(unsafe { &*fat::from_raw_parts(data, vtable) })
}
@@ -259,17 +293,20 @@ impl Content {
where
C: ?Sized + 'static,
{
- // Safety: We ensure the element is not shared.
+ // Safety: The vtable comes from the `Capable` implementation which
+ // guarantees to return a matching vtable for `Packed<T>` and `C`.
+ // Since any `Packed<T>` is a repr(transparent) `Content`, we can also
+ // use a `*const Content` pointer.
+ //
+ // The resulting trait object contains an `&mut Packed<T>`. We do _not_
+ // need to ensure that we hold the only reference to the `Arc` here
+ // because `Packed<T>`'s DerefMut impl will take care of that if
+ // mutable access is required.
let vtable = self.elem().vtable()(TypeId::of::<C>())?;
- let data = self.make_mut() as *mut dyn NativeElement as *mut ();
+ let data = self as *mut Content as *mut ();
Some(unsafe { &mut *fat::from_raw_parts_mut(data, vtable) })
}
- /// Whether the content is a sequence.
- pub fn is_sequence(&self) -> bool {
- self.is::<SequenceElem>()
- }
-
/// Whether the content is an empty sequence.
pub fn is_empty(&self) -> bool {
let Some(sequence) = self.to::<SequenceElem>() else {
@@ -279,6 +316,17 @@ impl Content {
sequence.children.is_empty()
}
+ /// Whether the content is a sequence.
+ pub fn is_sequence(&self) -> bool {
+ self.is::<SequenceElem>()
+ }
+
+ /// Access the children if this is a sequence.
+ pub fn to_sequence(&self) -> Option<impl Iterator<Item = &Prehashed<Content>>> {
+ let sequence = self.to::<SequenceElem>()?;
+ Some(sequence.children.iter())
+ }
+
/// Also auto expands sequence of sequences into flat sequence
pub fn sequence_recursive_for_each(&self, f: &mut impl FnMut(&Self)) {
if let Some(children) = self.to_sequence() {
@@ -383,7 +431,8 @@ impl Content {
{
f(self.clone());
- self.0
+ self.inner
+ .elem
.fields()
.into_iter()
.for_each(|(_, value)| walk_value(value, f));
@@ -404,47 +453,6 @@ impl Content {
}
}
}
-
- /// Downcasts the element to the specified type.
- pub fn to<T: NativeElement>(&self) -> Option<&T> {
- // Early check for performance.
- if !self.is::<T>() {
- return None;
- }
-
- self.0.as_any().downcast_ref()
- }
-
- /// Downcasts mutably the element to the specified type.
- pub fn to_mut<T: NativeElement>(&mut self) -> Option<&mut T> {
- // Early check for performance.
- if !self.is::<T>() {
- return None;
- }
-
- self.make_mut().as_any_mut().downcast_mut()
- }
-
- /// Downcast the element into an owned value.
- pub fn unpack<T: NativeElement>(self) -> Option<Arc<T>> {
- // Early check for performance.
- if !self.is::<T>() {
- return None;
- }
-
- Arc::downcast(self.0.into_any()).ok()
- }
-
- /// Makes sure the content is not shared and returns a mutable reference to
- /// the inner element.
- fn make_mut(&mut self) -> &mut dyn NativeElement {
- let arc = &mut self.0;
- if Arc::strong_count(arc) > 1 || Arc::weak_count(arc) > 0 {
- *arc = arc.dyn_clone();
- }
-
- Arc::get_mut(arc).unwrap()
- }
}
impl Content {
@@ -517,11 +525,15 @@ impl Content {
/// The field to look for.
field: Str,
) -> bool {
+ if field.as_str() == "label" {
+ return self.label().is_some();
+ }
+
let Some(id) = self.elem().field_id(&field) else {
return false;
};
- self.0.has(id)
+ self.inner.elem.has(id)
}
/// Access the specified field on the content. Returns the default value if
@@ -536,11 +548,7 @@ impl Content {
#[named]
default: Option<Value>,
) -> StrResult<Value> {
- let Some(id) = self.elem().field_id(&field) else {
- return default.ok_or_else(|| missing_field_no_default(&field));
- };
-
- self.get(id)
+ self.get_by_name(&field)
.or(default)
.ok_or_else(|| missing_field_no_default(&field))
}
@@ -555,7 +563,11 @@ impl Content {
/// ```
#[func]
pub fn fields(&self) -> Dict {
- self.0.fields()
+ let mut dict = self.inner.elem.fields();
+ if let Some(label) = self.label() {
+ dict.insert("label".into(), label.into_value());
+ }
+ dict
}
/// The location of the content. This is only available on content returned
@@ -565,7 +577,7 @@ impl Content {
/// [counters]($counter), [state]($state) and [queries]($query).
#[func]
pub fn location(&self) -> Option<Location> {
- self.0.location()
+ self.inner.location
}
}
@@ -577,7 +589,7 @@ impl Default for Content {
impl Debug for Content {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- self.0.fmt(f)
+ self.inner.elem.fmt(f)
}
}
@@ -587,22 +599,16 @@ impl<T: NativeElement> From<T> for Content {
}
}
-impl From<Arc<dyn NativeElement>> for Content {
- fn from(value: Arc<dyn NativeElement>) -> Self {
- Self(value)
- }
-}
-
impl PartialEq for Content {
fn eq(&self, other: &Self) -> bool {
// Additional short circuit for different elements.
- self.elem() == other.elem() && self.0.dyn_eq(other)
+ self.elem() == other.elem() && self.inner.elem.dyn_eq(other)
}
}
impl Repr for Content {
fn repr(&self) -> EcoString {
- self.0.repr()
+ self.inner.elem.repr()
}
}
@@ -686,23 +692,199 @@ impl Serialize for Content {
}
}
-/// Defines the `ElemFunc` for sequences.
+/// The trait that combines all the other traits into a trait object.
+trait Bounds: Debug + Repr + Fields + Send + Sync + 'static {
+ fn dyn_type_id(&self) -> TypeId;
+ fn dyn_elem(&self) -> Element;
+ fn dyn_clone(&self, inner: &Inner<dyn Bounds>, span: Span) -> Content;
+ fn dyn_hash(&self, hasher: &mut dyn Hasher);
+ fn dyn_eq(&self, other: &Content) -> bool;
+}
+
+impl<T: NativeElement> Bounds for T {
+ fn dyn_type_id(&self) -> TypeId {
+ TypeId::of::<Self>()
+ }
+
+ fn dyn_elem(&self) -> Element {
+ Self::elem()
+ }
+
+ fn dyn_clone(&self, inner: &Inner<dyn Bounds>, span: Span) -> Content {
+ Content {
+ inner: Arc::new(Inner {
+ label: inner.label,
+ location: inner.location,
+ prepared: inner.prepared,
+ guards: inner.guards.clone(),
+ elem: self.clone(),
+ }),
+ span,
+ }
+ }
+
+ fn dyn_hash(&self, mut state: &mut dyn Hasher) {
+ TypeId::of::<Self>().hash(&mut state);
+ self.hash(&mut state);
+ }
+
+ fn dyn_eq(&self, other: &Content) -> bool {
+ let Some(other) = other.to::<Self>() else {
+ return false;
+ };
+ *self == **other
+ }
+}
+
+impl Hash for dyn Bounds {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.dyn_hash(state);
+ }
+}
+
+/// A packed element of a static type.
+#[derive(Clone, PartialEq, Hash)]
+#[repr(transparent)]
+pub struct Packed<T: NativeElement>(
+ /// Invariant: Must be of type `T`.
+ Content,
+ PhantomData<T>,
+);
+
+impl<T: NativeElement> Packed<T> {
+ /// Pack element while retaining its static type.
+ pub fn new(element: T) -> Self {
+ // Safety: The element is known to be of type `T`.
+ Packed(element.pack(), PhantomData)
+ }
+
+ /// Try to cast type-erased content into a statically known packed element.
+ pub fn from_ref(content: &Content) -> Option<&Self> {
+ if content.is::<T>() {
+ // Safety:
+ // - We have checked the type.
+ // - Packed<T> is repr(transparent).
+ return Some(unsafe { std::mem::transmute(content) });
+ }
+ None
+ }
+
+ /// Try to cast type-erased content into a statically known packed element.
+ pub fn from_mut(content: &mut Content) -> Option<&mut Self> {
+ if content.is::<T>() {
+ // Safety:
+ // - We have checked the type.
+ // - Packed<T> is repr(transparent).
+ return Some(unsafe { std::mem::transmute(content) });
+ }
+ None
+ }
+
+ /// Try to cast type-erased content into a statically known packed element.
+ pub fn from_owned(content: Content) -> Result<Self, Content> {
+ if content.is::<T>() {
+ // Safety:
+ // - We have checked the type.
+ // - Packed<T> is repr(transparent).
+ return Ok(unsafe { std::mem::transmute(content) });
+ }
+ Err(content)
+ }
+
+ /// Pack back into content.
+ pub fn pack(self) -> Content {
+ self.0
+ }
+
+ /// Extract the raw underlying element.
+ pub fn unpack(self) -> T {
+ // This function doesn't yet need owned self, but might in the future.
+ (*self).clone()
+ }
+
+ /// The element's span.
+ pub fn span(&self) -> Span {
+ self.0.span()
+ }
+
+ /// Set the span of the element.
+ pub fn spanned(self, span: Span) -> Self {
+ Self(self.0.spanned(span), PhantomData)
+ }
+
+ /// Accesses the label of the element.
+ pub fn label(&self) -> Option<Label> {
+ self.0.label()
+ }
+
+ /// Accesses the location of the element.
+ pub fn location(&self) -> Option<Location> {
+ self.0.location()
+ }
+
+ /// Sets the location of the element.
+ pub fn set_location(&mut self, location: Location) {
+ self.0.set_location(location);
+ }
+}
+
+impl<T: NativeElement> AsRef<T> for Packed<T> {
+ fn as_ref(&self) -> &T {
+ self
+ }
+}
+
+impl<T: NativeElement> AsMut<T> for Packed<T> {
+ fn as_mut(&mut self) -> &mut T {
+ self
+ }
+}
+
+impl<T: NativeElement> Deref for Packed<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // Safety:
+ // - Packed<T> guarantees that the content trait object wraps
+ // an element of type `T`.
+ // - This downcast works the same way as dyn Any's does. We can't reuse
+ // that one because we don't want to pay the cost for every deref.
+ let elem = &self.0.inner.elem;
+ unsafe { &*(elem as *const dyn Bounds as *const T) }
+ }
+}
+
+impl<T: NativeElement> DerefMut for Packed<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // Safety:
+ // - Packed<T> guarantees that the content trait object wraps
+ // an element of type `T`.
+ // - We have guaranteed unique access thanks to `make_mut`.
+ // - This downcast works the same way as dyn Any's does. We can't reuse
+ // that one because we don't want to pay the cost for every deref.
+ let elem = &mut self.0.make_mut().elem;
+ unsafe { &mut *(elem as *mut dyn Bounds as *mut T) }
+ }
+}
+
+impl<T: NativeElement + Debug> Debug for Packed<T> {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+/// Defines the element for sequences.
#[elem(Repr, PartialEq)]
struct SequenceElem {
#[required]
children: Vec<Prehashed<Content>>,
}
+// Derive is currently incompatible with `elem` macro.
+#[allow(clippy::derivable_impls)]
impl Default for SequenceElem {
fn default() -> Self {
- Self {
- span: Span::detached(),
- location: Default::default(),
- label: Default::default(),
- prepared: Default::default(),
- guards: Default::default(),
- children: Default::default(),
- }
+ Self { children: Default::default() }
}
}
@@ -723,7 +905,11 @@ impl Repr for SequenceElem {
eco_format!(
"[{}]",
crate::foundations::repr::pretty_array_like(
- &self.children.iter().map(|c| c.0.repr()).collect::<Vec<_>>(),
+ &self
+ .children
+ .iter()
+ .map(|c| c.inner.elem.repr())
+ .collect::<Vec<_>>(),
false
)
)
@@ -748,7 +934,7 @@ impl PartialEq for StyledElem {
impl Repr for StyledElem {
fn repr(&self) -> EcoString {
- eco_format!("styled(child: {}, ..)", self.child.0.repr())
+ eco_format!("styled(child: {}, ..)", self.child.repr())
}
}
diff --git a/crates/typst/src/foundations/element.rs b/crates/typst/src/foundations/element.rs
index 301a4003..665aa8ef 100644
--- a/crates/typst/src/foundations/element.rs
+++ b/crates/typst/src/foundations/element.rs
@@ -1,22 +1,19 @@
-use std::any::{Any, TypeId};
+use std::any::TypeId;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Debug};
-use std::hash::{Hash, Hasher};
-use std::sync::Arc;
+use std::hash::Hash;
use ecow::EcoString;
use once_cell::sync::Lazy;
use smallvec::SmallVec;
-use crate::diag::{SourceResult, StrResult};
+use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
- cast, Args, Content, Dict, Func, Label, ParamInfo, Repr, Scope, Selector, StyleChain,
+ cast, Args, Content, Dict, Func, ParamInfo, Repr, Scope, Selector, StyleChain,
Styles, Value,
};
-use crate::introspection::Location;
-use crate::syntax::Span;
use crate::text::{Lang, Region};
use crate::util::Static;
@@ -35,11 +32,17 @@ impl Element {
/// Extract the field ID for the given field name.
pub fn field_id(&self, name: &str) -> Option<u8> {
+ if name == "label" {
+ return Some(255);
+ }
(self.0.field_id)(name)
}
/// Extract the field name for the given field ID.
pub fn field_name(&self, id: u8) -> Option<&'static str> {
+ if id == 255 {
+ return Some("label");
+ }
(self.0.field_name)(id)
}
@@ -163,7 +166,20 @@ pub trait ElementFields {
}
/// A Typst element that is defined by a native Rust type.
-pub trait NativeElement: Debug + Repr + Construct + Set + Send + Sync + 'static {
+pub trait NativeElement:
+ Debug
+ + Clone
+ + PartialEq
+ + Hash
+ + Construct
+ + Set
+ + Capable
+ + Fields
+ + Repr
+ + Send
+ + Sync
+ + 'static
+{
/// Get the element for the native Rust element.
fn elem() -> Element
where
@@ -184,103 +200,31 @@ pub trait NativeElement: Debug + Repr + Construct + Set + Send + Sync + 'static
fn data() -> &'static NativeElementData
where
Self: Sized;
+}
- /// Get the element data for the native Rust element.
- fn dyn_elem(&self) -> Element;
-
- /// Dynamically hash the element.
- fn dyn_hash(&self, hasher: &mut dyn Hasher);
-
- /// Dynamically compare the element.
- fn dyn_eq(&self, other: &Content) -> bool;
-
- /// Dynamically clone the element.
- fn dyn_clone(&self) -> Arc<dyn NativeElement>;
-
- /// Get the element as a dynamic value.
- fn as_any(&self) -> &dyn Any;
-
- /// Get the element as a mutable dynamic value.
- fn as_any_mut(&mut self) -> &mut dyn Any;
-
- /// Get the element as a dynamic value.
- fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
-
- /// Get the element's span.
- ///
- /// May be detached if it has not been set.
- fn span(&self) -> Span;
-
- /// Sets the span of this element.
- fn set_span(&mut self, span: Span);
-
- /// Set the element's span.
- fn spanned(mut self, span: Span) -> Self
- where
- Self: Sized,
- {
- self.set_span(span);
- self
- }
-
- /// Get the element's label.
- fn label(&self) -> Option<Label>;
-
- /// Sets the label of this element.
- fn set_label(&mut self, label: Label);
-
- /// Set the element's label.
- fn labelled(mut self, label: Label) -> Self
- where
- Self: Sized,
- {
- self.set_label(label);
- self
- }
-
- /// Get the element's location.
- fn location(&self) -> Option<Location>;
-
- /// Sets the location of this element.
- fn set_location(&mut self, location: Location);
-
- /// Checks whether the element is guarded by the given guard.
- fn is_guarded(&self, guard: Guard) -> bool;
-
- /// Pushes a guard onto the element.
- fn push_guard(&mut self, guard: Guard);
-
- /// Whether the element is pristine.
- fn is_pristine(&self) -> bool;
-
- /// Mark the element as having been prepared.
- fn mark_prepared(&mut self);
-
- /// Whether this element needs preparations.
- fn needs_preparation(&self) -> bool;
-
- /// Whether this element has been prepared.
- fn is_prepared(&self) -> bool;
-
- /// Get the field with the given field ID.
- fn field(&self, id: u8) -> Option<Value>;
+/// Used to cast an element to a trait object for a trait it implements.
+///
+/// # Safety
+/// If the `vtable` function returns `Some(p)`, then `p` must be a valid pointer
+/// to a vtable of `Packed<Self>` w.r.t to the trait `C` where `capability` is
+/// `TypeId::of::<dyn C>()`.
+pub unsafe trait Capable {
+ /// Get the pointer to the vtable for the given capability / trait.
+ fn vtable(capability: TypeId) -> Option<*const ()>;
+}
+/// Defines how fields of an element are accessed.
+pub trait Fields {
/// Whether the element has the given field set.
fn has(&self, id: u8) -> bool;
- /// Set the field with the given ID.
- fn set_field(&mut self, id: u8, value: Value) -> StrResult<()>;
+ /// Get the field with the given field ID.
+ fn field(&self, id: u8) -> Option<Value>;
/// Get the fields of the element.
fn fields(&self) -> Dict;
}
-impl Hash for dyn NativeElement {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.dyn_hash(state);
- }
-}
-
/// An element's constructor function.
pub trait Construct {
/// Construct an element from the arguments.
@@ -309,7 +253,7 @@ pub struct NativeElementData {
pub keywords: &'static [&'static str],
pub construct: fn(&mut Engine, &mut Args) -> SourceResult<Content>,
pub set: fn(&mut Engine, &mut Args) -> SourceResult<Styles>,
- pub vtable: fn(of: TypeId) -> Option<*const ()>,
+ pub vtable: fn(capability: TypeId) -> Option<*const ()>,
pub field_id: fn(name: &str) -> Option<u8>,
pub field_name: fn(u8) -> Option<&'static str>,
pub local_name: Option<fn(Lang, Option<Region>) -> &'static str>,
diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs
index 771a3d2c..b2287c2d 100644
--- a/crates/typst/src/foundations/styles.rs
+++ b/crates/typst/src/foundations/styles.rs
@@ -12,7 +12,8 @@ use smallvec::SmallVec;
use crate::diag::{SourceResult, Trace, Tracepoint};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, func, ty, Content, Element, Func, NativeElement, Repr, Selector, Show,
+ cast, elem, func, ty, Content, Element, Func, NativeElement, Packed, Repr, Selector,
+ Show,
};
use crate::syntax::Span;
use crate::text::{FontFamily, FontList, TextElem};
@@ -45,7 +46,7 @@ pub fn style(
/// content that depends on the style context it appears in.
func: Func,
) -> Content {
- StyleElem::new(func).spanned(span).pack()
+ StyleElem::new(func).pack().spanned(span)
}
/// Executes a style access.
@@ -56,7 +57,7 @@ struct StyleElem {
func: Func,
}
-impl Show for StyleElem {
+impl Show for Packed<StyleElem> {
#[typst_macros::time(name = "style", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.func().call(engine, [styles.to_map()])?.display())
diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs
index 0f319fab..e4bb282f 100644
--- a/crates/typst/src/introspection/counter.rs
+++ b/crates/typst/src/introspection/counter.rs
@@ -10,8 +10,8 @@ use crate::engine::{Engine, Route};
use crate::eval::Tracer;
use crate::foundations::{
cast, elem, func, scope, select_where, ty, Array, Content, Element, Func, IntoValue,
- Label, LocatableSelector, NativeElement, Repr, Selector, Show, Str, StyleChain,
- Value,
+ Label, LocatableSelector, NativeElement, Packed, Repr, Selector, Show, Str,
+ StyleChain, Value,
};
use crate::introspection::{Introspector, Locatable, Location, Locator, Meta};
use crate::layout::{Frame, FrameItem, PageElem};
@@ -372,7 +372,7 @@ impl Counter {
#[default(false)]
both: bool,
) -> Content {
- DisplayElem::new(self, numbering, both).spanned(span).pack()
+ DisplayElem::new(self, numbering, both).pack().spanned(span)
}
/// Increases the value of the counter by one.
@@ -411,7 +411,7 @@ impl Counter {
/// return the new value (integer or array).
update: CounterUpdate,
) -> Content {
- UpdateElem::new(self.0, update).spanned(span).pack()
+ UpdateElem::new(self.0, update).pack().spanned(span)
}
/// Gets the value of the counter at the given location. Always returns an
@@ -632,7 +632,7 @@ struct DisplayElem {
both: bool,
}
-impl Show for DisplayElem {
+impl Show for Packed<DisplayElem> {
#[typst_macros::time(name = "counter.display", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
@@ -681,13 +681,13 @@ struct UpdateElem {
update: CounterUpdate,
}
-impl Show for UpdateElem {
+impl Show for Packed<UpdateElem> {
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(Content::empty())
}
}
-impl Count for UpdateElem {
+impl Count for Packed<UpdateElem> {
fn update(&self) -> Option<CounterUpdate> {
Some(self.update.clone())
}
@@ -726,7 +726,7 @@ impl ManualPageCounter {
let Some(elem) = elem.to::<UpdateElem>() else { continue };
if *elem.key() == CounterKey::Page {
let mut state = CounterState(smallvec![self.logical]);
- state.update(engine, elem.update().clone())?;
+ state.update(engine, elem.update.clone())?;
self.logical = state.first();
}
}
diff --git a/crates/typst/src/introspection/locate.rs b/crates/typst/src/introspection/locate.rs
index 4cec04c9..132714f1 100644
--- a/crates/typst/src/introspection/locate.rs
+++ b/crates/typst/src/introspection/locate.rs
@@ -1,6 +1,8 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, func, Content, Func, NativeElement, Show, StyleChain};
+use crate::foundations::{
+ elem, func, Content, Func, NativeElement, Packed, Show, StyleChain,
+};
use crate::introspection::Locatable;
use crate::syntax::Span;
@@ -28,7 +30,7 @@ pub fn locate(
/// content that depends on its own location in the document.
func: Func,
) -> Content {
- LocateElem::new(func).spanned(span).pack()
+ LocateElem::new(func).pack().spanned(span)
}
/// Executes a `locate` call.
@@ -39,7 +41,7 @@ struct LocateElem {
func: Func,
}
-impl Show for LocateElem {
+impl Show for Packed<LocateElem> {
#[typst_macros::time(name = "locate", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
diff --git a/crates/typst/src/introspection/metadata.rs b/crates/typst/src/introspection/metadata.rs
index 15d144eb..d66441a2 100644
--- a/crates/typst/src/introspection/metadata.rs
+++ b/crates/typst/src/introspection/metadata.rs
@@ -1,6 +1,8 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Behave, Behaviour, Content, Show, StyleChain, Value};
+use crate::foundations::{
+ elem, Behave, Behaviour, Content, Packed, Show, StyleChain, Value,
+};
use crate::introspection::Locatable;
/// Exposes a value to the query system without producing visible content.
@@ -30,13 +32,13 @@ pub struct MetadataElem {
pub value: Value,
}
-impl Show for MetadataElem {
+impl Show for Packed<MetadataElem> {
fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> {
Ok(Content::empty())
}
}
-impl Behave for MetadataElem {
+impl Behave for Packed<MetadataElem> {
fn behaviour(&self) -> Behaviour {
Behaviour::Invisible
}
diff --git a/crates/typst/src/introspection/mod.rs b/crates/typst/src/introspection/mod.rs
index 86917891..e9ea0291 100644
--- a/crates/typst/src/introspection/mod.rs
+++ b/crates/typst/src/introspection/mod.rs
@@ -25,6 +25,7 @@ use std::fmt::{self, Debug, Formatter};
use ecow::{eco_format, EcoString};
use smallvec::SmallVec;
+use crate::foundations::Packed;
use crate::foundations::{
category, elem, ty, Behave, Behaviour, Category, Content, Repr, Scope, Unlabellable,
};
@@ -61,9 +62,9 @@ pub struct MetaElem {
pub data: SmallVec<[Meta; 1]>,
}
-impl Unlabellable for MetaElem {}
+impl Unlabellable for Packed<MetaElem> {}
-impl Behave for MetaElem {
+impl Behave for Packed<MetaElem> {
fn behaviour(&self) -> Behaviour {
Behaviour::Invisible
}
diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs
index 3d050fb0..1f593549 100644
--- a/crates/typst/src/introspection/state.rs
+++ b/crates/typst/src/introspection/state.rs
@@ -5,8 +5,8 @@ use crate::diag::SourceResult;
use crate::engine::{Engine, Route};
use crate::eval::Tracer;
use crate::foundations::{
- cast, elem, func, scope, select_where, ty, Content, Func, NativeElement, Repr,
- Selector, Show, Str, StyleChain, Value,
+ cast, elem, func, scope, select_where, ty, Content, Func, NativeElement, Packed,
+ Repr, Selector, Show, Str, StyleChain, Value,
};
use crate::introspection::{Introspector, Locatable, Location, Locator};
use crate::syntax::Span;
@@ -280,7 +280,7 @@ impl State {
#[default]
func: Option<Func>,
) -> Content {
- DisplayElem::new(self, func).spanned(span).pack()
+ DisplayElem::new(self, func).pack().spanned(span)
}
/// Update the value of the state.
@@ -301,7 +301,7 @@ impl State {
/// to return the new state.
update: StateUpdate,
) -> Content {
- UpdateElem::new(self.key, update).spanned(span).pack()
+ UpdateElem::new(self.key, update).pack().spanned(span)
}
/// Get the value of the state at the given location.
@@ -385,7 +385,7 @@ struct DisplayElem {
func: Option<Func>,
}
-impl Show for DisplayElem {
+impl Show for Packed<DisplayElem> {
#[typst_macros::time(name = "state.display", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
@@ -411,7 +411,7 @@ struct UpdateElem {
update: StateUpdate,
}
-impl Show for UpdateElem {
+impl Show for Packed<UpdateElem> {
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(Content::empty())
}
diff --git a/crates/typst/src/layout/align.rs b/crates/typst/src/layout/align.rs
index a1f2a553..3dbba643 100644
--- a/crates/typst/src/layout/align.rs
+++ b/crates/typst/src/layout/align.rs
@@ -5,7 +5,7 @@ use ecow::{eco_format, EcoString};
use crate::diag::{bail, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, func, scope, ty, Content, Fold, Repr, Resolve, Show, StyleChain,
+ cast, elem, func, scope, ty, Content, Fold, Packed, Repr, Resolve, Show, StyleChain,
};
use crate::layout::{Abs, Axes, Axis, Dir, Side};
use crate::text::TextElem;
@@ -45,13 +45,13 @@ pub struct AlignElem {
pub body: Content,
}
-impl Show for AlignElem {
+impl Show for Packed<AlignElem> {
#[typst_macros::time(name = "align", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self
.body()
.clone()
- .styled(Self::set_alignment(self.alignment(styles))))
+ .styled(AlignElem::set_alignment(self.alignment(styles))))
}
}
diff --git a/crates/typst/src/layout/columns.rs b/crates/typst/src/layout/columns.rs
index 4ec8e56e..88b459f2 100644
--- a/crates/typst/src/layout/columns.rs
+++ b/crates/typst/src/layout/columns.rs
@@ -2,7 +2,7 @@ use std::num::NonZeroUsize;
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Behave, Behaviour, Content, StyleChain};
+use crate::foundations::{elem, Behave, Behaviour, Content, Packed, StyleChain};
use crate::layout::{
Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size,
};
@@ -57,7 +57,7 @@ pub struct ColumnsElem {
pub body: Content,
}
-impl Layout for ColumnsElem {
+impl Layout for Packed<ColumnsElem> {
#[typst_macros::time(name = "columns", span = self.span())]
fn layout(
&self,
@@ -166,7 +166,7 @@ pub struct ColbreakElem {
pub weak: bool,
}
-impl Behave for ColbreakElem {
+impl Behave for Packed<ColbreakElem> {
fn behaviour(&self) -> Behaviour {
if self.weak(StyleChain::default()) {
Behaviour::Weak(1)
diff --git a/crates/typst/src/layout/container.rs b/crates/typst/src/layout/container.rs
index f2d182ae..3905a37a 100644
--- a/crates/typst/src/layout/container.rs
+++ b/crates/typst/src/layout/container.rs
@@ -1,7 +1,7 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, AutoValue, Content, NativeElement, Resolve, Smart, StyleChain, Value,
+ cast, elem, AutoValue, Content, Packed, Resolve, Smart, StyleChain, Value,
};
use crate::layout::{
Abs, Axes, Corners, Em, Fr, Fragment, FrameKind, Layout, Length, Ratio, Regions, Rel,
@@ -109,7 +109,7 @@ pub struct BoxElem {
pub body: Option<Content>,
}
-impl Layout for BoxElem {
+impl Layout for Packed<BoxElem> {
#[typst_macros::time(name = "box", span = self.span())]
fn layout(
&self,
@@ -341,7 +341,7 @@ pub struct BlockElem {
pub sticky: bool,
}
-impl Layout for BlockElem {
+impl Layout for Packed<BlockElem> {
#[typst_macros::time(name = "block", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/layout/flow.rs b/crates/typst/src/layout/flow.rs
index fd9350ac..65774c69 100644
--- a/crates/typst/src/layout/flow.rs
+++ b/crates/typst/src/layout/flow.rs
@@ -2,7 +2,9 @@ use comemo::Prehashed;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
-use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain};
+use crate::foundations::{
+ elem, Content, NativeElement, Packed, Resolve, Smart, StyleChain,
+};
use crate::introspection::{Meta, MetaElem};
use crate::layout::{
Abs, AlignElem, Axes, BlockElem, ColbreakElem, ColumnsElem, FixedAlign, Fr, Fragment,
@@ -27,7 +29,7 @@ pub struct FlowElem {
pub children: Vec<Prehashed<Content>>,
}
-impl Layout for FlowElem {
+impl Layout for Packed<FlowElem> {
#[typst_macros::time(name = "flow", span = self.span())]
fn layout(
&self,
@@ -207,7 +209,7 @@ impl<'a> FlowLayouter<'a> {
fn layout_spacing(
&mut self,
engine: &mut Engine,
- v: &VElem,
+ v: &Packed<VElem>,
styles: StyleChain,
) -> SourceResult<()> {
self.layout_item(
@@ -226,7 +228,7 @@ impl<'a> FlowLayouter<'a> {
fn layout_par(
&mut self,
engine: &mut Engine,
- par: &ParElem,
+ par: &Packed<ParElem>,
styles: StyleChain,
) -> SourceResult<()> {
let align = AlignElem::alignment_in(styles).resolve(styles);
@@ -299,7 +301,7 @@ impl<'a> FlowLayouter<'a> {
fn layout_placed(
&mut self,
engine: &mut Engine,
- placed: &PlaceElem,
+ placed: &Packed<PlaceElem>,
styles: StyleChain,
) -> SourceResult<()> {
let float = placed.float(styles);
@@ -631,7 +633,7 @@ impl FlowLayouter<'_> {
fn try_handle_footnotes(
&mut self,
engine: &mut Engine,
- mut notes: Vec<FootnoteElem>,
+ mut notes: Vec<Packed<FootnoteElem>>,
) -> SourceResult<()> {
if self.root && !self.handle_footnotes(engine, &mut notes, false, false)? {
self.finish_region(engine, false)?;
@@ -644,7 +646,7 @@ impl FlowLayouter<'_> {
fn handle_footnotes(
&mut self,
engine: &mut Engine,
- notes: &mut Vec<FootnoteElem>,
+ notes: &mut Vec<Packed<FootnoteElem>>,
movable: bool,
force: bool,
) -> SourceResult<bool> {
@@ -735,7 +737,7 @@ impl FlowLayouter<'_> {
}
/// Finds all footnotes in the frame.
-fn find_footnotes(notes: &mut Vec<FootnoteElem>, frame: &Frame) {
+fn find_footnotes(notes: &mut Vec<Packed<FootnoteElem>>, frame: &Frame) {
for (_, item) in frame.items() {
match item {
FrameItem::Group(group) => find_footnotes(notes, &group.frame),
diff --git a/crates/typst/src/layout/grid/mod.rs b/crates/typst/src/layout/grid/mod.rs
index 3b7c8553..fb82dbcf 100644
--- a/crates/typst/src/layout/grid/mod.rs
+++ b/crates/typst/src/layout/grid/mod.rs
@@ -9,8 +9,8 @@ use smallvec::{smallvec, SmallVec};
use crate::diag::{SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, Array, Content, Fold, NativeElement, Show, Smart, StyleChain,
- Value,
+ cast, elem, scope, Array, Content, Fold, NativeElement, Packed, Show, Smart,
+ StyleChain, Value,
};
use crate::layout::{
Abs, AlignElem, Alignment, Axes, Fragment, Layout, Length, Regions, Rel, Sides,
@@ -222,7 +222,7 @@ impl GridElem {
type GridCell;
}
-impl Layout for GridElem {
+impl Layout for Packed<GridElem> {
#[typst_macros::time(name = "grid", span = self.span())]
fn layout(
&self,
@@ -346,7 +346,7 @@ impl ResolvableCell for GridCell {
}
}
-impl Show for GridCell {
+impl Show for Packed<GridCell> {
fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
show_grid_cell(self.body().clone(), self.inset(styles), self.align(styles))
}
@@ -354,10 +354,10 @@ impl Show for GridCell {
impl From<Content> for GridCell {
fn from(value: Content) -> Self {
- value
- .to::<Self>()
- .cloned()
- .unwrap_or_else(|| Self::new(value.clone()))
+ match value.to_packed::<Self>() {
+ Ok(packed) => packed.unpack(),
+ Err(v) => Self::new(v),
+ }
}
}
diff --git a/crates/typst/src/layout/hide.rs b/crates/typst/src/layout/hide.rs
index 1b8b0efd..7a8618c1 100644
--- a/crates/typst/src/layout/hide.rs
+++ b/crates/typst/src/layout/hide.rs
@@ -2,7 +2,7 @@ use smallvec::smallvec;
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, Show, StyleChain};
+use crate::foundations::{elem, Content, Packed, Show, StyleChain};
use crate::introspection::{Meta, MetaElem};
/// Hides content without affecting layout.
@@ -24,7 +24,7 @@ pub struct HideElem {
pub body: Content,
}
-impl Show for HideElem {
+impl Show for Packed<HideElem> {
#[typst_macros::time(name = "hide", span = self.span())]
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone().styled(MetaElem::set_data(smallvec![Meta::Hide])))
diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs
index 20e6dcbc..7c243da3 100644
--- a/crates/typst/src/layout/inline/mod.rs
+++ b/crates/typst/src/layout/inline/mod.rs
@@ -13,7 +13,7 @@ use self::shaping::{
use crate::diag::{bail, SourceResult};
use crate::engine::{Engine, Route};
use crate::eval::Tracer;
-use crate::foundations::{Content, Resolve, Smart, StyleChain};
+use crate::foundations::{Content, Packed, Resolve, Smart, StyleChain};
use crate::introspection::{Introspector, Locator, MetaElem};
use crate::layout::{
Abs, AlignElem, Axes, BoxElem, Dir, Em, FixedAlign, Fr, Fragment, Frame, HElem,
@@ -189,9 +189,9 @@ enum Segment<'a> {
/// Horizontal spacing between other segments.
Spacing(Spacing),
/// A mathematical equation.
- Equation(&'a EquationElem, Vec<MathParItem>),
+ Equation(&'a Packed<EquationElem>, Vec<MathParItem>),
/// A box with arbitrary content.
- Box(&'a BoxElem, bool),
+ Box(&'a Packed<BoxElem>, bool),
/// Metadata.
Meta,
}
@@ -221,7 +221,7 @@ enum Item<'a> {
/// Absolute spacing between other items.
Absolute(Abs),
/// Fractional spacing between other items.
- Fractional(Fr, Option<(&'a BoxElem, StyleChain<'a>)>),
+ Fractional(Fr, Option<(&'a Packed<BoxElem>, StyleChain<'a>)>),
/// Layouted inline-level content.
Frame(Frame),
/// Metadata.
diff --git a/crates/typst/src/layout/layout.rs b/crates/typst/src/layout/layout.rs
index 126fe067..6af3ac79 100644
--- a/crates/typst/src/layout/layout.rs
+++ b/crates/typst/src/layout/layout.rs
@@ -1,6 +1,8 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{dict, elem, func, Content, Func, NativeElement, StyleChain};
+use crate::foundations::{
+ dict, elem, func, Content, Func, NativeElement, Packed, StyleChain,
+};
use crate::layout::{Fragment, Layout, Regions, Size};
use crate::syntax::Span;
@@ -57,7 +59,7 @@ pub fn layout(
/// content that depends on the size of the container it is inside of.
func: Func,
) -> Content {
- LayoutElem::new(func).spanned(span).pack()
+ LayoutElem::new(func).pack().spanned(span)
}
/// Executes a `layout` call.
@@ -68,7 +70,7 @@ struct LayoutElem {
func: Func,
}
-impl Layout for LayoutElem {
+impl Layout for Packed<LayoutElem> {
#[typst_macros::time(name = "layout", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/layout/pad.rs b/crates/typst/src/layout/pad.rs
index 0a880b3b..0e44ab67 100644
--- a/crates/typst/src/layout/pad.rs
+++ b/crates/typst/src/layout/pad.rs
@@ -1,6 +1,6 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, Resolve, StyleChain};
+use crate::foundations::{elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size};
/// Adds spacing around content.
@@ -58,7 +58,7 @@ pub struct PadElem {
pub body: Content,
}
-impl Layout for PadElem {
+impl Layout for Packed<PadElem> {
#[typst_macros::time(name = "pad", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/layout/page.rs b/crates/typst/src/layout/page.rs
index a99920a8..c36be514 100644
--- a/crates/typst/src/layout/page.rs
+++ b/crates/typst/src/layout/page.rs
@@ -6,8 +6,8 @@ use std::str::FromStr;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, AutoValue, Cast, Content, Dict, Fold, Func, NativeElement, Resolve,
- Smart, StyleChain, Value,
+ cast, elem, AutoValue, Cast, Content, Dict, Fold, Func, NativeElement, Packed,
+ Resolve, Smart, StyleChain, Value,
};
use crate::introspection::{Counter, CounterKey, ManualPageCounter, Meta};
use crate::layout::{
@@ -333,7 +333,7 @@ pub struct PageElem {
pub clear_to: Option<Parity>,
}
-impl PageElem {
+impl Packed<PageElem> {
/// A document can consist of multiple `PageElem`s, one per run of pages
/// with equal properties (not one per actual output page!). The `number` is
/// the physical page number of the first page of this run. It is mutated
@@ -385,9 +385,9 @@ impl PageElem {
let columns = self.columns(styles);
if columns.get() > 1 {
child = ColumnsElem::new(child)
- .spanned(self.span())
.with_count(columns)
- .pack();
+ .pack()
+ .spanned(self.span());
}
let area = size - margin.sum_by_axis();
diff --git a/crates/typst/src/layout/place.rs b/crates/typst/src/layout/place.rs
index 87dd2216..bc88550c 100644
--- a/crates/typst/src/layout/place.rs
+++ b/crates/typst/src/layout/place.rs
@@ -1,8 +1,6 @@
use crate::diag::{bail, At, Hint, SourceResult};
use crate::engine::Engine;
-use crate::foundations::{
- elem, Behave, Behaviour, Content, NativeElement, Smart, StyleChain,
-};
+use crate::foundations::{elem, Behave, Behaviour, Content, Packed, Smart, StyleChain};
use crate::layout::{
Alignment, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlignment,
};
@@ -88,7 +86,7 @@ pub struct PlaceElem {
pub body: Content,
}
-impl Layout for PlaceElem {
+impl Layout for Packed<PlaceElem> {
#[typst_macros::time(name = "place", span = self.span())]
fn layout(
&self,
@@ -125,7 +123,7 @@ impl Layout for PlaceElem {
}
}
-impl Behave for PlaceElem {
+impl Behave for Packed<PlaceElem> {
fn behaviour(&self) -> Behaviour {
Behaviour::Ignorant
}
diff --git a/crates/typst/src/layout/repeat.rs b/crates/typst/src/layout/repeat.rs
index f3018573..1fe21618 100644
--- a/crates/typst/src/layout/repeat.rs
+++ b/crates/typst/src/layout/repeat.rs
@@ -1,6 +1,6 @@
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
-use crate::foundations::{elem, Content, NativeElement, Resolve, StyleChain};
+use crate::foundations::{elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{
Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size,
};
@@ -34,7 +34,7 @@ pub struct RepeatElem {
pub body: Content,
}
-impl Layout for RepeatElem {
+impl Layout for Packed<RepeatElem> {
#[typst_macros::time(name = "repeat", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/layout/spacing.rs b/crates/typst/src/layout/spacing.rs
index 1620c139..4e65fff2 100644
--- a/crates/typst/src/layout/spacing.rs
+++ b/crates/typst/src/layout/spacing.rs
@@ -1,6 +1,8 @@
use std::borrow::Cow;
-use crate::foundations::{cast, elem, Behave, Behaviour, Content, Resolve, StyleChain};
+use crate::foundations::{
+ cast, elem, Behave, Behaviour, Content, Packed, Resolve, StyleChain,
+};
use crate::layout::{Abs, Em, Fr, Length, Ratio, Rel};
use crate::util::Numeric;
@@ -62,7 +64,7 @@ impl HElem {
}
}
-impl Behave for HElem {
+impl Behave for Packed<HElem> {
fn behaviour(&self) -> Behaviour {
if self.amount().is_fractional() {
Behaviour::Destructive
@@ -78,7 +80,7 @@ impl Behave for HElem {
prev: &(Cow<Content>, Behaviour, StyleChain),
styles: StyleChain,
) -> bool {
- let Some(other) = prev.0.to::<Self>() else { return false };
+ let Some(other) = prev.0.to::<HElem>() else { return false };
match (self.amount(), other.amount()) {
(Spacing::Fr(this), Spacing::Fr(other)) => this > other,
(Spacing::Rel(this), Spacing::Rel(other)) => {
@@ -164,7 +166,7 @@ impl VElem {
}
}
-impl Behave for VElem {
+impl Behave for Packed<VElem> {
fn behaviour(&self) -> Behaviour {
if self.amount().is_fractional() {
Behaviour::Destructive
@@ -180,7 +182,7 @@ impl Behave for VElem {
prev: &(Cow<Content>, Behaviour, StyleChain),
styles: StyleChain,
) -> bool {
- let Some(other) = prev.0.to::<Self>() else { return false };
+ let Some(other) = prev.0.to::<VElem>() else { return false };
match (self.amount(), other.amount()) {
(Spacing::Fr(this), Spacing::Fr(other)) => this > other,
(Spacing::Rel(this), Spacing::Rel(other)) => {
@@ -193,7 +195,7 @@ impl Behave for VElem {
cast! {
VElem,
- v: Content => v.to::<Self>().cloned().ok_or("expected `v` element")?,
+ v: Content => v.to_packed::<Self>().map_err(|_| "expected `v` element")?.unpack(),
}
/// Kinds of spacing.
diff --git a/crates/typst/src/layout/stack.rs b/crates/typst/src/layout/stack.rs
index be97e667..477105f7 100644
--- a/crates/typst/src/layout/stack.rs
+++ b/crates/typst/src/layout/stack.rs
@@ -2,7 +2,7 @@ use std::fmt::{self, Debug, Formatter};
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{cast, elem, Content, Resolve, StyleChain};
+use crate::foundations::{cast, elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{
Abs, AlignElem, Axes, Axis, Dir, FixedAlign, Fr, Fragment, Frame, Layout, Point,
Regions, Size, Spacing,
@@ -51,7 +51,7 @@ pub struct StackElem {
pub children: Vec<StackChild>,
}
-impl Layout for StackElem {
+impl Layout for Packed<StackElem> {
#[typst_macros::time(name = "stack", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/layout/transform.rs b/crates/typst/src/layout/transform.rs
index e0887193..527bad7c 100644
--- a/crates/typst/src/layout/transform.rs
+++ b/crates/typst/src/layout/transform.rs
@@ -1,6 +1,6 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, Resolve, StyleChain};
+use crate::foundations::{elem, Content, Packed, Resolve, StyleChain};
use crate::layout::{
Abs, Alignment, Angle, Axes, FixedAlign, Fragment, Frame, HAlignment, Layout, Length,
Point, Ratio, Regions, Rel, Size, VAlignment,
@@ -37,7 +37,7 @@ pub struct MoveElem {
pub body: Content,
}
-impl Layout for MoveElem {
+impl Layout for Packed<MoveElem> {
#[typst_macros::time(name = "move", span = self.span())]
fn layout(
&self,
@@ -115,7 +115,7 @@ pub struct RotateElem {
pub body: Content,
}
-impl Layout for RotateElem {
+impl Layout for Packed<RotateElem> {
#[typst_macros::time(name = "rotate", span = self.span())]
fn layout(
&self,
@@ -203,7 +203,7 @@ pub struct ScaleElem {
pub body: Content,
}
-impl Layout for ScaleElem {
+impl Layout for Packed<ScaleElem> {
#[typst_macros::time(name = "scale", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/math/accent.rs b/crates/typst/src/math/accent.rs
index 8f88c5b8..f1602f3c 100644
--- a/crates/typst/src/math/accent.rs
+++ b/crates/typst/src/math/accent.rs
@@ -1,7 +1,7 @@
use unicode_math_class::MathClass;
use crate::diag::{bail, SourceResult};
-use crate::foundations::{cast, elem, Content, NativeElement, Resolve, Smart, Value};
+use crate::foundations::{cast, elem, Content, Packed, Resolve, Smart, Value};
use crate::layout::{Em, Frame, Length, Point, Rel, Size};
use crate::math::{
FrameFragment, GlyphFragment, LayoutMath, MathContext, MathFragment, Scaled,
@@ -62,7 +62,7 @@ pub struct AccentElem {
pub size: Smart<Rel<Length>>,
}
-impl LayoutMath for AccentElem {
+impl LayoutMath for Packed<AccentElem> {
#[typst_macros::time(name = "math.accent", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
ctx.style(ctx.style.with_cramped(true));
diff --git a/crates/typst/src/math/align.rs b/crates/typst/src/math/align.rs
index 41f043b4..a1d396da 100644
--- a/crates/typst/src/math/align.rs
+++ b/crates/typst/src/math/align.rs
@@ -1,5 +1,5 @@
use crate::diag::SourceResult;
-use crate::foundations::elem;
+use crate::foundations::{elem, Packed};
use crate::layout::Abs;
use crate::math::{LayoutMath, MathContext, MathFragment, MathRow};
@@ -7,7 +7,7 @@ use crate::math::{LayoutMath, MathContext, MathFragment, MathRow};
#[elem(title = "Alignment Point", LayoutMath)]
pub struct AlignPointElem {}
-impl LayoutMath for AlignPointElem {
+impl LayoutMath for Packed<AlignPointElem> {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
ctx.push(MathFragment::Align);
Ok(())
diff --git a/crates/typst/src/math/attach.rs b/crates/typst/src/math/attach.rs
index a6f92afb..ff66a386 100644
--- a/crates/typst/src/math/attach.rs
+++ b/crates/typst/src/math/attach.rs
@@ -1,7 +1,7 @@
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
-use crate::foundations::{elem, Content, StyleChain};
+use crate::foundations::{elem, Content, Packed, StyleChain};
use crate::layout::{Abs, Frame, Point, Size};
use crate::math::{
FrameFragment, LayoutMath, MathContext, MathFragment, MathSize, Scaled,
@@ -48,7 +48,7 @@ pub struct AttachElem {
pub br: Option<Content>,
}
-impl LayoutMath for AttachElem {
+impl LayoutMath for Packed<AttachElem> {
#[typst_macros::time(name = "math.attach", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
type GetAttachment = fn(&AttachElem, styles: StyleChain) -> Option<Content>;
@@ -61,15 +61,15 @@ impl LayoutMath for AttachElem {
let base = ctx.layout_fragment(self.base())?;
ctx.style(ctx.style.for_superscript());
- let tl = layout_attachment(ctx, Self::tl)?;
- let tr = layout_attachment(ctx, Self::tr)?;
- let t = layout_attachment(ctx, Self::t)?;
+ let tl = layout_attachment(ctx, AttachElem::tl)?;
+ let tr = layout_attachment(ctx, AttachElem::tr)?;
+ let t = layout_attachment(ctx, AttachElem::t)?;
ctx.unstyle();
ctx.style(ctx.style.for_subscript());
- let bl = layout_attachment(ctx, Self::bl)?;
- let br = layout_attachment(ctx, Self::br)?;
- let b = layout_attachment(ctx, Self::b)?;
+ let bl = layout_attachment(ctx, AttachElem::bl)?;
+ let br = layout_attachment(ctx, AttachElem::br)?;
+ let b = layout_attachment(ctx, AttachElem::b)?;
ctx.unstyle();
let limits = base.limits().active(ctx);
@@ -96,7 +96,7 @@ pub struct PrimesElem {
pub count: usize,
}
-impl LayoutMath for PrimesElem {
+impl LayoutMath for Packed<PrimesElem> {
#[typst_macros::time(name = "math.primes", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
match *self.count() {
@@ -142,7 +142,7 @@ pub struct ScriptsElem {
pub body: Content,
}
-impl LayoutMath for ScriptsElem {
+impl LayoutMath for Packed<ScriptsElem> {
#[typst_macros::time(name = "math.scripts", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let mut fragment = ctx.layout_fragment(self.body())?;
@@ -171,7 +171,7 @@ pub struct LimitsElem {
pub inline: bool,
}
-impl LayoutMath for LimitsElem {
+impl LayoutMath for Packed<LimitsElem> {
#[typst_macros::time(name = "math.limits", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let mut fragment = ctx.layout_fragment(self.body())?;
diff --git a/crates/typst/src/math/cancel.rs b/crates/typst/src/math/cancel.rs
index 5fa34d7d..e01b98ca 100644
--- a/crates/typst/src/math/cancel.rs
+++ b/crates/typst/src/math/cancel.rs
@@ -1,7 +1,7 @@
use unicode_math_class::MathClass;
use crate::diag::{At, SourceResult};
-use crate::foundations::{cast, elem, Content, Func, NativeElement, Resolve, Smart};
+use crate::foundations::{cast, elem, Content, Func, Packed, Resolve, Smart};
use crate::layout::{
Abs, Angle, Frame, FrameItem, Length, Point, Ratio, Rel, Size, Transform,
};
@@ -105,7 +105,7 @@ pub struct CancelElem {
pub stroke: Stroke,
}
-impl LayoutMath for CancelElem {
+impl LayoutMath for Packed<CancelElem> {
#[typst_macros::time(name = "math.cancel", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let body = ctx.layout_fragment(self.body())?;
diff --git a/crates/typst/src/math/class.rs b/crates/typst/src/math/class.rs
index 1b229fce..9f430ad7 100644
--- a/crates/typst/src/math/class.rs
+++ b/crates/typst/src/math/class.rs
@@ -1,7 +1,7 @@
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
-use crate::foundations::{elem, Content};
+use crate::foundations::{elem, Content, Packed};
use crate::math::{LayoutMath, MathContext};
/// Forced use of a certain math class.
@@ -29,7 +29,7 @@ pub struct ClassElem {
pub body: Content,
}
-impl LayoutMath for ClassElem {
+impl LayoutMath for Packed<ClassElem> {
#[typst_macros::time(name = "math.class", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
ctx.style(ctx.style.with_class(*self.class()));
diff --git a/crates/typst/src/math/ctx.rs b/crates/typst/src/math/ctx.rs
index 2c88fe3c..0e7cb2e6 100644
--- a/crates/typst/src/math/ctx.rs
+++ b/crates/typst/src/math/ctx.rs
@@ -12,7 +12,7 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{Content, NativeElement, Smart, StyleChain, Styles};
+use crate::foundations::{Content, Packed, Smart, StyleChain, Styles};
use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size};
use crate::math::{
FrameFragment, GlyphFragment, LayoutMath, MathFragment, MathRow, MathSize, MathStyle,
@@ -173,7 +173,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
Ok(self.layout_fragment(elem)?.into_frame())
}
- pub fn layout_box(&mut self, boxed: &BoxElem) -> SourceResult<Frame> {
+ pub fn layout_box(&mut self, boxed: &Packed<BoxElem>) -> SourceResult<Frame> {
Ok(boxed
.layout(self.engine, self.outer.chain(&self.local), self.regions)?
.into_frame())
@@ -185,7 +185,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
.into_frame())
}
- pub fn layout_text(&mut self, elem: &TextElem) -> SourceResult<MathFragment> {
+ pub fn layout_text(&mut self, elem: &Packed<TextElem>) -> SourceResult<MathFragment> {
let text = elem.text();
let span = elem.span();
let mut chars = text.chars();
@@ -276,7 +276,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
// it will overflow. So emulate an `hbox` instead and allow the paragraph
// to extend as far as needed.
let span = elem.span();
- let frame = ParElem::new(vec![Prehashed::new(elem)])
+ let frame = Packed::new(ParElem::new(vec![Prehashed::new(elem)]))
.spanned(span)
.layout(
self.engine,
diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs
index 07f61bd3..4a0ee9b8 100644
--- a/crates/typst/src/math/equation.rs
+++ b/crates/typst/src/math/equation.rs
@@ -3,8 +3,8 @@ use std::num::NonZeroUsize;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- elem, Content, Finalize, Guard, NativeElement, Resolve, Show, Smart, StyleChain,
- Synthesize,
+ elem, Content, Finalize, Guard, NativeElement, Packed, Resolve, Show, Smart,
+ StyleChain, Synthesize,
};
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
use crate::layout::{
@@ -89,41 +89,41 @@ pub struct EquationElem {
pub body: Content,
}
-impl Synthesize for EquationElem {
+impl Synthesize for Packed<EquationElem> {
fn synthesize(
&mut self,
engine: &mut Engine,
styles: StyleChain,
) -> SourceResult<()> {
- // Resolve the supplement.
- let supplement = match self.supplement(styles) {
+ let supplement = match self.as_ref().supplement(styles) {
Smart::Auto => TextElem::packed(Self::local_name_in(styles)),
Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => {
- supplement.resolve(engine, [self.clone()])?
+ supplement.resolve(engine, [self.clone().pack()])?
}
};
- self.push_block(self.block(styles));
- self.push_numbering(self.numbering(styles));
- self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement))));
+ let elem = self.as_mut();
+ elem.push_block(elem.block(styles));
+ elem.push_numbering(elem.numbering(styles));
+ elem.push_supplement(Smart::Custom(Some(Supplement::Content(supplement))));
Ok(())
}
}
-impl Show for EquationElem {
+impl Show for Packed<EquationElem> {
#[typst_macros::time(name = "math.equation", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
- let mut realized = self.clone().pack().guarded(Guard::Base(Self::elem()));
+ let mut realized = self.clone().pack().guarded(Guard::Base(EquationElem::elem()));
if self.block(styles) {
- realized = AlignElem::new(realized).spanned(self.span()).pack();
+ realized = AlignElem::new(realized).pack().spanned(self.span());
}
Ok(realized)
}
}
-impl Finalize for EquationElem {
+impl Finalize for Packed<EquationElem> {
fn finalize(&self, realized: Content, style: StyleChain) -> Content {
let mut realized = realized;
if self.block(style) {
@@ -154,7 +154,7 @@ impl MathParItem {
}
}
-impl EquationElem {
+impl Packed<EquationElem> {
pub fn layout_inline(
&self,
engine: &mut Engine<'_>,
@@ -197,7 +197,7 @@ impl EquationElem {
}
}
-impl Layout for EquationElem {
+impl Layout for Packed<EquationElem> {
#[typst_macros::time(name = "math.equation", span = self.span())]
fn layout(
&self,
@@ -215,9 +215,9 @@ impl Layout for EquationElem {
let mut ctx = MathContext::new(engine, styles, regions, &font, true);
let mut frame = ctx.layout_frame(self)?;
- if let Some(numbering) = self.numbering(styles) {
+ if let Some(numbering) = (**self).numbering(styles) {
let pod = Regions::one(regions.base(), Axes::splat(false));
- let counter = Counter::of(Self::elem())
+ let counter = Counter::of(EquationElem::elem())
.display(self.span(), Some(numbering), false)
.layout(engine, styles, pod)?
.into_frame();
@@ -258,15 +258,14 @@ impl Layout for EquationElem {
}
}
-impl Count for EquationElem {
+impl Count for Packed<EquationElem> {
fn update(&self) -> Option<CounterUpdate> {
- (self.block(StyleChain::default())
- && self.numbering(StyleChain::default()).is_some())
- .then(|| CounterUpdate::Step(NonZeroUsize::ONE))
+ (self.block(StyleChain::default()) && self.numbering().is_some())
+ .then(|| CounterUpdate::Step(NonZeroUsize::ONE))
}
}
-impl LocalName for EquationElem {
+impl LocalName for Packed<EquationElem> {
fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Ekuacion",
@@ -304,35 +303,35 @@ impl LocalName for EquationElem {
}
}
-impl Refable for EquationElem {
+impl Refable for Packed<EquationElem> {
fn supplement(&self) -> Content {
// After synthesis, this should always be custom content.
- match self.supplement(StyleChain::default()) {
+ match (**self).supplement(StyleChain::default()) {
Smart::Custom(Some(Supplement::Content(content))) => content,
_ => Content::empty(),
}
}
fn counter(&self) -> Counter {
- Counter::of(Self::elem())
+ Counter::of(EquationElem::elem())
}
fn numbering(&self) -> Option<Numbering> {
- self.numbering(StyleChain::default())
+ (**self).numbering(StyleChain::default())
}
}
-impl Outlinable for EquationElem {
+impl Outlinable for Packed<EquationElem> {
fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> {
if !self.block(StyleChain::default()) {
return Ok(None);
}
- let Some(numbering) = self.numbering(StyleChain::default()) else {
+ let Some(numbering) = self.numbering() else {
return Ok(None);
};
// After synthesis, this should always be custom content.
- let mut supplement = match self.supplement(StyleChain::default()) {
+ let mut supplement = match (**self).supplement(StyleChain::default()) {
Smart::Custom(Some(Supplement::Content(content))) => content,
_ => Content::empty(),
};
@@ -350,7 +349,7 @@ impl Outlinable for EquationElem {
}
}
-impl LayoutMath for EquationElem {
+impl LayoutMath for Packed<EquationElem> {
#[typst_macros::time(name = "math.equation", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
self.body().layout_math(ctx)
diff --git a/crates/typst/src/math/frac.rs b/crates/typst/src/math/frac.rs
index b5ced71d..50185de2 100644
--- a/crates/typst/src/math/frac.rs
+++ b/crates/typst/src/math/frac.rs
@@ -1,5 +1,5 @@
use crate::diag::{bail, SourceResult};
-use crate::foundations::{elem, Content, NativeElement, Value};
+use crate::foundations::{elem, Content, Packed, Value};
use crate::layout::{Em, Frame, FrameItem, Point, Size};
use crate::math::{
FrameFragment, GlyphFragment, LayoutMath, MathContext, MathSize, Scaled,
@@ -35,7 +35,7 @@ pub struct FracElem {
pub denom: Content,
}
-impl LayoutMath for FracElem {
+impl LayoutMath for Packed<FracElem> {
#[typst_macros::time(name = "math.frac", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout(ctx, self.num(), std::slice::from_ref(self.denom()), false, self.span())
@@ -69,7 +69,7 @@ pub struct BinomElem {
pub lower: Vec<Content>,
}
-impl LayoutMath for BinomElem {
+impl LayoutMath for Packed<BinomElem> {
#[typst_macros::time(name = "math.binom", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout(ctx, self.upper(), self.lower(), true, self.span())
diff --git a/crates/typst/src/math/lr.rs b/crates/typst/src/math/lr.rs
index 4a1e758b..e2c098e7 100644
--- a/crates/typst/src/math/lr.rs
+++ b/crates/typst/src/math/lr.rs
@@ -1,7 +1,7 @@
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
-use crate::foundations::{elem, func, Content, NativeElement, Resolve, Smart};
+use crate::foundations::{elem, func, Content, NativeElement, Packed, Resolve, Smart};
use crate::layout::{Abs, Em, Length, Rel};
use crate::math::{
GlyphFragment, LayoutMath, MathContext, MathFragment, Scaled, SpacingFragment,
@@ -35,7 +35,7 @@ pub struct LrElem {
pub body: Content,
}
-impl LayoutMath for LrElem {
+impl LayoutMath for Packed<LrElem> {
#[typst_macros::time(name = "math.lr", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let mut body = self.body();
@@ -110,7 +110,7 @@ pub struct MidElem {
pub body: Content,
}
-impl LayoutMath for MidElem {
+impl LayoutMath for Packed<MidElem> {
#[typst_macros::time(name = "math.mid", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let mut fragments = ctx.layout_fragments(self.body())?;
@@ -255,11 +255,10 @@ fn delimited(
TextElem::packed(left),
body,
TextElem::packed(right),
- ]))
- .spanned(span);
+ ]));
// Push size only if size is provided
if let Some(size) = size {
elem.push_size(size);
}
- elem.pack()
+ elem.pack().spanned(span)
}
diff --git a/crates/typst/src/math/matrix.rs b/crates/typst/src/math/matrix.rs
index fe0a188c..0a3d0c2f 100644
--- a/crates/typst/src/math/matrix.rs
+++ b/crates/typst/src/math/matrix.rs
@@ -2,7 +2,7 @@ use smallvec::{smallvec, SmallVec};
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::foundations::{
- cast, dict, elem, Array, Cast, Content, Dict, Fold, NativeElement, Resolve, Smart,
+ cast, dict, elem, Array, Cast, Content, Dict, Fold, Packed, Resolve, Smart,
StyleChain, Value,
};
use crate::layout::{
@@ -57,7 +57,7 @@ pub struct VecElem {
pub children: Vec<Content>,
}
-impl LayoutMath for VecElem {
+impl LayoutMath for Packed<VecElem> {
#[typst_macros::time(name = "math.vec", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let delim = self.delim(ctx.styles());
@@ -210,11 +210,9 @@ pub struct MatElem {
pub rows: Vec<Vec<Content>>,
}
-impl LayoutMath for MatElem {
+impl LayoutMath for Packed<MatElem> {
#[typst_macros::time(name = "math.mat", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- // validate inputs
-
let augment = self.augment(ctx.styles());
let rows = self.rows();
@@ -311,7 +309,7 @@ pub struct CasesElem {
pub children: Vec<Content>,
}
-impl LayoutMath for CasesElem {
+impl LayoutMath for Packed<CasesElem> {
#[typst_macros::time(name = "math.cases", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let delim = self.delim(ctx.styles());
diff --git a/crates/typst/src/math/op.rs b/crates/typst/src/math/op.rs
index e1ac2b72..1d0645ff 100644
--- a/crates/typst/src/math/op.rs
+++ b/crates/typst/src/math/op.rs
@@ -2,7 +2,7 @@ use ecow::EcoString;
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
-use crate::foundations::{elem, Content, NativeElement, Scope};
+use crate::foundations::{elem, Content, NativeElement, Packed, Scope};
use crate::layout::HElem;
use crate::math::{FrameFragment, LayoutMath, Limits, MathContext, MathStyleElem, THIN};
use crate::text::TextElem;
@@ -33,7 +33,7 @@ pub struct OpElem {
pub limits: bool,
}
-impl LayoutMath for OpElem {
+impl LayoutMath for Packed<OpElem> {
#[typst_macros::time(name = "math.op", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let fragment = ctx.layout_fragment(self.text())?;
diff --git a/crates/typst/src/math/root.rs b/crates/typst/src/math/root.rs
index badb8e86..db3a7b85 100644
--- a/crates/typst/src/math/root.rs
+++ b/crates/typst/src/math/root.rs
@@ -1,5 +1,5 @@
use crate::diag::SourceResult;
-use crate::foundations::{elem, func, Content, NativeElement};
+use crate::foundations::{elem, func, Content, NativeElement, Packed};
use crate::layout::{Abs, Frame, FrameItem, Point, Size};
use crate::math::{
FrameFragment, GlyphFragment, LayoutMath, MathContext, MathSize, Scaled,
@@ -20,7 +20,7 @@ pub fn sqrt(
/// The expression to take the square root of.
radicand: Content,
) -> Content {
- RootElem::new(radicand).spanned(span).pack()
+ RootElem::new(radicand).pack().spanned(span)
}
/// A general root.
@@ -39,7 +39,7 @@ pub struct RootElem {
pub radicand: Content,
}
-impl LayoutMath for RootElem {
+impl LayoutMath for Packed<RootElem> {
#[typst_macros::time(name = "math.root", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout(ctx, self.index(ctx.styles()).as_ref(), self.radicand(), self.span())
diff --git a/crates/typst/src/math/style.rs b/crates/typst/src/math/style.rs
index 00c7bef0..0d3c06fa 100644
--- a/crates/typst/src/math/style.rs
+++ b/crates/typst/src/math/style.rs
@@ -1,7 +1,9 @@
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
-use crate::foundations::{elem, func, Cast, Content, NativeElement, Smart, StyleChain};
+use crate::foundations::{
+ elem, func, Cast, Content, NativeElement, Packed, Smart, StyleChain,
+};
use crate::math::{LayoutMath, MathContext};
use crate::syntax::Span;
@@ -17,7 +19,7 @@ pub fn bold(
/// The content to style.
body: Content,
) -> Content {
- MathStyleElem::new(body).spanned(span).with_bold(Some(true)).pack()
+ MathStyleElem::new(body).with_bold(Some(true)).pack().spanned(span)
}
/// Upright (non-italic) font style in math.
@@ -32,7 +34,7 @@ pub fn upright(
/// The content to style.
body: Content,
) -> Content {
- MathStyleElem::new(body).spanned(span).with_italic(Some(false)).pack()
+ MathStyleElem::new(body).with_italic(Some(false)).pack().spanned(span)
}
/// Italic font style in math.
@@ -45,7 +47,7 @@ pub fn italic(
/// The content to style.
body: Content,
) -> Content {
- MathStyleElem::new(body).spanned(span).with_italic(Some(true)).pack()
+ MathStyleElem::new(body).with_italic(Some(true)).pack().spanned(span)
}
/// Serif (roman) font style in math.
///
@@ -58,9 +60,9 @@ pub fn serif(
body: Content,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_variant(Some(MathVariant::Serif))
.pack()
+ .spanned(span)
}
/// Sans-serif font style in math.
@@ -76,9 +78,9 @@ pub fn sans(
body: Content,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_variant(Some(MathVariant::Sans))
.pack()
+ .spanned(span)
}
/// Calligraphic font style in math.
@@ -94,9 +96,9 @@ pub fn cal(
body: Content,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_variant(Some(MathVariant::Cal))
.pack()
+ .spanned(span)
}
/// Fraktur font style in math.
@@ -112,9 +114,9 @@ pub fn frak(
body: Content,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_variant(Some(MathVariant::Frak))
.pack()
+ .spanned(span)
}
/// Monospace font style in math.
@@ -130,9 +132,9 @@ pub fn mono(
body: Content,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_variant(Some(MathVariant::Mono))
.pack()
+ .spanned(span)
}
/// Blackboard bold (double-struck) font style in math.
@@ -153,9 +155,9 @@ pub fn bb(
body: Content,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_variant(Some(MathVariant::Bb))
.pack()
+ .spanned(span)
}
/// Forced display style in math.
@@ -178,10 +180,10 @@ pub fn display(
cramped: bool,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_size(Some(MathSize::Display))
.with_cramped(Some(cramped))
.pack()
+ .spanned(span)
}
/// Forced inline (text) style in math.
@@ -205,10 +207,10 @@ pub fn inline(
cramped: bool,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_size(Some(MathSize::Text))
.with_cramped(Some(cramped))
.pack()
+ .spanned(span)
}
/// Forced script style in math.
@@ -231,10 +233,10 @@ pub fn script(
cramped: bool,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_size(Some(MathSize::Script))
.with_cramped(Some(cramped))
.pack()
+ .spanned(span)
}
/// Forced second script style in math.
@@ -258,10 +260,10 @@ pub fn sscript(
cramped: bool,
) -> Content {
MathStyleElem::new(body)
- .spanned(span)
.with_size(Some(MathSize::ScriptScript))
.with_cramped(Some(cramped))
.pack()
+ .spanned(span)
}
/// A font variant in math.
@@ -287,7 +289,7 @@ pub struct MathStyleElem {
pub cramped: Option<bool>,
}
-impl LayoutMath for MathStyleElem {
+impl LayoutMath for Packed<MathStyleElem> {
#[typst_macros::time(name = "math.style", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let mut style = ctx.style;
diff --git a/crates/typst/src/math/underover.rs b/crates/typst/src/math/underover.rs
index c3a2a573..593493b8 100644
--- a/crates/typst/src/math/underover.rs
+++ b/crates/typst/src/math/underover.rs
@@ -1,7 +1,7 @@
use unicode_math_class::MathClass;
use crate::diag::SourceResult;
-use crate::foundations::{elem, Content, NativeElement};
+use crate::foundations::{elem, Content, Packed};
use crate::layout::{Abs, Em, FixedAlign, Frame, FrameItem, Point, Size};
use crate::math::{
alignments, AlignmentResult, FrameFragment, GlyphFragment, LayoutMath, MathContext,
@@ -32,7 +32,7 @@ pub struct UnderlineElem {
pub body: Content,
}
-impl LayoutMath for UnderlineElem {
+impl LayoutMath for Packed<UnderlineElem> {
#[typst_macros::time(name = "math.underline", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverline(ctx, self.body(), self.span(), LineKind::Under)
@@ -51,7 +51,7 @@ pub struct OverlineElem {
pub body: Content,
}
-impl LayoutMath for OverlineElem {
+impl LayoutMath for Packed<OverlineElem> {
#[typst_macros::time(name = "math.overline", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverline(ctx, self.body(), self.span(), LineKind::Over)
@@ -136,7 +136,7 @@ pub struct UnderbraceElem {
pub annotation: Option<Content>,
}
-impl LayoutMath for UnderbraceElem {
+impl LayoutMath for Packed<UnderbraceElem> {
#[typst_macros::time(name = "math.underbrace", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
@@ -167,7 +167,7 @@ pub struct OverbraceElem {
pub annotation: Option<Content>,
}
-impl LayoutMath for OverbraceElem {
+impl LayoutMath for Packed<OverbraceElem> {
#[typst_macros::time(name = "math.overbrace", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
@@ -198,7 +198,7 @@ pub struct UnderbracketElem {
pub annotation: Option<Content>,
}
-impl LayoutMath for UnderbracketElem {
+impl LayoutMath for Packed<UnderbracketElem> {
#[typst_macros::time(name = "math.underbrace", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
@@ -229,7 +229,7 @@ pub struct OverbracketElem {
pub annotation: Option<Content>,
}
-impl LayoutMath for OverbracketElem {
+impl LayoutMath for Packed<OverbracketElem> {
#[typst_macros::time(name = "math.overbracket", span = self.span())]
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
layout_underoverspreader(
diff --git a/crates/typst/src/model/bibliography.rs b/crates/typst/src/model/bibliography.rs
index ecffcb78..06a80d6b 100644
--- a/crates/typst/src/model/bibliography.rs
+++ b/crates/typst/src/model/bibliography.rs
@@ -24,8 +24,8 @@ use crate::engine::Engine;
use crate::eval::{eval_string, EvalMode};
use crate::foundations::{
cast, elem, ty, Args, Array, Bytes, CastInfo, Content, Finalize, FromValue,
- IntoValue, Label, NativeElement, Reflect, Repr, Scope, Show, Smart, Str, StyleChain,
- Synthesize, Type, Value,
+ IntoValue, Label, NativeElement, Packed, Reflect, Repr, Scope, Show, Smart, Str,
+ StyleChain, Synthesize, Type, Value,
};
use crate::introspection::{Introspector, Locatable, Location};
use crate::layout::{
@@ -155,7 +155,7 @@ cast! {
impl BibliographyElem {
/// Find the document's bibliography.
- pub fn find(introspector: Tracked<Introspector>) -> StrResult<Self> {
+ pub fn find(introspector: Tracked<Introspector>) -> StrResult<Packed<Self>> {
let query = introspector.query(&Self::elem().select());
let mut iter = query.iter();
let Some(elem) = iter.next() else {
@@ -166,7 +166,7 @@ impl BibliographyElem {
bail!("multiple bibliographies are not yet supported");
}
- Ok(elem.to::<Self>().cloned().unwrap())
+ Ok(elem.to::<Self>().unwrap().clone())
}
/// Whether the bibliography contains the given key.
@@ -196,17 +196,18 @@ impl BibliographyElem {
}
}
-impl Synthesize for BibliographyElem {
+impl Synthesize for Packed<BibliographyElem> {
fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> {
- self.push_full(self.full(styles));
- self.push_style(self.style(styles));
- self.push_lang(TextElem::lang_in(styles));
- self.push_region(TextElem::region_in(styles));
+ let elem = self.as_mut();
+ elem.push_full(elem.full(styles));
+ elem.push_style(elem.style(styles));
+ elem.push_lang(TextElem::lang_in(styles));
+ elem.push_region(TextElem::region_in(styles));
Ok(())
}
}
-impl Show for BibliographyElem {
+impl Show for Packed<BibliographyElem> {
#[typst_macros::time(name = "bibliography", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
const COLUMN_GUTTER: Em = Em::new(0.65);
@@ -220,9 +221,9 @@ impl Show for BibliographyElem {
seq.push(
HeadingElem::new(title)
- .spanned(self.span())
.with_level(NonZeroUsize::ONE)
- .pack(),
+ .pack()
+ .spanned(self.span()),
);
}
@@ -246,11 +247,11 @@ impl Show for BibliographyElem {
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
seq.push(
GridElem::new(cells)
- .spanned(self.span())
.with_columns(TrackSizings(smallvec![Sizing::Auto; 2]))
.with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()]))
.with_row_gutter(TrackSizings(smallvec![(row_gutter).into()]))
- .pack(),
+ .pack()
+ .spanned(self.span()),
);
} else {
for (_, reference) in references {
@@ -269,7 +270,7 @@ impl Show for BibliographyElem {
}
}
-impl Finalize for BibliographyElem {
+impl Finalize for Packed<BibliographyElem> {
fn finalize(&self, realized: Content, _: StyleChain) -> Content {
const INDENT: Em = Em::new(1.0);
realized
@@ -278,7 +279,7 @@ impl Finalize for BibliographyElem {
}
}
-impl LocalName for BibliographyElem {
+impl LocalName for Packed<BibliographyElem> {
fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Bibliografi",
@@ -607,7 +608,7 @@ struct Generator<'a> {
/// The world that is used to evaluate mathematical material in citations.
world: Tracked<'a, dyn World + 'a>,
/// The document's bibliography.
- bibliography: BibliographyElem,
+ bibliography: Packed<BibliographyElem>,
/// The document's citation groups.
groups: EcoVec<Prehashed<Content>>,
/// Details about each group that are accumulated while driving hayagriva's
@@ -672,7 +673,7 @@ impl<'a> Generator<'a> {
let mut driver = BibliographyDriver::new();
for elem in &self.groups {
let group = elem.to::<CiteGroup>().unwrap();
- let location = group.location().unwrap();
+ let location = elem.location().unwrap();
let children = group.children();
// Groups should never be empty.
@@ -945,19 +946,19 @@ impl ElemRenderer<'_> {
if let Some(prefix) = suf_prefix {
const COLUMN_GUTTER: Em = Em::new(0.65);
content = GridElem::new(vec![GridCell::new(prefix), GridCell::new(content)])
- .spanned(self.span)
.with_columns(TrackSizings(smallvec![Sizing::Auto; 2]))
.with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()]))
- .pack();
+ .pack()
+ .spanned(self.span);
}
match elem.display {
Some(Display::Block) => {
content =
- BlockElem::new().spanned(self.span).with_body(Some(content)).pack();
+ BlockElem::new().with_body(Some(content)).pack().spanned(self.span);
}
Some(Display::Indent) => {
- content = PadElem::new(content).spanned(self.span).pack();
+ content = PadElem::new(content).pack().spanned(self.span);
}
Some(Display::LeftMargin) => {
*prefix.get_or_insert_with(Default::default) += content;
@@ -987,8 +988,8 @@ impl ElemRenderer<'_> {
fn display_link(&self, text: &hayagriva::Formatted, url: &str) -> Content {
let dest = Destination::Url(url.into());
LinkElem::new(dest.into(), self.display_formatted(text))
- .spanned(self.span)
.pack()
+ .spanned(self.span)
}
/// Display transparent pass-through content.
@@ -1043,10 +1044,10 @@ fn apply_formatting(mut content: Content, format: &hayagriva::Formatting) -> Con
citationberg::VerticalAlign::Baseline => {}
citationberg::VerticalAlign::Sup => {
// Add zero-width weak spacing to make the superscript "sticky".
- content = HElem::hole().pack() + SuperElem::new(content).spanned(span).pack();
+ content = HElem::hole().pack() + SuperElem::new(content).pack().spanned(span);
}
citationberg::VerticalAlign::Sub => {
- content = HElem::hole().pack() + SubElem::new(content).spanned(span).pack();
+ content = HElem::hole().pack() + SubElem::new(content).pack().spanned(span);
}
}
diff --git a/crates/typst/src/model/cite.rs b/crates/typst/src/model/cite.rs
index d2b50790..2e28a834 100644
--- a/crates/typst/src/model/cite.rs
+++ b/crates/typst/src/model/cite.rs
@@ -1,7 +1,7 @@
use crate::diag::{bail, At, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, Cast, Content, Label, NativeElement, Show, Smart, StyleChain, Synthesize,
+ cast, elem, Cast, Content, Label, Packed, Show, Smart, StyleChain, Synthesize,
};
use crate::introspection::Locatable;
use crate::model::bibliography::Works;
@@ -99,20 +99,21 @@ pub struct CiteElem {
pub region: Option<Region>,
}
-impl Synthesize for CiteElem {
+impl Synthesize for Packed<CiteElem> {
fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> {
- self.push_supplement(self.supplement(styles));
- self.push_form(self.form(styles));
- self.push_style(self.style(styles));
- self.push_lang(TextElem::lang_in(styles));
- self.push_region(TextElem::region_in(styles));
+ let elem = self.as_mut();
+ elem.push_supplement(elem.supplement(styles));
+ elem.push_form(elem.form(styles));
+ elem.push_style(elem.style(styles));
+ elem.push_lang(TextElem::lang_in(styles));
+ elem.push_region(TextElem::region_in(styles));
Ok(())
}
}
cast! {
CiteElem,
- v: Content => v.to::<Self>().cloned().ok_or("expected citation")?,
+ v: Content => v.to_packed::<Self>().map_err(|_| "expected citation")?.unpack(),
}
/// The form of the citation.
@@ -139,10 +140,10 @@ pub enum CitationForm {
pub struct CiteGroup {
/// The citations.
#[required]
- pub children: Vec<CiteElem>,
+ pub children: Vec<Packed<CiteElem>>,
}
-impl Show for CiteGroup {
+impl Show for Packed<CiteGroup> {
#[typst_macros::time(name = "cite", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
diff --git a/crates/typst/src/model/document.rs b/crates/typst/src/model/document.rs
index 65b4280b..018a8d25 100644
--- a/crates/typst/src/model/document.rs
+++ b/crates/typst/src/model/document.rs
@@ -3,7 +3,8 @@ use ecow::EcoString;
use crate::diag::{bail, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, Args, Array, Construct, Content, Datetime, Smart, StyleChain, Value,
+ cast, elem, Args, Array, Construct, Content, Datetime, Packed, Smart, StyleChain,
+ Value,
};
use crate::introspection::{Introspector, ManualPageCounter};
use crate::layout::{Frame, LayoutRoot, PageElem};
@@ -65,7 +66,7 @@ impl Construct for DocumentElem {
}
}
-impl LayoutRoot for DocumentElem {
+impl LayoutRoot for Packed<DocumentElem> {
/// Layout the document into a sequence of frames, one per page.
#[typst_macros::time(name = "document", span = self.span())]
fn layout_root(
diff --git a/crates/typst/src/model/emph.rs b/crates/typst/src/model/emph.rs
index 46fa0ca9..b67643de 100644
--- a/crates/typst/src/model/emph.rs
+++ b/crates/typst/src/model/emph.rs
@@ -1,6 +1,6 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, Show, StyleChain};
+use crate::foundations::{elem, Content, Packed, Show, StyleChain};
use crate::text::{ItalicToggle, TextElem};
/// Emphasizes content by toggling italics.
@@ -33,7 +33,7 @@ pub struct EmphElem {
pub body: Content,
}
-impl Show for EmphElem {
+impl Show for Packed<EmphElem> {
#[typst_macros::time(name = "emph", span = self.span())]
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone().styled(TextElem::set_emph(ItalicToggle)))
diff --git a/crates/typst/src/model/enum.rs b/crates/typst/src/model/enum.rs
index ad0789f0..870ff3b6 100644
--- a/crates/typst/src/model/enum.rs
+++ b/crates/typst/src/model/enum.rs
@@ -3,7 +3,7 @@ use std::str::FromStr;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, Array, Content, Fold, NativeElement, Smart, StyleChain,
+ cast, elem, scope, Array, Content, Fold, Packed, Smart, StyleChain,
};
use crate::layout::{
Alignment, Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment,
@@ -194,7 +194,7 @@ pub struct EnumElem {
/// ) [+ #phase]
/// ```
#[variadic]
- pub children: Vec<EnumItem>,
+ pub children: Vec<Packed<EnumItem>>,
/// The numbers of parent items.
#[internal]
@@ -208,7 +208,7 @@ impl EnumElem {
type EnumItem;
}
-impl Layout for EnumElem {
+impl Layout for Packed<EnumElem> {
#[typst_macros::time(name = "enum", span = self.span())]
fn layout(
&self,
@@ -263,7 +263,7 @@ impl Layout for EnumElem {
cells.push(Cell::from(resolved));
cells.push(Cell::from(Content::empty()));
cells.push(Cell::from(
- item.body().clone().styled(Self::set_parents(Parent(number))),
+ item.body().clone().styled(EnumElem::set_parents(Parent(number))),
));
number = number.saturating_add(1);
}
@@ -308,7 +308,10 @@ cast! {
};
Self::new(body).with_number(number)
},
- v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())),
+ v: Content => match v.to_packed::<Self>() {
+ Ok(packed) => packed.unpack(),
+ Err(v) => Self::new(v),
+ },
}
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
diff --git a/crates/typst/src/model/figure.rs b/crates/typst/src/model/figure.rs
index ad77f171..e42bf68a 100644
--- a/crates/typst/src/model/figure.rs
+++ b/crates/typst/src/model/figure.rs
@@ -7,8 +7,8 @@ use ecow::EcoString;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, select_where, Content, Element, Finalize, NativeElement, Selector,
- Show, Smart, StyleChain, Synthesize,
+ cast, elem, scope, select_where, Content, Element, Finalize, NativeElement, Packed,
+ Selector, Show, Smart, StyleChain, Synthesize,
};
use crate::introspection::{
Count, Counter, CounterKey, CounterUpdate, Locatable, Location,
@@ -134,7 +134,7 @@ pub struct FigureElem {
pub placement: Option<Smart<VAlignment>>,
/// The figure's caption.
- pub caption: Option<FigureCaption>,
+ pub caption: Option<Packed<FigureCaption>>,
/// The kind of figure this is.
///
@@ -222,24 +222,29 @@ impl FigureElem {
type FigureCaption;
}
-impl Synthesize for FigureElem {
+impl Synthesize for Packed<FigureElem> {
fn synthesize(
&mut self,
engine: &mut Engine,
styles: StyleChain,
) -> SourceResult<()> {
- let numbering = self.numbering(styles);
+ let span = self.span();
+ let location = self.location();
+
+ let elem = self.as_mut();
+ let placement = elem.placement(styles);
+ let numbering = elem.numbering(styles);
// Determine the figure's kind.
- let kind = self.kind(styles).unwrap_or_else(|| {
- self.body()
+ let kind = elem.kind(styles).unwrap_or_else(|| {
+ elem.body()
.query_first(Selector::can::<dyn Figurable>())
.map(|elem| FigureKind::Elem(elem.func()))
.unwrap_or_else(|| FigureKind::Elem(ImageElem::elem()))
});
// Resolve the supplement.
- let supplement = match self.supplement(styles).as_ref() {
+ let supplement = match elem.supplement(styles).as_ref() {
Smart::Auto => {
// Default to the local name for the kind, if available.
let name = match &kind {
@@ -253,7 +258,7 @@ impl Synthesize for FigureElem {
};
if numbering.is_some() && name.is_none() {
- bail!(self.span(), "please specify the figure's supplement")
+ bail!(span, "please specify the figure's supplement")
}
Some(name.unwrap_or_default())
@@ -263,45 +268,46 @@ impl Synthesize for FigureElem {
// Resolve the supplement with the first descendant of the kind or
// just the body, if none was found.
let descendant = match kind {
- FigureKind::Elem(func) => self
+ FigureKind::Elem(func) => elem
.body()
.query_first(Selector::Elem(func, None))
.map(Cow::Owned),
FigureKind::Name(_) => None,
};
- let target = descendant.unwrap_or_else(|| Cow::Borrowed(self.body()));
+ let target = descendant.unwrap_or_else(|| Cow::Borrowed(elem.body()));
Some(supplement.resolve(engine, [target])?)
}
};
// Construct the figure's counter.
- let counter =
- Counter::new(CounterKey::Selector(select_where!(Self, Kind => kind.clone())));
+ let counter = Counter::new(CounterKey::Selector(
+ select_where!(FigureElem, Kind => kind.clone()),
+ ));
// Fill the figure's caption.
- let mut caption = self.caption(styles);
+ let mut caption = elem.caption(styles);
if let Some(caption) = &mut caption {
caption.push_kind(kind.clone());
caption.push_supplement(supplement.clone());
caption.push_numbering(numbering.clone());
caption.push_counter(Some(counter.clone()));
- caption.push_figure_location(self.location());
+ caption.push_figure_location(location);
}
- self.push_placement(self.placement(styles));
- self.push_caption(caption);
- self.push_kind(Smart::Custom(kind));
- self.push_supplement(Smart::Custom(supplement.map(Supplement::Content)));
- self.push_numbering(numbering);
- self.push_outlined(self.outlined(styles));
- self.push_counter(Some(counter));
+ elem.push_placement(placement);
+ elem.push_caption(caption);
+ elem.push_kind(Smart::Custom(kind));
+ elem.push_supplement(Smart::Custom(supplement.map(Supplement::Content)));
+ elem.push_numbering(numbering);
+ elem.push_outlined(elem.outlined(styles));
+ elem.push_counter(Some(counter));
Ok(())
}
}
-impl Show for FigureElem {
+impl Show for Packed<FigureElem> {
#[typst_macros::time(name = "figure", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let mut realized = self.body().clone();
@@ -319,60 +325,62 @@ impl Show for FigureElem {
// Wrap the contents in a block.
realized = BlockElem::new()
.with_body(Some(realized))
- .spanned(self.span())
.pack()
+ .spanned(self.span())
.aligned(Alignment::CENTER);
// Wrap in a float.
if let Some(align) = self.placement(styles) {
realized = PlaceElem::new(realized)
- .spanned(self.span())
.with_float(true)
.with_alignment(align.map(|align| HAlignment::Center + align))
- .pack();
+ .pack()
+ .spanned(self.span());
}
Ok(realized)
}
}
-impl Finalize for FigureElem {
+impl Finalize for Packed<FigureElem> {
fn finalize(&self, realized: Content, _: StyleChain) -> Content {
// Allow breakable figures with `show figure: set block(breakable: true)`.
realized.styled(BlockElem::set_breakable(false))
}
}
-impl Count for FigureElem {
+impl Count for Packed<FigureElem> {
fn update(&self) -> Option<CounterUpdate> {
// If the figure is numbered, step the counter by one.
// This steps the `counter(figure)` which is global to all numbered figures.
- self.numbering(StyleChain::default())
+ self.numbering()
.is_some()
.then(|| CounterUpdate::Step(NonZeroUsize::ONE))
}
}
-impl Refable for FigureElem {
+impl Refable for Packed<FigureElem> {
fn supplement(&self) -> Content {
// After synthesis, this should always be custom content.
- let default = StyleChain::default();
- match self.supplement(default).as_ref() {
+ match (**self).supplement(StyleChain::default()).as_ref() {
Smart::Custom(Some(Supplement::Content(content))) => content.clone(),
_ => Content::empty(),
}
}
fn counter(&self) -> Counter {
- self.counter().clone().unwrap_or_else(|| Counter::of(Self::elem()))
+ (**self)
+ .counter()
+ .clone()
+ .unwrap_or_else(|| Counter::of(FigureElem::elem()))
}
fn numbering(&self) -> Option<Numbering> {
- self.numbering(StyleChain::default())
+ (**self).numbering(StyleChain::default())
}
}
-impl Outlinable for FigureElem {
+impl Outlinable for Packed<FigureElem> {
fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> {
if !self.outlined(StyleChain::default()) {
return Ok(None);
@@ -388,9 +396,9 @@ impl Outlinable for FigureElem {
Some(counter),
Some(numbering),
) = (
- self.supplement(StyleChain::default()).clone(),
- self.counter(),
- self.numbering(StyleChain::default()),
+ (**self).supplement(StyleChain::default()).clone(),
+ (**self).counter(),
+ self.numbering(),
) {
let location = self.location().unwrap();
let numbers = counter.at(engine, location)?.display(engine, &numbering)?;
@@ -546,15 +554,16 @@ impl FigureCaption {
}
}
-impl Synthesize for FigureCaption {
+impl Synthesize for Packed<FigureCaption> {
fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> {
- self.push_position(self.position(styles));
- self.push_separator(Smart::Custom(self.get_separator(styles)));
+ let elem = self.as_mut();
+ elem.push_position(elem.position(styles));
+ elem.push_separator(Smart::Custom(elem.get_separator(styles)));
Ok(())
}
}
-impl Show for FigureCaption {
+impl Show for Packed<FigureCaption> {
#[typst_macros::time(name = "figure.caption", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let mut realized = self.body().clone();
@@ -578,7 +587,10 @@ impl Show for FigureCaption {
cast! {
FigureCaption,
- v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())),
+ v: Content => match v.to_packed::<Self>() {
+ Ok(packed) => packed.unpack(),
+ Err(v) => Self::new(v),
+ },
}
/// The `kind` parameter of a [`FigureElem`].
diff --git a/crates/typst/src/model/footnote.rs b/crates/typst/src/model/footnote.rs
index 1f9ce704..241f8db5 100644
--- a/crates/typst/src/model/footnote.rs
+++ b/crates/typst/src/model/footnote.rs
@@ -4,8 +4,8 @@ use std::str::FromStr;
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain,
- Synthesize,
+ cast, elem, scope, Content, Finalize, Label, NativeElement, Packed, Show, Smart,
+ StyleChain, Synthesize,
};
use crate::introspection::{Count, Counter, CounterUpdate, Locatable, Location};
use crate::layout::{Abs, Em, HElem, Length, Ratio};
@@ -104,7 +104,9 @@ impl FootnoteElem {
_ => None,
}
}
+}
+impl Packed<FootnoteElem> {
/// Returns the location of the definition of this footnote.
pub fn declaration_location(&self, engine: &Engine) -> StrResult<Location> {
match self.body() {
@@ -120,22 +122,23 @@ impl FootnoteElem {
}
}
-impl Synthesize for FootnoteElem {
+impl Synthesize for Packed<FootnoteElem> {
fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> {
- self.push_numbering(self.numbering(styles).clone());
+ let elem = self.as_mut();
+ elem.push_numbering(elem.numbering(styles).clone());
Ok(())
}
}
-impl Show for FootnoteElem {
+impl Show for Packed<FootnoteElem> {
#[typst_macros::time(name = "footnote", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let loc = self.declaration_location(engine).at(self.span())?;
let numbering = self.numbering(styles);
- let counter = Counter::of(Self::elem());
+ let counter = Counter::of(FootnoteElem::elem());
let num = counter.at(engine, loc)?.display(engine, numbering)?;
- let sup = SuperElem::new(num).spanned(self.span()).pack();
+ let sup = SuperElem::new(num).pack().spanned(self.span());
let loc = loc.variant(1);
// Add zero-width weak spacing to make the footnote "sticky".
Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc)))
@@ -143,7 +146,7 @@ impl Show for FootnoteElem {
}
}
-impl Count for FootnoteElem {
+impl Count for Packed<FootnoteElem> {
fn update(&self) -> Option<CounterUpdate> {
(!self.is_ref()).then(|| CounterUpdate::Step(NonZeroUsize::ONE))
}
@@ -203,7 +206,7 @@ pub struct FootnoteEntry {
/// listing #footnote[World! 🌏]
/// ```
#[required]
- pub note: FootnoteElem,
+ pub note: Packed<FootnoteElem>,
/// The separator between the document body and the footnote listing.
///
@@ -269,7 +272,7 @@ pub struct FootnoteEntry {
pub indent: Length,
}
-impl Show for FootnoteEntry {
+impl Show for Packed<FootnoteEntry> {
#[typst_macros::time(name = "footnote.entry", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let note = self.note();
@@ -286,8 +289,8 @@ impl Show for FootnoteEntry {
let num = counter.at(engine, loc)?.display(engine, numbering)?;
let sup = SuperElem::new(num)
- .spanned(self.span())
.pack()
+ .spanned(self.span())
.linked(Destination::Location(loc))
.backlinked(loc.variant(1));
Ok(Content::sequence([
@@ -299,7 +302,7 @@ impl Show for FootnoteEntry {
}
}
-impl Finalize for FootnoteEntry {
+impl Finalize for Packed<FootnoteEntry> {
fn finalize(&self, realized: Content, _: StyleChain) -> Content {
let text_size = Em::new(0.85);
let leading = Em::new(0.5);
@@ -311,5 +314,8 @@ impl Finalize for FootnoteEntry {
cast! {
FootnoteElem,
- v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::with_content(v.clone())),
+ v: Content => match v.to_packed::<Self>() {
+ Ok(packed) => packed.unpack(),
+ Err(v) => Self::with_content(v),
+ }
}
diff --git a/crates/typst/src/model/heading.rs b/crates/typst/src/model/heading.rs
index bbddcb04..ef5e4007 100644
--- a/crates/typst/src/model/heading.rs
+++ b/crates/typst/src/model/heading.rs
@@ -3,7 +3,7 @@ use std::num::NonZeroUsize;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, Content, Finalize, NativeElement, Show, Smart, StyleChain, Styles,
+ elem, Content, Finalize, NativeElement, Packed, Show, Smart, StyleChain, Styles,
Synthesize,
};
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
@@ -126,53 +126,49 @@ pub struct HeadingElem {
pub body: Content,
}
-impl Synthesize for HeadingElem {
+impl Synthesize for Packed<HeadingElem> {
fn synthesize(
&mut self,
engine: &mut Engine,
styles: StyleChain,
) -> SourceResult<()> {
- // Resolve the supplement.
- let supplement = match self.supplement(styles) {
+ let supplement = match (**self).supplement(styles) {
Smart::Auto => TextElem::packed(Self::local_name_in(styles)),
Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => {
- supplement.resolve(engine, [self.clone()])?
+ supplement.resolve(engine, [self.clone().pack()])?
}
};
- self.push_level(self.level(styles));
- self.push_numbering(self.numbering(styles).clone());
- self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement))));
- self.push_outlined(self.outlined(styles));
- self.push_bookmarked(self.bookmarked(styles));
+ let elem = self.as_mut();
+ elem.push_level(elem.level(styles));
+ elem.push_numbering(elem.numbering(styles).clone());
+ elem.push_supplement(Smart::Custom(Some(Supplement::Content(supplement))));
+ elem.push_outlined(elem.outlined(styles));
+ elem.push_bookmarked(elem.bookmarked(styles));
Ok(())
}
}
-impl Show for HeadingElem {
+impl Show for Packed<HeadingElem> {
#[typst_macros::time(name = "heading", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let mut realized = self.body().clone();
- if let Some(numbering) = self.numbering(styles).as_ref() {
- realized = Counter::of(Self::elem())
+ if let Some(numbering) = (**self).numbering(styles).as_ref() {
+ realized = Counter::of(HeadingElem::elem())
.display(self.span(), Some(numbering.clone()), false)
.spanned(self.span())
+ HElem::new(Em::new(0.3).into()).with_weak(true).pack()
+ realized;
}
- Ok(BlockElem::new()
- .spanned(self.span())
- .spanned(self.span())
- .with_body(Some(realized))
- .pack())
+ Ok(BlockElem::new().with_body(Some(realized)).pack().spanned(self.span()))
}
}
-impl Finalize for HeadingElem {
+impl Finalize for Packed<HeadingElem> {
fn finalize(&self, realized: Content, styles: StyleChain) -> Content {
- let level = self.level(styles).get();
+ let level = (**self).level(styles).get();
let scale = match level {
1 => 1.4,
2 => 1.2,
@@ -193,47 +189,42 @@ impl Finalize for HeadingElem {
}
}
-impl Count for HeadingElem {
+impl Count for Packed<HeadingElem> {
fn update(&self) -> Option<CounterUpdate> {
- self.numbering(StyleChain::default())
+ (**self)
+ .numbering(StyleChain::default())
.is_some()
- .then(|| CounterUpdate::Step(self.level(StyleChain::default())))
+ .then(|| CounterUpdate::Step((**self).level(StyleChain::default())))
}
}
-cast! {
- HeadingElem,
- v: Content => v.to::<Self>().ok_or("expected heading")?.clone(),
-}
-
-impl Refable for HeadingElem {
+impl Refable for Packed<HeadingElem> {
fn supplement(&self) -> Content {
// After synthesis, this should always be custom content.
- match self.supplement(StyleChain::default()) {
+ match (**self).supplement(StyleChain::default()) {
Smart::Custom(Some(Supplement::Content(content))) => content,
_ => Content::empty(),
}
}
fn counter(&self) -> Counter {
- Counter::of(Self::elem())
+ Counter::of(HeadingElem::elem())
}
fn numbering(&self) -> Option<Numbering> {
- self.numbering(StyleChain::default()).clone()
+ (**self).numbering(StyleChain::default()).clone()
}
}
-impl Outlinable for HeadingElem {
+impl Outlinable for Packed<HeadingElem> {
fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> {
if !self.outlined(StyleChain::default()) {
return Ok(None);
}
let mut content = self.body().clone();
- let default = StyleChain::default();
- if let Some(numbering) = self.numbering(default).as_ref() {
- let numbers = Counter::of(Self::elem())
+ if let Some(numbering) = (**self).numbering(StyleChain::default()).as_ref() {
+ let numbers = Counter::of(HeadingElem::elem())
.at(engine, self.location().unwrap())?
.display(engine, numbering)?;
content = numbers + SpaceElem::new().pack() + content;
@@ -243,11 +234,11 @@ impl Outlinable for HeadingElem {
}
fn level(&self) -> NonZeroUsize {
- self.level(StyleChain::default())
+ (**self).level(StyleChain::default())
}
}
-impl LocalName for HeadingElem {
+impl LocalName for Packed<HeadingElem> {
fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Kapitull",
diff --git a/crates/typst/src/model/link.rs b/crates/typst/src/model/link.rs
index 7c68b711..7b39e90b 100644
--- a/crates/typst/src/model/link.rs
+++ b/crates/typst/src/model/link.rs
@@ -3,7 +3,7 @@ use ecow::{eco_format, EcoString};
use crate::diag::{At, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, Content, Label, NativeElement, Repr, Show, Smart, StyleChain,
+ cast, elem, Content, Label, Packed, Repr, Show, Smart, StyleChain,
};
use crate::introspection::Location;
use crate::layout::Position;
@@ -89,7 +89,7 @@ impl LinkElem {
}
}
-impl Show for LinkElem {
+impl Show for Packed<LinkElem> {
#[typst_macros::time(name = "link", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
let body = self.body().clone();
diff --git a/crates/typst/src/model/list.rs b/crates/typst/src/model/list.rs
index 4e02f60b..dc0312d2 100644
--- a/crates/typst/src/model/list.rs
+++ b/crates/typst/src/model/list.rs
@@ -1,8 +1,7 @@
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, Array, Content, Fold, Func, NativeElement, Smart, StyleChain,
- Value,
+ cast, elem, scope, Array, Content, Fold, Func, Packed, Smart, StyleChain, Value,
};
use crate::layout::{
Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment, Layout,
@@ -120,7 +119,7 @@ pub struct ListElem {
/// ]
/// ```
#[variadic]
- pub children: Vec<ListItem>,
+ pub children: Vec<Packed<ListItem>>,
/// The nesting depth.
#[internal]
@@ -134,7 +133,7 @@ impl ListElem {
type ListItem;
}
-impl Layout for ListElem {
+impl Layout for Packed<ListElem> {
#[typst_macros::time(name = "list", span = self.span())]
fn layout(
&self,
@@ -163,7 +162,8 @@ impl Layout for ListElem {
cells.push(Cell::from(Content::empty()));
cells.push(Cell::from(marker.clone()));
cells.push(Cell::from(Content::empty()));
- cells.push(Cell::from(item.body().clone().styled(Self::set_depth(Depth))));
+ cells
+ .push(Cell::from(item.body().clone().styled(ListElem::set_depth(Depth))));
}
let stroke = None;
@@ -194,7 +194,10 @@ pub struct ListItem {
cast! {
ListItem,
- v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())),
+ v: Content => match v.to_packed::<Self>() {
+ Ok(packed) => packed.unpack(),
+ Err(v) => Self::new(v),
+ }
}
/// A list's marker.
diff --git a/crates/typst/src/model/outline.rs b/crates/typst/src/model/outline.rs
index c77a9a98..833b035c 100644
--- a/crates/typst/src/model/outline.rs
+++ b/crates/typst/src/model/outline.rs
@@ -5,7 +5,7 @@ use crate::diag::{bail, At, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
cast, elem, scope, select_where, Content, Finalize, Func, LocatableSelector,
- NativeElement, Show, Smart, StyleChain,
+ NativeElement, Packed, Show, Smart, StyleChain,
};
use crate::introspection::{Counter, CounterKey, Locatable};
use crate::layout::{BoxElem, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing};
@@ -185,7 +185,7 @@ impl OutlineElem {
type OutlineEntry;
}
-impl Show for OutlineElem {
+impl Show for Packed<OutlineElem> {
#[typst_macros::time(name = "outline", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let mut seq = vec![ParbreakElem::new().pack()];
@@ -197,9 +197,9 @@ impl Show for OutlineElem {
seq.push(
HeadingElem::new(title)
- .spanned(self.span())
.with_level(NonZeroUsize::ONE)
- .pack(),
+ .pack()
+ .spanned(self.span()),
);
}
@@ -250,7 +250,7 @@ impl Show for OutlineElem {
}
}
-impl Finalize for OutlineElem {
+impl Finalize for Packed<OutlineElem> {
fn finalize(&self, realized: Content, _: StyleChain) -> Content {
realized
.styled(HeadingElem::set_outlined(false))
@@ -258,7 +258,7 @@ impl Finalize for OutlineElem {
}
}
-impl LocalName for OutlineElem {
+impl LocalName for Packed<OutlineElem> {
fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Përmbajtja",
@@ -492,7 +492,7 @@ impl OutlineEntry {
}
}
-impl Show for OutlineEntry {
+impl Show for Packed<OutlineEntry> {
#[typst_macros::time(name = "outline.entry", span = self.span())]
fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> {
let mut seq = vec![];
@@ -518,10 +518,10 @@ impl Show for OutlineEntry {
seq.push(SpaceElem::new().pack());
seq.push(
BoxElem::new()
- .spanned(self.span())
.with_body(Some(filler.clone()))
.with_width(Fr::one().into())
- .pack(),
+ .pack()
+ .spanned(self.span()),
);
seq.push(SpaceElem::new().pack());
} else {
diff --git a/crates/typst/src/model/par.rs b/crates/typst/src/model/par.rs
index f00c39f0..690b7276 100644
--- a/crates/typst/src/model/par.rs
+++ b/crates/typst/src/model/par.rs
@@ -3,7 +3,7 @@ use comemo::Prehashed;
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
- elem, Args, Cast, Construct, Content, NativeElement, Set, Smart, StyleChain,
+ elem, Args, Cast, Construct, Content, NativeElement, Packed, Set, Smart, StyleChain,
Unlabellable,
};
use crate::layout::{Em, Fragment, Length, Size};
@@ -122,7 +122,7 @@ impl Construct for ParElem {
}
}
-impl ParElem {
+impl Packed<ParElem> {
/// Layout the paragraph into a collection of lines.
#[typst_macros::time(name = "par", span = self.span())]
pub fn layout(
@@ -177,4 +177,4 @@ pub enum Linebreaks {
#[elem(title = "Paragraph Break", Unlabellable)]
pub struct ParbreakElem {}
-impl Unlabellable for ParbreakElem {}
+impl Unlabellable for Packed<ParbreakElem> {}
diff --git a/crates/typst/src/model/quote.rs b/crates/typst/src/model/quote.rs
index 920a2a97..311fd464 100644
--- a/crates/typst/src/model/quote.rs
+++ b/crates/typst/src/model/quote.rs
@@ -1,7 +1,7 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain,
+ cast, elem, Content, Finalize, Label, NativeElement, Packed, Show, Smart, StyleChain,
Synthesize,
};
use crate::layout::{Alignment, BlockElem, Em, HElem, PadElem, Spacing, VElem};
@@ -145,15 +145,16 @@ cast! {
label: Label => Self::Label(label),
}
-impl Synthesize for QuoteElem {
+impl Synthesize for Packed<QuoteElem> {
fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> {
- self.push_block(self.block(styles));
- self.push_quotes(self.quotes(styles));
+ let elem = self.as_mut();
+ elem.push_block(elem.block(styles));
+ elem.push_quotes(elem.quotes(styles));
Ok(())
}
}
-impl Show for QuoteElem {
+impl Show for Packed<QuoteElem> {
#[typst_macros::time(name = "quote", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let mut realized = self.body().clone();
@@ -169,7 +170,7 @@ impl Show for QuoteElem {
if block {
realized =
- BlockElem::new().spanned(self.span()).with_body(Some(realized)).pack();
+ BlockElem::new().with_body(Some(realized)).pack().spanned(self.span());
if let Some(attribution) = self.attribution(styles).as_ref() {
let mut seq = vec![TextElem::packed('—'), SpaceElem::new().pack()];
@@ -181,9 +182,9 @@ impl Show for QuoteElem {
Attribution::Label(label) => {
seq.push(
CiteElem::new(*label)
- .spanned(self.span())
.with_form(Some(CitationForm::Prose))
- .pack(),
+ .pack()
+ .spanned(self.span()),
);
}
}
@@ -197,14 +198,14 @@ impl Show for QuoteElem {
realized = PadElem::new(realized).pack();
} else if let Some(Attribution::Label(label)) = self.attribution(styles) {
realized += SpaceElem::new().pack()
- + CiteElem::new(*label).spanned(self.span()).pack();
+ + CiteElem::new(*label).pack().spanned(self.span());
}
Ok(realized)
}
}
-impl Finalize for QuoteElem {
+impl Finalize for Packed<QuoteElem> {
fn finalize(&self, realized: Content, _: StyleChain) -> Content {
let x = Em::new(1.0).into();
let above = Em::new(2.4).into();
diff --git a/crates/typst/src/model/reference.rs b/crates/typst/src/model/reference.rs
index 756c83fa..b96d0a53 100644
--- a/crates/typst/src/model/reference.rs
+++ b/crates/typst/src/model/reference.rs
@@ -3,8 +3,8 @@ use ecow::eco_format;
use crate::diag::{bail, At, Hint, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, Content, Func, IntoValue, Label, NativeElement, Show, Smart, StyleChain,
- Synthesize,
+ cast, elem, Content, Func, IntoValue, Label, NativeElement, Packed, Show, Smart,
+ StyleChain, Synthesize,
};
use crate::introspection::{Counter, Locatable};
use crate::math::EquationElem;
@@ -129,27 +129,29 @@ pub struct RefElem {
/// A synthesized citation.
#[synthesized]
- pub citation: Option<CiteElem>,
+ pub citation: Option<Packed<CiteElem>>,
/// The referenced element.
#[synthesized]
pub element: Option<Content>,
}
-impl Synthesize for RefElem {
+impl Synthesize for Packed<RefElem> {
fn synthesize(
&mut self,
engine: &mut Engine,
styles: StyleChain,
) -> SourceResult<()> {
- let citation = self.to_citation(engine, styles)?;
- self.push_citation(Some(citation));
- self.push_element(None);
+ let citation = to_citation(self, engine, styles)?;
- let target = *self.target();
+ let elem = self.as_mut();
+ elem.push_citation(Some(citation));
+ elem.push_element(None);
+
+ let target = *elem.target();
if !BibliographyElem::has(engine, target) {
- if let Ok(elem) = engine.introspector.query_label(target).cloned() {
- self.push_element(Some(elem.into_inner()));
+ if let Ok(found) = engine.introspector.query_label(target).cloned() {
+ elem.push_element(Some(found.into_inner()));
return Ok(());
}
}
@@ -158,7 +160,7 @@ impl Synthesize for RefElem {
}
}
-impl Show for RefElem {
+impl Show for Packed<RefElem> {
#[typst_macros::time(name = "ref", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
@@ -171,13 +173,13 @@ impl Show for RefElem {
bail!(span, "label occurs in the document and its bibliography");
}
- return Ok(self.to_citation(engine, styles)?.spanned(span).pack());
+ return Ok(to_citation(self, engine, styles)?.pack().spanned(span));
}
let elem = elem.at(span)?;
if elem.func() == FootnoteElem::elem() {
- return Ok(FootnoteElem::with_label(target).spanned(span).pack());
+ return Ok(FootnoteElem::with_label(target).pack().spanned(span));
}
let elem = elem.clone();
@@ -236,23 +238,23 @@ impl Show for RefElem {
}
}
-impl RefElem {
- /// Turn the reference into a citation.
- pub fn to_citation(
- &self,
- engine: &mut Engine,
- styles: StyleChain,
- ) -> SourceResult<CiteElem> {
- let mut elem = CiteElem::new(*self.target()).spanned(self.span());
- elem.set_location(self.location().unwrap());
- elem.synthesize(engine, styles)?;
- elem.push_supplement(match self.supplement(styles).clone() {
+/// Turn a reference into a citation.
+fn to_citation(
+ reference: &Packed<RefElem>,
+ engine: &mut Engine,
+ styles: StyleChain,
+) -> SourceResult<Packed<CiteElem>> {
+ let mut elem = Packed::new(CiteElem::new(*reference.target()).with_supplement(
+ match reference.supplement(styles).clone() {
Smart::Custom(Some(Supplement::Content(content))) => Some(content),
_ => None,
- });
+ },
+ ));
- Ok(elem)
- }
+ elem.synthesize(engine, styles)?;
+ elem.set_location(reference.location().unwrap());
+
+ Ok(elem)
}
/// Additional content for a reference.
diff --git a/crates/typst/src/model/strong.rs b/crates/typst/src/model/strong.rs
index f6d75fb5..95d1575a 100644
--- a/crates/typst/src/model/strong.rs
+++ b/crates/typst/src/model/strong.rs
@@ -1,6 +1,6 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, Show, StyleChain};
+use crate::foundations::{elem, Content, Packed, Show, StyleChain};
use crate::text::{TextElem, WeightDelta};
/// Strongly emphasizes content by increasing the font weight.
@@ -37,7 +37,7 @@ pub struct StrongElem {
pub body: Content,
}
-impl Show for StrongElem {
+impl Show for Packed<StrongElem> {
#[typst_macros::time(name = "strong", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self
diff --git a/crates/typst/src/model/table.rs b/crates/typst/src/model/table.rs
index 3055100f..b405bd9f 100644
--- a/crates/typst/src/model/table.rs
+++ b/crates/typst/src/model/table.rs
@@ -1,7 +1,7 @@
use crate::diag::SourceResult;
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, Content, Fold, NativeElement, Show, Smart, StyleChain,
+ cast, elem, scope, Content, Fold, NativeElement, Packed, Show, Smart, StyleChain,
};
use crate::layout::{
show_grid_cell, Abs, Alignment, Axes, Cell, CellGrid, Celled, Fragment, GridLayouter,
@@ -166,7 +166,7 @@ impl TableElem {
type TableCell;
}
-impl Layout for TableElem {
+impl Layout for Packed<TableElem> {
#[typst_macros::time(name = "table", span = self.span())]
fn layout(
&self,
@@ -202,7 +202,7 @@ impl Layout for TableElem {
}
}
-impl LocalName for TableElem {
+impl LocalName for Packed<TableElem> {
fn local_name(lang: Lang, _: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Tabel",
@@ -239,7 +239,7 @@ impl LocalName for TableElem {
}
}
-impl Figurable for TableElem {}
+impl Figurable for Packed<TableElem> {}
/// A cell in the table. Use this to either override table properties for a
/// particular cell, or in show rules to apply certain styles to multiple cells
@@ -315,7 +315,7 @@ impl ResolvableCell for TableCell {
}
}
-impl Show for TableCell {
+impl Show for Packed<TableCell> {
fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
show_grid_cell(self.body().clone(), self.inset(styles), self.align(styles))
}
@@ -323,9 +323,9 @@ impl Show for TableCell {
impl From<Content> for TableCell {
fn from(value: Content) -> Self {
- value
- .to::<Self>()
- .cloned()
- .unwrap_or_else(|| Self::new(value.clone()))
+ match value.to_packed::<Self>() {
+ Ok(packed) => packed.unpack(),
+ Err(v) => Self::new(v),
+ }
}
}
diff --git a/crates/typst/src/model/terms.rs b/crates/typst/src/model/terms.rs
index 53310f07..9fa7365b 100644
--- a/crates/typst/src/model/terms.rs
+++ b/crates/typst/src/model/terms.rs
@@ -1,7 +1,7 @@
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, scope, Array, Content, NativeElement, Smart, StyleChain,
+ cast, elem, scope, Array, Content, NativeElement, Packed, Smart, StyleChain,
};
use crate::layout::{
BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem,
@@ -98,7 +98,7 @@ pub struct TermsElem {
/// ) [/ #product: Born in #year.]
/// ```
#[variadic]
- pub children: Vec<TermItem>,
+ pub children: Vec<Packed<TermItem>>,
}
#[scope]
@@ -107,7 +107,7 @@ impl TermsElem {
type TermItem;
}
-impl Layout for TermsElem {
+impl Layout for Packed<TermsElem> {
#[typst_macros::time(name = "terms", span = self.span())]
fn layout(
&self,
@@ -166,5 +166,5 @@ cast! {
};
Self::new(term, description)
},
- v: Content => v.to::<Self>().cloned().ok_or("expected term item or array")?,
+ v: Content => v.to_packed::<Self>().map_err(|_| "expected term item or array")?.unpack(),
}
diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs
index a17f82bb..080b854f 100644
--- a/crates/typst/src/realize/mod.rs
+++ b/crates/typst/src/realize/mod.rs
@@ -13,8 +13,8 @@ use typed_arena::Arena;
use crate::diag::{bail, SourceResult};
use crate::engine::{Engine, Route};
use crate::foundations::{
- Behave, Behaviour, Content, Finalize, Guard, NativeElement, Recipe, Selector, Show,
- StyleChain, StyleVec, StyleVecBuilder, Styles, Synthesize,
+ Behave, Behaviour, Content, Finalize, Guard, NativeElement, Packed, Recipe, Selector,
+ Show, StyleChain, StyleVec, StyleVecBuilder, Styles, Synthesize,
};
use crate::introspection::{Locatable, Meta, MetaElem};
use crate::layout::{
@@ -51,7 +51,7 @@ pub fn realize_root<'a>(
builder.interrupt_page(Some(styles), true)?;
let (pages, shared) = builder.doc.unwrap().pages.finish();
let span = first_span(&pages);
- Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).spanned(span).pack()), shared))
+ Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack().spanned(span)), shared))
}
/// Realize into an element that is capable of block-level layout.
@@ -86,7 +86,7 @@ pub fn realize_block<'a>(
let (children, shared) = builder.flow.0.finish();
let span = first_span(&children);
- Ok((Cow::Owned(FlowElem::new(children.to_vec()).spanned(span).pack()), shared))
+ Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack().spanned(span)), shared))
}
/// Whether the target is affected by show rules in the given style chain.
@@ -137,7 +137,7 @@ pub fn realize(
let span = elem.span();
let meta = Meta::Elem(elem.clone());
return Ok(Some(
- (elem + MetaElem::new().spanned(span).pack())
+ (elem + MetaElem::new().pack().spanned(span))
.styled(MetaElem::set_data(smallvec![meta])),
));
}
@@ -307,7 +307,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
content = self
.scratch
.content
- .alloc(EquationElem::new(content.clone()).spanned(content.span()).pack());
+ .alloc(EquationElem::new(content.clone()).pack().spanned(content.span()));
}
if let Some(realized) = realize(self.engine, content, styles)? {
@@ -482,9 +482,9 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
shared
};
let span = first_span(&children);
- let flow = FlowElem::new(children.to_vec()).spanned(span);
- let page = PageElem::new(flow.pack()).spanned(span);
- let stored = self.scratch.content.alloc(page.pack());
+ let flow = FlowElem::new(children.to_vec());
+ let page = PageElem::new(flow.pack().spanned(span));
+ let stored = self.scratch.content.alloc(page.pack().spanned(span));
self.accept(stored, styles)?;
}
Ok(())
@@ -622,7 +622,7 @@ impl<'a> ParBuilder<'a> {
fn finish(self) -> (Content, StyleChain<'a>) {
let (children, shared) = self.0.finish();
let span = first_span(&children);
- (ParElem::new(children.to_vec()).spanned(span).pack(), shared)
+ (ParElem::new(children.to_vec()).pack().spanned(span), shared)
}
}
@@ -671,46 +671,49 @@ impl<'a> ListBuilder<'a> {
items
.iter()
.map(|(item, local)| {
- let item = item.to::<ListItem>().unwrap();
- item.clone()
- .with_body(item.body().clone().styled_with_map(local.clone()))
+ let mut item = item.to::<ListItem>().unwrap().clone();
+ let body = item.body().clone().styled_with_map(local.clone());
+ item.push_body(body);
+ item
})
.collect::<Vec<_>>(),
)
.with_tight(self.tight)
- .spanned(span)
.pack()
+ .spanned(span)
} else if item.is::<EnumItem>() {
EnumElem::new(
items
.iter()
.map(|(item, local)| {
- let item = item.to::<EnumItem>().unwrap();
- item.clone()
- .with_body(item.body().clone().styled_with_map(local.clone()))
+ let mut item = item.to::<EnumItem>().unwrap().clone();
+ let body = item.body().clone().styled_with_map(local.clone());
+ item.push_body(body);
+ item
})
.collect::<Vec<_>>(),
)
.with_tight(self.tight)
- .spanned(span)
.pack()
+ .spanned(span)
} else if item.is::<TermItem>() {
TermsElem::new(
items
.iter()
.map(|(item, local)| {
- let item = item.to::<TermItem>().unwrap();
- item.clone()
- .with_term(item.term().clone().styled_with_map(local.clone()))
- .with_description(
- item.description().clone().styled_with_map(local.clone()),
- )
+ let mut item = item.to::<TermItem>().unwrap().clone();
+ let term = item.term().clone().styled_with_map(local.clone());
+ let description =
+ item.description().clone().styled_with_map(local.clone());
+ item.push_term(term);
+ item.push_description(description);
+ item
})
.collect::<Vec<_>>(),
)
.with_tight(self.tight)
- .spanned(span)
.pack()
+ .spanned(span)
} else {
unreachable!()
};
@@ -734,7 +737,7 @@ struct CiteGroupBuilder<'a> {
/// The styles.
styles: StyleChain<'a>,
/// The citations.
- items: Vec<CiteElem>,
+ items: Vec<Packed<CiteElem>>,
/// Trailing content for which it is unclear whether it is part of the list.
staged: Vec<(&'a Content, StyleChain<'a>)>,
}
@@ -762,7 +765,7 @@ impl<'a> CiteGroupBuilder<'a> {
fn finish(self) -> (Content, StyleChain<'a>) {
let span = self.items.first().map(|cite| cite.span()).unwrap_or(Span::detached());
- (CiteGroup::new(self.items).spanned(span).pack(), self.styles)
+ (CiteGroup::new(self.items).pack().spanned(span), self.styles)
}
}
diff --git a/crates/typst/src/text/deco.rs b/crates/typst/src/text/deco.rs
index 0968782e..3872334d 100644
--- a/crates/typst/src/text/deco.rs
+++ b/crates/typst/src/text/deco.rs
@@ -5,7 +5,9 @@ use ecow::{eco_format, EcoString};
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, ty, Content, Fold, Repr, Show, Smart, StyleChain};
+use crate::foundations::{
+ elem, ty, Content, Fold, Packed, Repr, Show, Smart, StyleChain,
+};
use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size};
use crate::syntax::Span;
use crate::text::{
@@ -84,7 +86,7 @@ pub struct UnderlineElem {
pub body: Content,
}
-impl Show for UnderlineElem {
+impl Show for Packed<UnderlineElem> {
#[typst_macros::time(name = "underline", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
@@ -176,7 +178,7 @@ pub struct OverlineElem {
pub body: Content,
}
-impl Show for OverlineElem {
+impl Show for Packed<OverlineElem> {
#[typst_macros::time(name = "overline", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
@@ -253,7 +255,7 @@ pub struct StrikeElem {
pub body: Content,
}
-impl Show for StrikeElem {
+impl Show for Packed<StrikeElem> {
#[typst_macros::time(name = "strike", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
@@ -323,7 +325,7 @@ pub struct HighlightElem {
pub body: Content,
}
-impl Show for HighlightElem {
+impl Show for Packed<HighlightElem> {
#[typst_macros::time(name = "highlight", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone().styled(TextElem::set_deco(Decoration {
diff --git a/crates/typst/src/text/linebreak.rs b/crates/typst/src/text/linebreak.rs
index d9802942..2bc315a3 100644
--- a/crates/typst/src/text/linebreak.rs
+++ b/crates/typst/src/text/linebreak.rs
@@ -1,4 +1,4 @@
-use crate::foundations::{elem, Behave, Behaviour};
+use crate::foundations::{elem, Behave, Behaviour, Packed};
/// Inserts a line break.
///
@@ -36,7 +36,7 @@ pub struct LinebreakElem {
pub justify: bool,
}
-impl Behave for LinebreakElem {
+impl Behave for Packed<LinebreakElem> {
fn behaviour(&self) -> Behaviour {
Behaviour::Destructive
}
diff --git a/crates/typst/src/text/mod.rs b/crates/typst/src/text/mod.rs
index 06e347a3..01d93feb 100644
--- a/crates/typst/src/text/mod.rs
+++ b/crates/typst/src/text/mod.rs
@@ -36,6 +36,7 @@ use ttf_parser::Rect;
use crate::diag::{bail, SourceResult, StrResult};
use crate::engine::Engine;
+use crate::foundations::Packed;
use crate::foundations::{
cast, category, elem, Args, Array, Cast, Category, Construct, Content, Dict, Fold,
NativeElement, Never, PlainText, Repr, Resolve, Scope, Set, Smart, StyleChain, Value,
@@ -673,7 +674,7 @@ impl Construct for TextElem {
}
}
-impl PlainText for TextElem {
+impl PlainText for Packed<TextElem> {
fn plain_text(&self, text: &mut EcoString) {
text.push_str(self.text());
}
diff --git a/crates/typst/src/text/raw.rs b/crates/typst/src/text/raw.rs
index fc5d8129..b032f666 100644
--- a/crates/typst/src/text/raw.rs
+++ b/crates/typst/src/text/raw.rs
@@ -13,7 +13,7 @@ use crate::diag::{At, FileError, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
cast, elem, scope, Args, Array, Bytes, Content, Finalize, Fold, NativeElement,
- PlainText, Show, Smart, StyleChain, Styles, Synthesize, Value,
+ Packed, PlainText, Show, Smart, StyleChain, Styles, Synthesize, Value,
};
use crate::layout::{BlockElem, Em, HAlignment};
use crate::model::Figurable;
@@ -261,7 +261,7 @@ pub struct RawElem {
/// Made accessible for the [`raw.line` element]($raw.line).
/// Allows more styling control in `show` rules.
#[synthesized]
- pub lines: Vec<RawLine>,
+ pub lines: Vec<Packed<RawLine>>,
}
#[scope]
@@ -287,11 +287,15 @@ impl RawElem {
}
}
-impl Synthesize for RawElem {
+impl Synthesize for Packed<RawElem> {
fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> {
- self.push_lang(self.lang(styles).clone());
+ let span = self.span();
+ let elem = self.as_mut();
- let mut text = self.text().clone();
+ let lang = elem.lang(styles).clone();
+ elem.push_lang(lang);
+
+ let mut text = elem.text().clone();
if text.contains('\t') {
let tab_size = RawElem::tab_size_in(styles);
text = align_tabs(&text, tab_size);
@@ -300,7 +304,7 @@ impl Synthesize for RawElem {
let lines = split_newlines(&text);
let count = lines.len() as i64;
- let lang = self
+ let lang = elem
.lang(styles)
.as_ref()
.as_ref()
@@ -308,11 +312,11 @@ impl Synthesize for RawElem {
.or(Some("txt".into()));
let extra_syntaxes = UnsyncLazy::new(|| {
- load_syntaxes(&self.syntaxes(styles), &self.syntaxes_data(styles)).unwrap()
+ load_syntaxes(&elem.syntaxes(styles), &elem.syntaxes_data(styles)).unwrap()
});
- let theme = self.theme(styles).as_ref().as_ref().map(|theme_path| {
- load_theme(theme_path, self.theme_data(styles).as_ref().as_ref().unwrap())
+ let theme = elem.theme(styles).as_ref().as_ref().map(|theme_path| {
+ load_theme(theme_path, elem.theme_data(styles).as_ref().as_ref().unwrap())
.unwrap()
});
@@ -333,13 +337,13 @@ impl Synthesize for RawElem {
&mut |_, range, style| styled(&text[range], foreground, style),
&mut |i, range, line| {
seq.push(
- RawLine::new(
+ Packed::new(RawLine::new(
i + 1,
count,
EcoString::from(&text[range]),
Content::sequence(line.drain(..)),
- )
- .spanned(self.span()),
+ ))
+ .spanned(span),
);
},
)
@@ -364,34 +368,34 @@ impl Synthesize for RawElem {
}
seq.push(
- RawLine::new(
+ Packed::new(RawLine::new(
i as i64 + 1,
count,
EcoString::from(line),
Content::sequence(line_content),
- )
- .spanned(self.span()),
+ ))
+ .spanned(span),
);
}
} else {
seq.extend(lines.into_iter().enumerate().map(|(i, line)| {
- RawLine::new(
+ Packed::new(RawLine::new(
i as i64 + 1,
count,
EcoString::from(line),
TextElem::packed(line),
- )
- .spanned(self.span())
+ ))
+ .spanned(span)
}));
};
- self.push_lines(seq);
+ elem.push_lines(seq);
Ok(())
}
}
-impl Show for RawElem {
+impl Show for Packed<RawElem> {
#[typst_macros::time(name = "raw", span = self.span())]
fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let mut lines = EcoVec::with_capacity((2 * self.lines().len()).saturating_sub(1));
@@ -408,14 +412,14 @@ impl Show for RawElem {
// Align the text before inserting it into the block.
realized = realized.aligned(self.align(styles).into());
realized =
- BlockElem::new().spanned(self.span()).with_body(Some(realized)).pack();
+ BlockElem::new().with_body(Some(realized)).pack().spanned(self.span());
}
Ok(realized)
}
}
-impl Finalize for RawElem {
+impl Finalize for Packed<RawElem> {
fn finalize(&self, realized: Content, _: StyleChain) -> Content {
let mut styles = Styles::new();
styles.set(TextElem::set_overhang(false));
@@ -428,7 +432,7 @@ impl Finalize for RawElem {
}
}
-impl LocalName for RawElem {
+impl LocalName for Packed<RawElem> {
fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "List",
@@ -464,9 +468,9 @@ impl LocalName for RawElem {
}
}
-impl Figurable for RawElem {}
+impl Figurable for Packed<RawElem> {}
-impl PlainText for RawElem {
+impl PlainText for Packed<RawElem> {
fn plain_text(&self, text: &mut EcoString) {
text.push_str(self.text());
}
@@ -498,14 +502,14 @@ pub struct RawLine {
pub body: Content,
}
-impl Show for RawLine {
+impl Show for Packed<RawLine> {
#[typst_macros::time(name = "raw.line", span = self.span())]
fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> {
Ok(self.body().clone())
}
}
-impl PlainText for RawLine {
+impl PlainText for Packed<RawLine> {
fn plain_text(&self, text: &mut EcoString) {
text.push_str(self.text());
}
diff --git a/crates/typst/src/text/shift.rs b/crates/typst/src/text/shift.rs
index 47a186fe..46ef703e 100644
--- a/crates/typst/src/text/shift.rs
+++ b/crates/typst/src/text/shift.rs
@@ -2,7 +2,7 @@ use ecow::EcoString;
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, Show, StyleChain};
+use crate::foundations::{elem, Content, Packed, Show, StyleChain};
use crate::layout::{Em, Length};
use crate::text::{variant, SpaceElem, TextElem, TextSize};
use crate::World;
@@ -47,7 +47,7 @@ pub struct SubElem {
pub body: Content,
}
-impl Show for SubElem {
+impl Show for Packed<SubElem> {
#[typst_macros::time(name = "sub", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let body = self.body().clone();
@@ -107,7 +107,7 @@ pub struct SuperElem {
pub body: Content,
}
-impl Show for SuperElem {
+impl Show for Packed<SuperElem> {
#[typst_macros::time(name = "super", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
let body = self.body().clone();
diff --git a/crates/typst/src/text/space.rs b/crates/typst/src/text/space.rs
index f790ee61..e584d948 100644
--- a/crates/typst/src/text/space.rs
+++ b/crates/typst/src/text/space.rs
@@ -1,4 +1,6 @@
-use crate::foundations::{elem, Behave, Behaviour, PlainText, Repr, Unlabellable};
+use crate::foundations::{
+ elem, Behave, Behaviour, Packed, PlainText, Repr, Unlabellable,
+};
use ecow::EcoString;
/// A text space.
@@ -11,15 +13,15 @@ impl Repr for SpaceElem {
}
}
-impl Behave for SpaceElem {
+impl Behave for Packed<SpaceElem> {
fn behaviour(&self) -> Behaviour {
Behaviour::Weak(2)
}
}
-impl Unlabellable for SpaceElem {}
+impl Unlabellable for Packed<SpaceElem> {}
-impl PlainText for SpaceElem {
+impl PlainText for Packed<SpaceElem> {
fn plain_text(&self, text: &mut EcoString) {
text.push(' ');
}
diff --git a/crates/typst/src/visualize/image/mod.rs b/crates/typst/src/visualize/image/mod.rs
index 0f4d59cc..15f9276f 100644
--- a/crates/typst/src/visualize/image/mod.rs
+++ b/crates/typst/src/visualize/image/mod.rs
@@ -16,7 +16,7 @@ use ecow::EcoString;
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, elem, func, scope, Bytes, Cast, Content, NativeElement, Resolve, Smart,
+ cast, elem, func, scope, Bytes, Cast, Content, NativeElement, Packed, Resolve, Smart,
StyleChain,
};
use crate::layout::{
@@ -124,7 +124,7 @@ impl ImageElem {
#[named]
fit: Option<ImageFit>,
) -> StrResult<Content> {
- let mut elem = ImageElem::new(EcoString::new(), data).spanned(span);
+ let mut elem = ImageElem::new(EcoString::new(), data);
if let Some(format) = format {
elem.push_format(format);
}
@@ -140,11 +140,11 @@ impl ImageElem {
if let Some(fit) = fit {
elem.push_fit(fit);
}
- Ok(elem.pack())
+ Ok(elem.pack().spanned(span))
}
}
-impl Layout for ImageElem {
+impl Layout for Packed<ImageElem> {
#[typst_macros::time(name = "image", span = self.span())]
fn layout(
&self,
@@ -247,7 +247,7 @@ impl Layout for ImageElem {
}
}
-impl LocalName for ImageElem {
+impl LocalName for Packed<ImageElem> {
fn local_name(lang: Lang, region: Option<Region>) -> &'static str {
match lang {
Lang::ALBANIAN => "Figurë",
@@ -285,7 +285,7 @@ impl LocalName for ImageElem {
}
}
-impl Figurable for ImageElem {}
+impl Figurable for Packed<ImageElem> {}
/// How an image should adjust itself to a given area.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
diff --git a/crates/typst/src/visualize/line.rs b/crates/typst/src/visualize/line.rs
index 94841d39..0c883500 100644
--- a/crates/typst/src/visualize/line.rs
+++ b/crates/typst/src/visualize/line.rs
@@ -1,6 +1,6 @@
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
-use crate::foundations::{elem, NativeElement, StyleChain};
+use crate::foundations::{elem, Packed, StyleChain};
use crate::layout::{
Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size,
};
@@ -58,7 +58,7 @@ pub struct LineElem {
pub stroke: Stroke,
}
-impl Layout for LineElem {
+impl Layout for Packed<LineElem> {
#[typst_macros::time(name = "line", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/visualize/path.rs b/crates/typst/src/visualize/path.rs
index 8b80f870..23be1d27 100644
--- a/crates/typst/src/visualize/path.rs
+++ b/crates/typst/src/visualize/path.rs
@@ -3,7 +3,7 @@ use kurbo::{CubicBez, ParamCurveExtrema};
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- array, cast, elem, Array, NativeElement, Reflect, Resolve, Smart, StyleChain,
+ array, cast, elem, Array, Packed, Reflect, Resolve, Smart, StyleChain,
};
use crate::layout::{
Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size,
@@ -70,7 +70,7 @@ pub struct PathElem {
pub vertices: Vec<PathVertex>,
}
-impl Layout for PathElem {
+impl Layout for Packed<PathElem> {
#[typst_macros::time(name = "path", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/visualize/polygon.rs b/crates/typst/src/visualize/polygon.rs
index 3b686f79..1f6dce44 100644
--- a/crates/typst/src/visualize/polygon.rs
+++ b/crates/typst/src/visualize/polygon.rs
@@ -3,7 +3,7 @@ use std::f64::consts::PI;
use crate::diag::{bail, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
- elem, func, scope, Content, NativeElement, Resolve, Smart, StyleChain,
+ elem, func, scope, Content, NativeElement, Packed, Resolve, Smart, StyleChain,
};
use crate::layout::{
Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel,
@@ -114,18 +114,18 @@ impl PolygonElem {
})
.collect();
- let mut elem = PolygonElem::new(vertices).spanned(span);
+ let mut elem = PolygonElem::new(vertices);
if let Some(fill) = fill {
elem.push_fill(fill);
}
if let Some(stroke) = stroke {
elem.push_stroke(stroke);
}
- elem.pack()
+ elem.pack().spanned(span)
}
}
-impl Layout for PolygonElem {
+impl Layout for Packed<PolygonElem> {
#[typst_macros::time(name = "polygon", span = self.span())]
fn layout(
&self,
diff --git a/crates/typst/src/visualize/shape.rs b/crates/typst/src/visualize/shape.rs
index f378d363..b8938d3b 100644
--- a/crates/typst/src/visualize/shape.rs
+++ b/crates/typst/src/visualize/shape.rs
@@ -2,7 +2,7 @@ use std::f64::consts::SQRT_2;
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain};
+use crate::foundations::{elem, Content, Packed, Resolve, Smart, StyleChain};
use crate::layout::{
Abs, Axes, Corner, Corners, Fragment, Frame, FrameItem, Layout, Length, Point, Ratio,
Regions, Rel, Sides, Size,
@@ -131,7 +131,7 @@ pub struct RectElem {
pub body: Option<Content>,
}
-impl Layout for RectElem {
+impl Layout for Packed<RectElem> {
#[typst_macros::time(name = "rect", span = self.span())]
fn layout(
&self,
@@ -237,7 +237,7 @@ pub struct SquareElem {
pub body: Option<Content>,
}
-impl Layout for SquareElem {
+impl Layout for Packed<SquareElem> {
#[typst_macros::time(name = "square", span = self.span())]
fn layout(
&self,
@@ -315,7 +315,7 @@ pub struct EllipseElem {
pub body: Option<Content>,
}
-impl Layout for EllipseElem {
+impl Layout for Packed<EllipseElem> {
#[typst_macros::time(name = "ellipse", span = self.span())]
fn layout(
&self,
@@ -418,7 +418,7 @@ pub struct CircleElem {
pub body: Option<Content>,
}
-impl Layout for CircleElem {
+impl Layout for Packed<CircleElem> {
#[typst_macros::time(name = "circle", span = self.span())]
fn layout(
&self,