summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-01-12 14:36:41 +0100
committerLaurenz <laurmaedje@gmail.com>2024-01-12 14:43:42 +0100
commit37249c20f793689b523cbb379f30b37466ca51b9 (patch)
treee1af42115de7685c43eee109d7f86ef0e69979e6
parent1834ebc52918754dee51afffd8b55e82613eb687 (diff)
Autogenerate default cast in`#[ty]` unless `cast` is specified
-rw-r--r--crates/typst-macros/src/lib.rs2
-rw-r--r--crates/typst-macros/src/ty.rs34
-rw-r--r--crates/typst-macros/src/util.rs1
-rw-r--r--crates/typst/src/foundations/args.rs2
-rw-r--r--crates/typst/src/foundations/array.rs2
-rw-r--r--crates/typst/src/foundations/auto.rs2
-rw-r--r--crates/typst/src/foundations/bool.rs2
-rw-r--r--crates/typst/src/foundations/bytes.rs2
-rw-r--r--crates/typst/src/foundations/content.rs2
-rw-r--r--crates/typst/src/foundations/datetime.rs2
-rw-r--r--crates/typst/src/foundations/dict.rs2
-rw-r--r--crates/typst/src/foundations/duration.rs2
-rw-r--r--crates/typst/src/foundations/float.rs2
-rw-r--r--crates/typst/src/foundations/func.rs2
-rw-r--r--crates/typst/src/foundations/int.rs2
-rw-r--r--crates/typst/src/foundations/label.rs2
-rw-r--r--crates/typst/src/foundations/module.rs2
-rw-r--r--crates/typst/src/foundations/none.rs2
-rw-r--r--crates/typst/src/foundations/plugin.rs2
-rw-r--r--crates/typst/src/foundations/selector.rs2
-rw-r--r--crates/typst/src/foundations/str.rs6
-rw-r--r--crates/typst/src/foundations/styles.rs2
-rw-r--r--crates/typst/src/foundations/ty.rs2
-rw-r--r--crates/typst/src/foundations/version.rs2
-rw-r--r--crates/typst/src/introspection/counter.rs6
-rw-r--r--crates/typst/src/introspection/location.rs6
-rw-r--r--crates/typst/src/introspection/mod.rs7
-rw-r--r--crates/typst/src/introspection/state.rs6
-rw-r--r--crates/typst/src/layout/align.rs4
-rw-r--r--crates/typst/src/layout/angle.rs2
-rw-r--r--crates/typst/src/layout/dir.rs6
-rw-r--r--crates/typst/src/layout/fr.rs2
-rw-r--r--crates/typst/src/layout/length.rs2
-rw-r--r--crates/typst/src/layout/ratio.rs2
-rw-r--r--crates/typst/src/layout/rel.rs2
-rw-r--r--crates/typst/src/model/bibliography.rs6
-rw-r--r--crates/typst/src/symbols/symbol.rs2
-rw-r--r--crates/typst/src/text/deco.rs6
-rw-r--r--crates/typst/src/visualize/color.rs2
-rw-r--r--crates/typst/src/visualize/gradient.rs2
-rw-r--r--crates/typst/src/visualize/pattern.rs2
-rw-r--r--crates/typst/src/visualize/stroke.rs2
42 files changed, 58 insertions, 92 deletions
diff --git a/crates/typst-macros/src/lib.rs b/crates/typst-macros/src/lib.rs
index 8ca7bcac..a9185a9b 100644
--- a/crates/typst-macros/src/lib.rs
+++ b/crates/typst-macros/src/lib.rs
@@ -116,6 +116,8 @@ pub fn func(stream: BoundaryStream, item: BoundaryStream) -> BoundaryStream {
/// You can customize some properties of the resulting type:
/// - `scope`: Indicates that the type has an associated scope defined by the
/// `#[scope]` macro
+/// - `cast`: Indicates that the type has a custom `cast!` implementation.
+/// The macro will then not autogenerate one.
/// - `name`: The type's normal name (e.g. `str`). Defaults to the Rust name in
/// kebab-case.
/// - `title`: The type's title case name (e.g. `String`). Defaults to the
diff --git a/crates/typst-macros/src/ty.rs b/crates/typst-macros/src/ty.rs
index 23f818bd..943bd453 100644
--- a/crates/typst-macros/src/ty.rs
+++ b/crates/typst-macros/src/ty.rs
@@ -28,18 +28,18 @@ pub fn ty(stream: TokenStream, item: syn::Item) -> Result<TokenStream> {
/// Holds all relevant parsed data about a type.
struct Type {
+ meta: Meta,
ident: Ident,
name: String,
long: String,
- scope: bool,
title: String,
docs: String,
- keywords: Vec<String>,
}
/// The `..` in `#[ty(..)]`.
struct Meta {
scope: bool,
+ cast: bool,
name: Option<String>,
title: Option<String>,
keywords: Vec<String>,
@@ -49,6 +49,7 @@ impl Parse for Meta {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
scope: parse_flag::<kw::scope>(input)?,
+ cast: parse_flag::<kw::cast>(input)?,
name: parse_string::<kw::name>(input)?,
title: parse_string::<kw::title>(input)?,
keywords: parse_string_array::<kw::keywords>(input)?,
@@ -59,37 +60,35 @@ impl Parse for Meta {
/// Parse details about the type from its definition.
fn parse(meta: Meta, ident: Ident, attrs: &[Attribute]) -> Result<Type> {
let docs = documentation(attrs);
- let (name, title) = determine_name_and_title(meta.name, meta.title, &ident, None)?;
+ let (name, title) =
+ determine_name_and_title(meta.name.clone(), meta.title.clone(), &ident, None)?;
let long = title.to_lowercase();
- Ok(Type {
- ident,
- name,
- long,
- scope: meta.scope,
- keywords: meta.keywords,
- title,
- docs,
- })
+ Ok(Type { meta, ident, name, long, title, docs })
}
/// Produce the output of the macro.
fn create(ty: &Type, item: Option<&syn::Item>) -> TokenStream {
- let Type {
- ident, name, long, title, docs, keywords, scope, ..
- } = ty;
+ let Type { ident, name, long, title, docs, meta, .. } = ty;
+ let Meta { keywords, .. } = meta;
- let constructor = if *scope {
+ let constructor = if meta.scope {
quote! { <#ident as #foundations::NativeScope>::constructor() }
} else {
quote! { None }
};
- let scope = if *scope {
+ let scope = if meta.scope {
quote! { <#ident as #foundations::NativeScope>::scope() }
} else {
quote! { #foundations::Scope::new() }
};
+ let cast = (!meta.cast).then(|| {
+ quote! {
+ #foundations::cast! { type #ident, }
+ }
+ });
+
let data = quote! {
#foundations::NativeTypeData {
name: #name,
@@ -104,6 +103,7 @@ fn create(ty: &Type, item: Option<&syn::Item>) -> TokenStream {
quote! {
#item
+ #cast
impl #foundations::NativeType for #ident {
const NAME: &'static str = #name;
diff --git a/crates/typst-macros/src/util.rs b/crates/typst-macros/src/util.rs
index 4f7cc5fb..89880db1 100644
--- a/crates/typst-macros/src/util.rs
+++ b/crates/typst-macros/src/util.rs
@@ -255,6 +255,7 @@ pub mod kw {
syn::custom_keyword!(span);
syn::custom_keyword!(title);
syn::custom_keyword!(scope);
+ syn::custom_keyword!(cast);
syn::custom_keyword!(constructor);
syn::custom_keyword!(keywords);
syn::custom_keyword!(parent);
diff --git a/crates/typst/src/foundations/args.rs b/crates/typst/src/foundations/args.rs
index 01cf6d7f..54811437 100644
--- a/crates/typst/src/foundations/args.rs
+++ b/crates/typst/src/foundations/args.rs
@@ -38,7 +38,7 @@ use crate::syntax::{Span, Spanned};
/// #let dict = (fill: blue)
/// #text(..dict)[Hello]
/// ```
-#[ty(scope, name = "arguments")]
+#[ty(scope, cast, name = "arguments")]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Args {
diff --git a/crates/typst/src/foundations/array.rs b/crates/typst/src/foundations/array.rs
index 86d4c2ac..6f7c6347 100644
--- a/crates/typst/src/foundations/array.rs
+++ b/crates/typst/src/foundations/array.rs
@@ -67,7 +67,7 @@ pub use crate::__array as array;
/// #(("A", "B", "C")
/// .join(", ", last: " and "))
/// ```
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Default, Clone, PartialEq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Array(EcoVec<Value>);
diff --git a/crates/typst/src/foundations/auto.rs b/crates/typst/src/foundations/auto.rs
index 5cb03f7f..fcd72999 100644
--- a/crates/typst/src/foundations/auto.rs
+++ b/crates/typst/src/foundations/auto.rs
@@ -15,7 +15,7 @@ use crate::foundations::{
/// contextual behaviour. A good example is the [text direction]($text.dir)
/// parameter. Setting it to `{auto}` lets Typst automatically determine the
/// direction from the [text language]($text.lang).
-#[ty(name = "auto")]
+#[ty(cast, name = "auto")]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AutoValue;
diff --git a/crates/typst/src/foundations/bool.rs b/crates/typst/src/foundations/bool.rs
index 4c85a741..e88c8c6f 100644
--- a/crates/typst/src/foundations/bool.rs
+++ b/crates/typst/src/foundations/bool.rs
@@ -13,7 +13,7 @@ use crate::foundations::{ty, Repr};
/// #true \
/// #(1 < 2)
/// ```
-#[ty(title = "Boolean")]
+#[ty(cast, title = "Boolean")]
type bool;
impl Repr for bool {
diff --git a/crates/typst/src/foundations/bytes.rs b/crates/typst/src/foundations/bytes.rs
index 4e894241..b2fd0e3b 100644
--- a/crates/typst/src/foundations/bytes.rs
+++ b/crates/typst/src/foundations/bytes.rs
@@ -37,7 +37,7 @@ use crate::foundations::{cast, func, scope, ty, Array, Reflect, Repr, Str, Value
/// #array(data.slice(0, 4)) \
/// #str(data.slice(1, 4))
/// ```
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>);
diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs
index 3d40c703..e498c8cb 100644
--- a/crates/typst/src/foundations/content.rs
+++ b/crates/typst/src/foundations/content.rs
@@ -65,7 +65,7 @@ use crate::util::fat;
/// In the web app, you can hover over a content variable to see exactly which
/// elements the content is composed of and what fields they have.
/// Alternatively, you can inspect the output of the [`repr`]($repr) function.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Content(Arc<dyn NativeElement>);
diff --git a/crates/typst/src/foundations/datetime.rs b/crates/typst/src/foundations/datetime.rs
index 78290c99..28a0d177 100644
--- a/crates/typst/src/foundations/datetime.rs
+++ b/crates/typst/src/foundations/datetime.rs
@@ -111,7 +111,7 @@ use crate::World;
/// will be stored as a plain date internally, meaning that you cannot use
/// components such as `hour` or `minute`, which would only work on datetimes
/// that have a specified time.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum Datetime {
/// Representation as a date.
diff --git a/crates/typst/src/foundations/dict.rs b/crates/typst/src/foundations/dict.rs
index b43c5428..f072a619 100644
--- a/crates/typst/src/foundations/dict.rs
+++ b/crates/typst/src/foundations/dict.rs
@@ -62,7 +62,7 @@ pub use crate::__dict as dict;
/// #dict.insert("city", "Berlin ")
/// #("name" in dict)
/// ```
-#[ty(scope, name = "dictionary")]
+#[ty(scope, cast, name = "dictionary")]
#[derive(Default, Clone, PartialEq)]
pub struct Dict(Arc<IndexMap<Str, Value>>);
diff --git a/crates/typst/src/foundations/duration.rs b/crates/typst/src/foundations/duration.rs
index b6a48f3b..83e3d962 100644
--- a/crates/typst/src/foundations/duration.rs
+++ b/crates/typst/src/foundations/duration.rs
@@ -7,7 +7,7 @@ use time::ext::NumericalDuration;
use crate::foundations::{func, repr, scope, ty, Repr};
/// Represents a positive or negative span of time.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Duration(time::Duration);
diff --git a/crates/typst/src/foundations/float.rs b/crates/typst/src/foundations/float.rs
index 6bcebda8..723e023b 100644
--- a/crates/typst/src/foundations/float.rs
+++ b/crates/typst/src/foundations/float.rs
@@ -19,7 +19,7 @@ use crate::layout::Ratio;
/// #1e4 \
/// #(10 / 4)
/// ```
-#[ty(scope, name = "float")]
+#[ty(scope, cast, name = "float")]
type f64;
#[scope]
diff --git a/crates/typst/src/foundations/func.rs b/crates/typst/src/foundations/func.rs
index 22a20fdb..70d0ec31 100644
--- a/crates/typst/src/foundations/func.rs
+++ b/crates/typst/src/foundations/func.rs
@@ -123,7 +123,7 @@ pub use typst_macros::func;
/// The only exception are built-in methods like
/// [`array.push(value)`]($array.push). These can modify the values they are
/// called on.
-#[ty(scope, name = "function")]
+#[ty(scope, cast, name = "function")]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Func {
diff --git a/crates/typst/src/foundations/int.rs b/crates/typst/src/foundations/int.rs
index 602cdd5a..9fffadbf 100644
--- a/crates/typst/src/foundations/int.rs
+++ b/crates/typst/src/foundations/int.rs
@@ -25,7 +25,7 @@ use crate::foundations::{cast, func, repr, scope, ty, Repr, Str, Value};
/// #0o10 \
/// #0b1001
/// ```
-#[ty(scope, name = "int", title = "Integer")]
+#[ty(scope, cast, name = "int", title = "Integer")]
type i64;
#[scope]
diff --git a/crates/typst/src/foundations/label.rs b/crates/typst/src/foundations/label.rs
index 53914c35..9d84a564 100644
--- a/crates/typst/src/foundations/label.rs
+++ b/crates/typst/src/foundations/label.rs
@@ -31,7 +31,7 @@ use crate::util::PicoStr;
///
/// Currently, labels can only be attached to elements in markup mode, not in
/// code mode. This might change in the future.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Label(PicoStr);
diff --git a/crates/typst/src/foundations/module.rs b/crates/typst/src/foundations/module.rs
index 140618bc..3ec516d3 100644
--- a/crates/typst/src/foundations/module.rs
+++ b/crates/typst/src/foundations/module.rs
@@ -23,7 +23,7 @@ use crate::foundations::{repr, ty, Content, Scope, Value};
/// >>>
/// >>> #(-3)
/// ```
-#[ty]
+#[ty(cast)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Module {
diff --git a/crates/typst/src/foundations/none.rs b/crates/typst/src/foundations/none.rs
index d03ca8fc..afb055a6 100644
--- a/crates/typst/src/foundations/none.rs
+++ b/crates/typst/src/foundations/none.rs
@@ -20,7 +20,7 @@ use crate::foundations::{
/// ```example
/// Not visible: #none
/// ```
-#[ty(name = "none")]
+#[ty(cast, name = "none")]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NoneValue;
diff --git a/crates/typst/src/foundations/plugin.rs b/crates/typst/src/foundations/plugin.rs
index 898ac6f8..80644ea5 100644
--- a/crates/typst/src/foundations/plugin.rs
+++ b/crates/typst/src/foundations/plugin.rs
@@ -115,7 +115,7 @@ use crate::World;
/// - Wrappers to help you write your plugin in Rust (Zig wrapper in
/// development)
/// - A stubber for WASI
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Clone)]
pub struct Plugin(Arc<Repr>);
diff --git a/crates/typst/src/foundations/selector.rs b/crates/typst/src/foundations/selector.rs
index f0ab90ee..05bc480e 100644
--- a/crates/typst/src/foundations/selector.rs
+++ b/crates/typst/src/foundations/selector.rs
@@ -76,7 +76,7 @@ pub use crate::__select_where as select_where;
/// == So will this
/// === But this will not.
/// ```
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum Selector {
/// Matches a specific type of element.
diff --git a/crates/typst/src/foundations/str.rs b/crates/typst/src/foundations/str.rs
index 57eac74d..553c2170 100644
--- a/crates/typst/src/foundations/str.rs
+++ b/crates/typst/src/foundations/str.rs
@@ -67,7 +67,7 @@ pub use ecow::eco_format;
/// - `[\r]` for a carriage return
/// - `[\t]` for a tab
/// - `[\u{1f600}]` for a hexadecimal Unicode escape sequence
-#[ty(scope, title = "String")]
+#[ty(scope, cast, title = "String")]
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
@@ -898,10 +898,6 @@ impl Hash for Regex {
}
}
-cast! {
- type Regex,
-}
-
/// A pattern which can be searched for in a string.
#[derive(Debug, Clone)]
pub enum StrPattern {
diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs
index 3fa9e9fb..771a3d2c 100644
--- a/crates/typst/src/foundations/styles.rs
+++ b/crates/typst/src/foundations/styles.rs
@@ -64,7 +64,7 @@ impl Show for StyleElem {
}
/// A list of style properties.
-#[ty]
+#[ty(cast)]
#[derive(Default, PartialEq, Clone, Hash)]
pub struct Styles(EcoVec<Prehashed<Style>>);
diff --git a/crates/typst/src/foundations/ty.rs b/crates/typst/src/foundations/ty.rs
index 4b9f19a9..485bfb45 100644
--- a/crates/typst/src/foundations/ty.rs
+++ b/crates/typst/src/foundations/ty.rs
@@ -53,7 +53,7 @@ pub use typst_macros::{scope, ty};
/// - Adding/joining a type and string will yield a string
/// - The `{in}` operator on a type and a dictionary will evaluate to `{true}`
/// if the dictionary has a string key matching the type's name
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Type(Static<NativeTypeData>);
diff --git a/crates/typst/src/foundations/version.rs b/crates/typst/src/foundations/version.rs
index 98ad598b..6f5c350c 100644
--- a/crates/typst/src/foundations/version.rs
+++ b/crates/typst/src/foundations/version.rs
@@ -20,7 +20,7 @@ use crate::foundations::{cast, func, repr, scope, ty, Repr};
///
/// You can convert a version to an array of explicitly given components using
/// the [`array`]($array) constructor.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Default, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Version(EcoVec<u32>);
diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs
index 0de1ecae..0f319fab 100644
--- a/crates/typst/src/introspection/counter.rs
+++ b/crates/typst/src/introspection/counter.rs
@@ -475,10 +475,6 @@ impl Repr for Counter {
}
}
-cast! {
- type Counter,
-}
-
/// Identifies a counter.
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum CounterKey {
@@ -521,7 +517,7 @@ impl Repr for CounterKey {
}
/// An update to perform on a counter.
-#[ty]
+#[ty(cast)]
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum CounterUpdate {
/// Set the counter to the specified state.
diff --git a/crates/typst/src/introspection/location.rs b/crates/typst/src/introspection/location.rs
index 0ceaac8b..23ed81d6 100644
--- a/crates/typst/src/introspection/location.rs
+++ b/crates/typst/src/introspection/location.rs
@@ -3,7 +3,7 @@ use std::num::NonZeroUsize;
use ecow::EcoString;
use crate::engine::Engine;
-use crate::foundations::{cast, func, scope, ty, Dict, Repr};
+use crate::foundations::{func, scope, ty, Dict, Repr};
use crate::model::Numbering;
/// Identifies an element in the document.
@@ -79,9 +79,5 @@ impl Repr for Location {
}
}
-cast! {
- type Location,
-}
-
/// Makes this element locatable through `engine.locate`.
pub trait Locatable {}
diff --git a/crates/typst/src/introspection/mod.rs b/crates/typst/src/introspection/mod.rs
index 0f5d11b1..86917891 100644
--- a/crates/typst/src/introspection/mod.rs
+++ b/crates/typst/src/introspection/mod.rs
@@ -26,8 +26,7 @@ use ecow::{eco_format, EcoString};
use smallvec::SmallVec;
use crate::foundations::{
- cast, category, elem, ty, Behave, Behaviour, Category, Content, Repr, Scope,
- Unlabellable,
+ category, elem, ty, Behave, Behaviour, Category, Content, Repr, Scope, Unlabellable,
};
use crate::layout::PdfPageLabel;
use crate::model::{Destination, Numbering};
@@ -89,10 +88,6 @@ pub enum Meta {
Hide,
}
-cast! {
- type Meta,
-}
-
impl Debug for Meta {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs
index c1264f1c..3d050fb0 100644
--- a/crates/typst/src/introspection/state.rs
+++ b/crates/typst/src/introspection/state.rs
@@ -351,12 +351,8 @@ impl Repr for State {
}
}
-cast! {
- type State,
-}
-
/// An update to perform on a state.
-#[ty]
+#[ty(cast)]
#[derive(Debug, Clone, PartialEq, Hash)]
pub enum StateUpdate {
/// Set the state to the specified value.
diff --git a/crates/typst/src/layout/align.rs b/crates/typst/src/layout/align.rs
index 052ac49f..a1f2a553 100644
--- a/crates/typst/src/layout/align.rs
+++ b/crates/typst/src/layout/align.rs
@@ -245,10 +245,6 @@ impl From<Side> for Alignment {
}
}
-cast! {
- type Alignment,
-}
-
/// Where to align something horizontally.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub enum HAlignment {
diff --git a/crates/typst/src/layout/angle.rs b/crates/typst/src/layout/angle.rs
index e6ed9a58..1cded9a3 100644
--- a/crates/typst/src/layout/angle.rs
+++ b/crates/typst/src/layout/angle.rs
@@ -19,7 +19,7 @@ use crate::util::{Numeric, Scalar};
/// ```example
/// #rotate(10deg)[Hello there!]
/// ```
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Angle(Scalar);
diff --git a/crates/typst/src/layout/dir.rs b/crates/typst/src/layout/dir.rs
index 569c1880..9a2e7710 100644
--- a/crates/typst/src/layout/dir.rs
+++ b/crates/typst/src/layout/dir.rs
@@ -1,6 +1,6 @@
use ecow::EcoString;
-use crate::foundations::{cast, func, scope, ty, Repr};
+use crate::foundations::{func, scope, ty, Repr};
use crate::layout::{Axis, Side};
/// The four directions into which content can be laid out.
@@ -130,7 +130,3 @@ impl Repr for Dir {
}
}
}
-
-cast! {
- type Dir,
-}
diff --git a/crates/typst/src/layout/fr.rs b/crates/typst/src/layout/fr.rs
index 24fe77f8..23f5cf62 100644
--- a/crates/typst/src/layout/fr.rs
+++ b/crates/typst/src/layout/fr.rs
@@ -20,7 +20,7 @@ use crate::util::{Numeric, Scalar};
/// ```example
/// Left #h(1fr) Left-ish #h(2fr) Right
/// ```
-#[ty(name = "fraction")]
+#[ty(cast, name = "fraction")]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Fr(Scalar);
diff --git a/crates/typst/src/layout/length.rs b/crates/typst/src/layout/length.rs
index 26b9320b..94e85248 100644
--- a/crates/typst/src/layout/length.rs
+++ b/crates/typst/src/layout/length.rs
@@ -38,7 +38,7 @@ use crate::util::Numeric;
/// - `abs`: A length with just the absolute component of the current length
/// (that is, excluding the `em` component).
/// - `em`: The amount of `em` units in this length, as a [float]($float).
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Length {
/// The absolute part.
diff --git a/crates/typst/src/layout/ratio.rs b/crates/typst/src/layout/ratio.rs
index b535df38..8b4e72d4 100644
--- a/crates/typst/src/layout/ratio.rs
+++ b/crates/typst/src/layout/ratio.rs
@@ -17,7 +17,7 @@ use crate::util::{Numeric, Scalar};
/// Scaled apart.
/// ]
/// ```
-#[ty]
+#[ty(cast)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ratio(Scalar);
diff --git a/crates/typst/src/layout/rel.rs b/crates/typst/src/layout/rel.rs
index 7769f858..8f937102 100644
--- a/crates/typst/src/layout/rel.rs
+++ b/crates/typst/src/layout/rel.rs
@@ -25,7 +25,7 @@ use crate::util::Numeric;
/// A relative length has the following fields:
/// - `length`: Its length component.
/// - `ratio`: Its ratio component.
-#[ty(name = "relative", title = "Relative Length")]
+#[ty(cast, name = "relative", title = "Relative Length")]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Rel<T: Numeric = Length> {
/// The relative part.
diff --git a/crates/typst/src/model/bibliography.rs b/crates/typst/src/model/bibliography.rs
index 62e6d986..6ec43b66 100644
--- a/crates/typst/src/model/bibliography.rs
+++ b/crates/typst/src/model/bibliography.rs
@@ -421,10 +421,6 @@ impl Repr for Bibliography {
}
}
-cast! {
- type Bibliography,
-}
-
/// Format a BibLaTeX loading error.
fn format_biblatex_error(path: &str, src: &str, errors: Vec<BibLaTeXError>) -> EcoString {
let Some(error) = errors.first() else {
@@ -440,7 +436,7 @@ fn format_biblatex_error(path: &str, src: &str, errors: Vec<BibLaTeXError>) -> E
}
/// A loaded CSL style.
-#[ty]
+#[ty(cast)]
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct CslStyle {
name: Option<EcoString>,
diff --git a/crates/typst/src/symbols/symbol.rs b/crates/typst/src/symbols/symbol.rs
index 4ba60382..73bdd286 100644
--- a/crates/typst/src/symbols/symbol.rs
+++ b/crates/typst/src/symbols/symbol.rs
@@ -42,7 +42,7 @@ pub use typst_macros::symbols;
/// $arrow.r$ \
/// $arrow.t.quad$
/// ```
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Symbol(Repr);
diff --git a/crates/typst/src/text/deco.rs b/crates/typst/src/text/deco.rs
index 4aced36d..0968782e 100644
--- a/crates/typst/src/text/deco.rs
+++ b/crates/typst/src/text/deco.rs
@@ -5,7 +5,7 @@ use ecow::{eco_format, EcoString};
use crate::diag::SourceResult;
use crate::engine::Engine;
-use crate::foundations::{cast, elem, ty, Content, Fold, Repr, Show, Smart, StyleChain};
+use crate::foundations::{elem, ty, Content, Fold, Repr, Show, Smart, StyleChain};
use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size};
use crate::syntax::Span;
use crate::text::{
@@ -363,10 +363,6 @@ impl Repr for Decoration {
}
}
-cast! {
- type Decoration,
-}
-
/// A kind of decorative line.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum DecoLine {
diff --git a/crates/typst/src/visualize/color.rs b/crates/typst/src/visualize/color.rs
index 0f50432b..a8b51cee 100644
--- a/crates/typst/src/visualize/color.rs
+++ b/crates/typst/src/visualize/color.rs
@@ -163,7 +163,7 @@ const ANGLE_EPSILON: f32 = 1e-5;
/// )
/// }))
/// ```
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Copy, Clone)]
pub enum Color {
/// A 32-bit luma color.
diff --git a/crates/typst/src/visualize/gradient.rs b/crates/typst/src/visualize/gradient.rs
index 623cc368..da747026 100644
--- a/crates/typst/src/visualize/gradient.rs
+++ b/crates/typst/src/visualize/gradient.rs
@@ -175,7 +175,7 @@ use crate::visualize::{Color, ColorSpace, WeightedColor};
/// [`color.oklab`]($color.oklab) colors with extra stops in between. This
/// avoids needing to encode these color spaces in your PDF file, but it does
/// add extra stops to your gradient, which can increase the file size.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Gradient {
Linear(Arc<LinearGradient>),
diff --git a/crates/typst/src/visualize/pattern.rs b/crates/typst/src/visualize/pattern.rs
index a181ad0d..4da1cd61 100644
--- a/crates/typst/src/visualize/pattern.rs
+++ b/crates/typst/src/visualize/pattern.rs
@@ -95,7 +95,7 @@ use crate::World;
/// that are implicitly created by show rules and elements. For example, a
/// [`rotate`]($rotate) will not affect the parent of a gradient, but a
/// [`grid`]($grid) will.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Pattern(Arc<Repr>);
diff --git a/crates/typst/src/visualize/stroke.rs b/crates/typst/src/visualize/stroke.rs
index 3686831d..1d43a7b3 100644
--- a/crates/typst/src/visualize/stroke.rs
+++ b/crates/typst/src/visualize/stroke.rs
@@ -49,7 +49,7 @@ use crate::visualize::{Color, Gradient, Paint, Pattern};
/// constructor function. For example, `{(2pt + blue).thickness}` is `{2pt}`.
/// Meanwhile, `{stroke(red).cap}` is `{auto}` because it's unspecified. Fields
/// set to `{auto}` are inherited.
-#[ty(scope)]
+#[ty(scope, cast)]
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Stroke<T: Numeric = Length> {
/// The stroke's paint.