summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst-docs/src/lib.rs6
-rw-r--r--crates/typst-ide/src/complete.rs2
-rw-r--r--crates/typst-ide/src/tooltip.rs2
-rw-r--r--crates/typst-library/src/lib.rs4
-rw-r--r--crates/typst-library/src/prelude.rs2
-rw-r--r--crates/typst-library/src/visualize/image.rs6
-rw-r--r--crates/typst-macros/src/elem.rs4
-rw-r--r--crates/typst-pdf/src/outline.rs4
-rw-r--r--crates/typst/src/doc.rs5
-rw-r--r--crates/typst/src/eval/args.rs2
-rw-r--r--crates/typst/src/eval/array.rs2
-rw-r--r--crates/typst/src/eval/auto.rs180
-rw-r--r--crates/typst/src/eval/cast.rs2
-rw-r--r--crates/typst/src/eval/datetime.rs5
-rw-r--r--crates/typst/src/eval/dict.rs3
-rw-r--r--crates/typst/src/eval/duration.rs2
-rw-r--r--crates/typst/src/eval/float.rs2
-rw-r--r--crates/typst/src/eval/int.rs2
-rw-r--r--crates/typst/src/eval/mod.rs6
-rw-r--r--crates/typst/src/eval/ops.rs5
-rw-r--r--crates/typst/src/eval/repr.rs (renamed from crates/typst/src/util/fmt.rs)6
-rw-r--r--crates/typst/src/eval/str.rs2
-rw-r--r--crates/typst/src/eval/value.rs12
-rw-r--r--crates/typst/src/eval/version.rs2
-rw-r--r--crates/typst/src/geom/mod.rs6
-rw-r--r--crates/typst/src/geom/smart.rs181
-rw-r--r--crates/typst/src/model/content.rs69
-rw-r--r--crates/typst/src/model/mod.rs2
-rw-r--r--crates/typst/src/model/selector.rs2
-rw-r--r--crates/typst/src/util/fat.rs55
-rw-r--r--crates/typst/src/util/mod.rs7
-rw-r--r--crates/typst/src/util/pico.rs (renamed from crates/typst/src/util/str.rs)0
-rw-r--r--tests/src/tests.rs4
33 files changed, 298 insertions, 296 deletions
diff --git a/crates/typst-docs/src/lib.rs b/crates/typst-docs/src/lib.rs
index 921695c7..d58734c6 100644
--- a/crates/typst-docs/src/lib.rs
+++ b/crates/typst-docs/src/lib.rs
@@ -21,9 +21,11 @@ use serde::Deserialize;
use serde_yaml as yaml;
use typst::diag::{bail, StrResult};
use typst::doc::Frame;
-use typst::eval::{CastInfo, Func, Library, Module, ParamInfo, Repr, Scope, Type, Value};
+use typst::eval::{
+ CastInfo, Func, Library, Module, ParamInfo, Repr, Scope, Smart, Type, Value,
+};
use typst::font::{Font, FontBook};
-use typst::geom::{Abs, Smart};
+use typst::geom::Abs;
use typst_library::layout::{Margin, PageElem};
static DOCS_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../docs");
diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs
index 32505585..c9a625d1 100644
--- a/crates/typst-ide/src/complete.rs
+++ b/crates/typst-ide/src/complete.rs
@@ -5,6 +5,7 @@ use ecow::{eco_format, EcoString};
use if_chain::if_chain;
use serde::{Deserialize, Serialize};
use typst::doc::Frame;
+use typst::eval::repr::separated_list;
use typst::eval::{
format_str, AutoValue, CastInfo, Func, Library, NoneValue, Repr, Scope, Type, Value,
};
@@ -13,7 +14,6 @@ use typst::model::Label;
use typst::syntax::{
ast, is_id_continue, is_id_start, is_ident, LinkedNode, Source, SyntaxKind,
};
-use typst::util::separated_list;
use typst::World;
use unscanny::Scanner;
diff --git a/crates/typst-ide/src/tooltip.rs b/crates/typst-ide/src/tooltip.rs
index f90f2aea..09433cde 100644
--- a/crates/typst-ide/src/tooltip.rs
+++ b/crates/typst-ide/src/tooltip.rs
@@ -3,11 +3,11 @@ use std::fmt::Write;
use ecow::{eco_format, EcoString};
use if_chain::if_chain;
use typst::doc::Frame;
+use typst::eval::repr::{pretty_comma_list, separated_list};
use typst::eval::{CapturesVisitor, CastInfo, Repr, Tracer, Value};
use typst::geom::{round_2, Length, Numeric};
use typst::syntax::ast;
use typst::syntax::{LinkedNode, Source, SyntaxKind};
-use typst::util::{pretty_comma_list, separated_list};
use typst::World;
use super::analyze::analyze_labels;
diff --git a/crates/typst-library/src/lib.rs b/crates/typst-library/src/lib.rs
index da31409a..554e7bcb 100644
--- a/crates/typst-library/src/lib.rs
+++ b/crates/typst-library/src/lib.rs
@@ -14,8 +14,8 @@ pub mod symbols;
pub mod text;
pub mod visualize;
-use typst::eval::{Array, LangItems, Library, Module, Scope};
-use typst::geom::{Align, Color, Dir, Smart};
+use typst::eval::{Array, LangItems, Library, Module, Scope, Smart};
+use typst::geom::{Align, Color, Dir};
use typst::model::{NativeElement, Styles};
use self::layout::LayoutRoot;
diff --git a/crates/typst-library/src/prelude.rs b/crates/typst-library/src/prelude.rs
index e3163e0f..00700540 100644
--- a/crates/typst-library/src/prelude.rs
+++ b/crates/typst-library/src/prelude.rs
@@ -18,7 +18,7 @@ pub use typst::doc::*;
#[doc(no_inline)]
pub use typst::eval::{
array, cast, dict, format_str, func, scope, ty, Args, Array, Bytes, Cast, Dict,
- FromValue, Func, IntoValue, Repr, Scope, Str, Symbol, Type, Value, Vm,
+ FromValue, Func, IntoValue, Repr, Scope, Smart, Str, Symbol, Type, Value, Vm,
};
#[doc(no_inline)]
pub use typst::geom::*;
diff --git a/crates/typst-library/src/visualize/image.rs b/crates/typst-library/src/visualize/image.rs
index 6e166bc0..7f0b8289 100644
--- a/crates/typst-library/src/visualize/image.rs
+++ b/crates/typst-library/src/visualize/image.rs
@@ -1,7 +1,5 @@
use std::ffi::OsStr;
-use std::path::Path;
-use typst::geom::{self, Smart};
use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat};
use typst::util::option_eq;
@@ -135,7 +133,7 @@ impl Layout for ImageElem {
let format = match self.format(styles) {
Smart::Custom(v) => v,
Smart::Auto => {
- let ext = Path::new(self.path().as_str())
+ let ext = std::path::Path::new(self.path().as_str())
.extension()
.and_then(OsStr::to_str)
.unwrap_or_default()
@@ -213,7 +211,7 @@ impl Layout for ImageElem {
// Create a clipping group if only part of the image should be visible.
if fit == ImageFit::Cover && !target.fits(fitted) {
- frame.clip(geom::Path::rect(frame.size()));
+ frame.clip(Path::rect(frame.size()));
}
// Apply metadata.
diff --git a/crates/typst-macros/src/elem.rs b/crates/typst-macros/src/elem.rs
index a5e14b5a..512cbc84 100644
--- a/crates/typst-macros/src/elem.rs
+++ b/crates/typst-macros/src/elem.rs
@@ -1087,7 +1087,7 @@ fn create_repr_impl(element: &Elem) -> TokenStream {
let fields = self.fields().into_iter()
.map(|(name, value)| eco_format!("{}: {}", name, value.repr()))
.collect::<Vec<_>>();
- ::ecow::eco_format!(#repr_format, ::typst::util::pretty_array_like(&fields, false))
+ ::ecow::eco_format!(#repr_format, ::typst::eval::repr::pretty_array_like(&fields, false))
}
}
}
@@ -1108,7 +1108,7 @@ fn create_vtable_func(element: &Elem) -> TokenStream {
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)
+ ::typst::model::fat::vtable(dangling)
};
return Some(vtable);
}
diff --git a/crates/typst-pdf/src/outline.rs b/crates/typst-pdf/src/outline.rs
index d17f8948..4fd072b6 100644
--- a/crates/typst-pdf/src/outline.rs
+++ b/crates/typst-pdf/src/outline.rs
@@ -1,8 +1,8 @@
use std::num::NonZeroUsize;
use pdf_writer::{Finish, Ref, TextStr};
-use typst::eval::item;
-use typst::geom::{Abs, Smart};
+use typst::eval::{item, Smart};
+use typst::geom::Abs;
use typst::model::Content;
use crate::{AbsExt, PdfContext};
diff --git a/crates/typst/src/doc.rs b/crates/typst/src/doc.rs
index 48f201dc..a53836ac 100644
--- a/crates/typst/src/doc.rs
+++ b/crates/typst/src/doc.rs
@@ -8,12 +8,11 @@ use std::sync::Arc;
use ecow::{eco_format, EcoString};
-use crate::eval::{cast, dict, ty, Datetime, Dict, Repr, Value};
+use crate::eval::{cast, dict, ty, Datetime, Dict, Repr, Smart, Value};
use crate::font::Font;
use crate::geom::{
self, styled_rect, Abs, Axes, Color, Corners, Dir, Em, FixedAlign, FixedStroke,
- Geometry, Length, Numeric, Paint, Path, Point, Rel, Shape, Sides, Size, Smart,
- Transform,
+ Geometry, Length, Numeric, Paint, Path, Point, Rel, Shape, Sides, Size, Transform,
};
use crate::image::Image;
use crate::model::{Content, Location, MetaElem, StyleChain};
diff --git a/crates/typst/src/eval/args.rs b/crates/typst/src/eval/args.rs
index c347f527..543d1913 100644
--- a/crates/typst/src/eval/args.rs
+++ b/crates/typst/src/eval/args.rs
@@ -2,10 +2,10 @@ use std::fmt::{self, Debug, Formatter};
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
+use super::repr::pretty_array_like;
use super::{func, scope, ty, Array, Dict, FromValue, IntoValue, Repr, Str, Value};
use crate::diag::{bail, At, SourceDiagnostic, SourceResult};
use crate::syntax::{Span, Spanned};
-use crate::util::pretty_array_like;
/// Captured arguments to a function.
///
diff --git a/crates/typst/src/eval/array.rs b/crates/typst/src/eval/array.rs
index 772db535..497f91b5 100644
--- a/crates/typst/src/eval/array.rs
+++ b/crates/typst/src/eval/array.rs
@@ -7,6 +7,7 @@ use ecow::{eco_format, EcoString, EcoVec};
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
+use super::repr::pretty_array_like;
use super::{
cast, func, ops, scope, ty, Args, Bytes, CastInfo, FromValue, Func, IntoValue,
Reflect, Repr, Value, Version, Vm,
@@ -14,7 +15,6 @@ use super::{
use crate::diag::{At, SourceResult, StrResult};
use crate::eval::ops::{add, mul};
use crate::syntax::Span;
-use crate::util::pretty_array_like;
/// Create a new [`Array`] from values.
#[macro_export]
diff --git a/crates/typst/src/eval/auto.rs b/crates/typst/src/eval/auto.rs
index 24254a0f..b14b21b1 100644
--- a/crates/typst/src/eval/auto.rs
+++ b/crates/typst/src/eval/auto.rs
@@ -3,6 +3,7 @@ use std::fmt::Debug;
use super::{ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value};
use crate::diag::StrResult;
+use crate::model::{Fold, Resolve, StyleChain};
/// A value that indicates a smart default.
///
@@ -50,3 +51,182 @@ impl Repr for AutoValue {
"auto".into()
}
}
+
+/// A value that can be automatically determined.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub enum Smart<T> {
+ /// The value should be determined smartly based on the circumstances.
+ Auto,
+ /// A specific value.
+ Custom(T),
+}
+
+impl<T> Smart<T> {
+ /// Whether the value is `Auto`.
+ pub fn is_auto(&self) -> bool {
+ matches!(self, Self::Auto)
+ }
+
+ /// Whether this holds a custom value.
+ pub fn is_custom(&self) -> bool {
+ matches!(self, Self::Custom(_))
+ }
+
+ /// Returns a `Smart<&T>` borrowing the inner `T`.
+ pub fn as_ref(&self) -> Smart<&T> {
+ match self {
+ Smart::Auto => Smart::Auto,
+ Smart::Custom(v) => Smart::Custom(v),
+ }
+ }
+
+ /// Returns a reference the contained custom value.
+ /// If the value is [`Smart::Auto`], `None` is returned.
+ pub fn as_custom(self) -> Option<T> {
+ match self {
+ Self::Auto => None,
+ Self::Custom(x) => Some(x),
+ }
+ }
+
+ /// Map the contained custom value with `f`.
+ pub fn map<F, U>(self, f: F) -> Smart<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ match self {
+ Self::Auto => Smart::Auto,
+ Self::Custom(x) => Smart::Custom(f(x)),
+ }
+ }
+
+ /// Map the contained custom value with `f` if it contains a custom value,
+ /// otherwise returns `default`.
+ pub fn map_or<F, U>(self, default: U, f: F) -> U
+ where
+ F: FnOnce(T) -> U,
+ {
+ match self {
+ Self::Auto => default,
+ Self::Custom(x) => f(x),
+ }
+ }
+
+ /// Keeps `self` if it contains a custom value, otherwise returns `other`.
+ pub fn or(self, other: Smart<T>) -> Self {
+ match self {
+ Self::Custom(x) => Self::Custom(x),
+ Self::Auto => other,
+ }
+ }
+
+ /// Retusn `Auto` if `self` is `Auto`, otherwise calls the provided function onthe contained
+ /// value and returns the result.
+ pub fn and_then<F, U>(self, f: F) -> Smart<U>
+ where
+ F: FnOnce(T) -> Smart<U>,
+ {
+ match self {
+ Smart::Auto => Smart::Auto,
+ Smart::Custom(x) => f(x),
+ }
+ }
+
+ /// Returns the contained custom value or a provided default value.
+ pub fn unwrap_or(self, default: T) -> T {
+ match self {
+ Self::Auto => default,
+ Self::Custom(x) => x,
+ }
+ }
+
+ /// Returns the contained custom value or computes a default value.
+ pub fn unwrap_or_else<F>(self, f: F) -> T
+ where
+ F: FnOnce() -> T,
+ {
+ match self {
+ Self::Auto => f(),
+ Self::Custom(x) => x,
+ }
+ }
+
+ /// Returns the contained custom value or the default value.
+ pub fn unwrap_or_default(self) -> T
+ where
+ T: Default,
+ {
+ // we want to do this; the Clippy lint is not type-aware
+ #[allow(clippy::unwrap_or_default)]
+ self.unwrap_or_else(T::default)
+ }
+}
+
+impl<T> Smart<Smart<T>> {
+ /// Removes a single level of nesting, returns `Auto` if the inner or outer value is `Auto`.
+ pub fn flatten(self) -> Smart<T> {
+ match self {
+ Smart::Custom(Smart::Auto) | Smart::Auto => Smart::Auto,
+ Smart::Custom(Smart::Custom(v)) => Smart::Custom(v),
+ }
+ }
+}
+
+impl<T> Default for Smart<T> {
+ fn default() -> Self {
+ Self::Auto
+ }
+}
+
+impl<T: Reflect> Reflect for Smart<T> {
+ fn input() -> CastInfo {
+ T::input() + AutoValue::input()
+ }
+
+ fn output() -> CastInfo {
+ T::output() + AutoValue::output()
+ }
+
+ fn castable(value: &Value) -> bool {
+ AutoValue::castable(value) || T::castable(value)
+ }
+}
+
+impl<T: IntoValue> IntoValue for Smart<T> {
+ fn into_value(self) -> Value {
+ match self {
+ Smart::Custom(v) => v.into_value(),
+ Smart::Auto => Value::Auto,
+ }
+ }
+}
+
+impl<T: FromValue> FromValue for Smart<T> {
+ fn from_value(value: Value) -> StrResult<Self> {
+ match value {
+ Value::Auto => Ok(Self::Auto),
+ v if T::castable(&v) => Ok(Self::Custom(T::from_value(v)?)),
+ _ => Err(Self::error(&value)),
+ }
+ }
+}
+
+impl<T: Resolve> Resolve for Smart<T> {
+ type Output = Smart<T::Output>;
+
+ fn resolve(self, styles: StyleChain) -> Self::Output {
+ self.map(|v| v.resolve(styles))
+ }
+}
+
+impl<T> Fold for Smart<T>
+where
+ T: Fold,
+ T::Output: Default,
+{
+ type Output = Smart<T::Output>;
+
+ fn fold(self, outer: Self::Output) -> Self::Output {
+ self.map(|inner| inner.fold(outer.unwrap_or_default()))
+ }
+}
diff --git a/crates/typst/src/eval/cast.rs b/crates/typst/src/eval/cast.rs
index eeb632f9..4bb5b6af 100644
--- a/crates/typst/src/eval/cast.rs
+++ b/crates/typst/src/eval/cast.rs
@@ -10,10 +10,10 @@ use ecow::{eco_format, EcoString};
use smallvec::SmallVec;
use unicode_math_class::MathClass;
+use super::repr::separated_list;
use super::{Repr, Type, Value};
use crate::diag::{At, SourceResult, StrResult};
use crate::syntax::{Span, Spanned};
-use crate::util::separated_list;
/// Determine details of a type.
///
diff --git a/crates/typst/src/eval/datetime.rs b/crates/typst/src/eval/datetime.rs
index a158ad31..129a05ca 100644
--- a/crates/typst/src/eval/datetime.rs
+++ b/crates/typst/src/eval/datetime.rs
@@ -9,10 +9,9 @@ use time::error::{Format, InvalidFormatDescription};
use time::macros::format_description;
use time::{format_description, Month, PrimitiveDateTime};
-use super::{cast, func, scope, ty, Dict, Duration, Repr, Str, Value, Vm};
+use super::repr::pretty_array_like;
+use super::{cast, func, scope, ty, Dict, Duration, Repr, Smart, Str, Value, Vm};
use crate::diag::{bail, StrResult};
-use crate::geom::Smart;
-use crate::util::pretty_array_like;
use crate::World;
/// Represents a date, a time, or a combination of both.
diff --git a/crates/typst/src/eval/dict.rs b/crates/typst/src/eval/dict.rs
index 1cc675c6..568c6e12 100644
--- a/crates/typst/src/eval/dict.rs
+++ b/crates/typst/src/eval/dict.rs
@@ -7,10 +7,11 @@ use ecow::{eco_format, EcoString};
use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use super::repr::{pretty_array_like, separated_list};
use super::{array, func, scope, ty, Array, Repr, Str, Value};
use crate::diag::StrResult;
use crate::syntax::is_ident;
-use crate::util::{pretty_array_like, separated_list, ArcExt};
+use crate::util::ArcExt;
/// Create a new [`Dict`] from key-value pairs.
#[macro_export]
diff --git a/crates/typst/src/eval/duration.rs b/crates/typst/src/eval/duration.rs
index e1e6ee57..8aa44aba 100644
--- a/crates/typst/src/eval/duration.rs
+++ b/crates/typst/src/eval/duration.rs
@@ -4,8 +4,8 @@ use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Neg, Sub};
use time::ext::NumericalDuration;
+use super::repr::pretty_array_like;
use super::{func, scope, ty, Repr};
-use crate::util::pretty_array_like;
/// Represents a positive or negative span of time.
#[ty(scope)]
diff --git a/crates/typst/src/eval/float.rs b/crates/typst/src/eval/float.rs
index 55becee2..f9340d69 100644
--- a/crates/typst/src/eval/float.rs
+++ b/crates/typst/src/eval/float.rs
@@ -2,9 +2,9 @@ use std::num::ParseFloatError;
use ecow::{eco_format, EcoString};
+use super::repr::{format_float, MINUS_SIGN};
use super::{cast, func, scope, ty, Repr, Str};
use crate::geom::Ratio;
-use crate::util::fmt::{format_float, MINUS_SIGN};
/// A floating-point number.
///
diff --git a/crates/typst/src/eval/int.rs b/crates/typst/src/eval/int.rs
index 077a1ec0..2cd19608 100644
--- a/crates/typst/src/eval/int.rs
+++ b/crates/typst/src/eval/int.rs
@@ -1,8 +1,8 @@
use std::num::{NonZeroI64, NonZeroIsize, NonZeroU64, NonZeroUsize, ParseIntError};
-use crate::util::fmt::{format_int_with_base, MINUS_SIGN};
use ecow::{eco_format, EcoString};
+use super::repr::{format_int_with_base, MINUS_SIGN};
use super::{cast, func, scope, ty, Repr, Str, Value};
/// A whole number.
diff --git a/crates/typst/src/eval/mod.rs b/crates/typst/src/eval/mod.rs
index 26de4399..ce055f1e 100644
--- a/crates/typst/src/eval/mod.rs
+++ b/crates/typst/src/eval/mod.rs
@@ -27,6 +27,7 @@ mod module;
mod none;
pub mod ops;
mod plugin;
+pub mod repr;
mod scope;
mod symbol;
mod tracer;
@@ -43,7 +44,7 @@ pub use {
pub use self::args::{Arg, Args};
pub use self::array::{array, Array};
-pub use self::auto::AutoValue;
+pub use self::auto::{AutoValue, Smart};
pub use self::bytes::Bytes;
pub use self::cast::{
cast, Cast, CastInfo, Container, FromValue, IntoResult, IntoValue, Never, Reflect,
@@ -60,12 +61,13 @@ pub use self::methods::mutable_methods_on;
pub use self::module::Module;
pub use self::none::NoneValue;
pub use self::plugin::Plugin;
+pub use self::repr::Repr;
pub use self::scope::{NativeScope, Scope, Scopes};
pub use self::str::{format_str, Regex, Str};
pub use self::symbol::{symbols, Symbol};
pub use self::tracer::Tracer;
pub use self::ty::{scope, ty, NativeType, NativeTypeData, Type};
-pub use self::value::{Dynamic, Repr, Value};
+pub use self::value::{Dynamic, Value};
pub use self::version::Version;
use std::collections::HashSet;
diff --git a/crates/typst/src/eval/ops.rs b/crates/typst/src/eval/ops.rs
index e0c3b984..cf5d27a6 100644
--- a/crates/typst/src/eval/ops.rs
+++ b/crates/typst/src/eval/ops.rs
@@ -4,10 +4,9 @@ use std::cmp::Ordering;
use ecow::eco_format;
-use super::{format_str, IntoValue, Regex, Repr, Value};
+use super::{format_str, item, IntoValue, Regex, Repr, Smart, Value};
use crate::diag::{bail, StrResult};
-use crate::eval::item;
-use crate::geom::{Align, Length, Numeric, Rel, Smart, Stroke};
+use crate::geom::{Align, Length, Numeric, Rel, Stroke};
use Value::*;
/// Bail with a type mismatch error.
diff --git a/crates/typst/src/util/fmt.rs b/crates/typst/src/eval/repr.rs
index 50e59095..96cca234 100644
--- a/crates/typst/src/util/fmt.rs
+++ b/crates/typst/src/eval/repr.rs
@@ -2,6 +2,12 @@ use ecow::{eco_format, EcoString};
pub const MINUS_SIGN: &str = "\u{2212}";
+/// A trait that defines the `repr` of a Typst value.
+pub trait Repr {
+ /// Return the debug representation of the value.
+ fn repr(&self) -> EcoString;
+}
+
/// Format an integer in a base.
pub fn format_int_with_base(mut n: i64, base: i64) -> EcoString {
if n == 0 {
diff --git a/crates/typst/src/eval/str.rs b/crates/typst/src/eval/str.rs
index 97d15870..def42059 100644
--- a/crates/typst/src/eval/str.rs
+++ b/crates/typst/src/eval/str.rs
@@ -7,6 +7,7 @@ use ecow::EcoString;
use serde::{Deserialize, Serialize};
use unicode_segmentation::UnicodeSegmentation;
+use super::repr::{format_float, format_int_with_base};
use super::{
cast, dict, func, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Repr, Type,
Value, Version, Vm,
@@ -15,7 +16,6 @@ use crate::diag::{bail, At, SourceResult, StrResult};
use crate::geom::Align;
use crate::model::Label;
use crate::syntax::{Span, Spanned};
-use crate::util::fmt::{format_float, format_int_with_base};
/// Create a new [`Str`] from a format string.
#[macro_export]
diff --git a/crates/typst/src/eval/value.rs b/crates/typst/src/eval/value.rs
index 1d866418..a0b2645c 100644
--- a/crates/typst/src/eval/value.rs
+++ b/crates/typst/src/eval/value.rs
@@ -11,17 +11,17 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use siphasher::sip128::{Hasher128, SipHasher13};
use typst::eval::Duration;
+use super::repr::{format_float, format_int_with_base};
use super::{
fields, ops, Args, Array, AutoValue, Bytes, CastInfo, Content, Dict, FromValue, Func,
- IntoValue, Module, NativeType, NoneValue, Plugin, Reflect, Scope, Str, Symbol, Type,
- Version,
+ IntoValue, Module, NativeType, NoneValue, Plugin, Reflect, Repr, Scope, Str, Symbol,
+ Type, Version,
};
use crate::diag::StrResult;
use crate::eval::{item, Datetime};
use crate::geom::{Abs, Angle, Color, Em, Fr, Gradient, Length, Ratio, Rel};
use crate::model::{Label, Styles};
use crate::syntax::{ast, Span};
-use crate::util::fmt::{format_float, format_int_with_base};
/// A computational value.
#[derive(Debug, Default, Clone)]
@@ -489,12 +489,6 @@ impl PartialEq for Dynamic {
}
}
-/// A trait that defines the `repr` of a Typst value.
-pub trait Repr {
- /// Return the debug representation of the value.
- fn repr(&self) -> EcoString;
-}
-
trait Bounds: Debug + Repr + Sync + Send + 'static {
fn as_any(&self) -> &dyn Any;
fn dyn_eq(&self, other: &Dynamic) -> bool;
diff --git a/crates/typst/src/eval/version.rs b/crates/typst/src/eval/version.rs
index bf488792..cf60fd68 100644
--- a/crates/typst/src/eval/version.rs
+++ b/crates/typst/src/eval/version.rs
@@ -5,9 +5,9 @@ use std::iter::repeat;
use ecow::{eco_format, EcoString, EcoVec};
+use super::repr::pretty_array_like;
use super::{cast, func, scope, ty, Repr};
use crate::diag::{bail, error, StrResult};
-use crate::util::pretty_array_like;
/// A version with an arbitrary number of components.
///
diff --git a/crates/typst/src/geom/mod.rs b/crates/typst/src/geom/mod.rs
index 1b2a79bc..fb38bd0a 100644
--- a/crates/typst/src/geom/mod.rs
+++ b/crates/typst/src/geom/mod.rs
@@ -24,7 +24,6 @@ mod scalar;
mod shape;
mod sides;
mod size;
-mod smart;
mod stroke;
mod transform;
@@ -52,7 +51,6 @@ pub use self::scalar::Scalar;
pub use self::shape::{Geometry, Shape};
pub use self::sides::{Side, Sides};
pub use self::size::Size;
-pub use self::smart::Smart;
pub use self::stroke::{DashLength, DashPattern, FixedStroke, LineCap, LineJoin, Stroke};
pub use self::transform::Transform;
@@ -66,9 +64,9 @@ use std::ops::*;
use ecow::{eco_format, EcoString};
use crate::diag::{bail, StrResult};
-use crate::eval::{array, cast, func, scope, ty, Array, Dict, Repr, Value};
+use crate::eval::repr::format_float;
+use crate::eval::{array, cast, func, scope, ty, Array, Dict, Repr, Smart, Value};
use crate::model::{Fold, Resolve, StyleChain};
-use crate::util::fmt::format_float;
/// Generic access to a structure's components.
pub trait Get<Index> {
diff --git a/crates/typst/src/geom/smart.rs b/crates/typst/src/geom/smart.rs
deleted file mode 100644
index bbd9b52a..00000000
--- a/crates/typst/src/geom/smart.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-use super::*;
-use crate::eval::{AutoValue, CastInfo, FromValue, IntoValue, Reflect};
-
-/// A value that can be automatically determined.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
-pub enum Smart<T> {
- /// The value should be determined smartly based on the circumstances.
- Auto,
- /// A specific value.
- Custom(T),
-}
-
-impl<T> Smart<T> {
- /// Whether the value is `Auto`.
- pub fn is_auto(&self) -> bool {
- matches!(self, Self::Auto)
- }
-
- /// Whether this holds a custom value.
- pub fn is_custom(&self) -> bool {
- matches!(self, Self::Custom(_))
- }
-
- /// Returns a `Smart<&T>` borrowing the inner `T`.
- pub fn as_ref(&self) -> Smart<&T> {
- match self {
- Smart::Auto => Smart::Auto,
- Smart::Custom(v) => Smart::Custom(v),
- }
- }
-
- /// Returns a reference the contained custom value.
- /// If the value is [`Smart::Auto`], `None` is returned.
- pub fn as_custom(self) -> Option<T> {
- match self {
- Self::Auto => None,
- Self::Custom(x) => Some(x),
- }
- }
-
- /// Map the contained custom value with `f`.
- pub fn map<F, U>(self, f: F) -> Smart<U>
- where
- F: FnOnce(T) -> U,
- {
- match self {
- Self::Auto => Smart::Auto,
- Self::Custom(x) => Smart::Custom(f(x)),
- }
- }
-
- /// Map the contained custom value with `f` if it contains a custom value,
- /// otherwise returns `default`.
- pub fn map_or<F, U>(self, default: U, f: F) -> U
- where
- F: FnOnce(T) -> U,
- {
- match self {
- Self::Auto => default,
- Self::Custom(x) => f(x),
- }
- }
-
- /// Keeps `self` if it contains a custom value, otherwise returns `other`.
- pub fn or(self, other: Smart<T>) -> Self {
- match self {
- Self::Custom(x) => Self::Custom(x),
- Self::Auto => other,
- }
- }
-
- /// Retusn `Auto` if `self` is `Auto`, otherwise calls the provided function onthe contained
- /// value and returns the result.
- pub fn and_then<F, U>(self, f: F) -> Smart<U>
- where
- F: FnOnce(T) -> Smart<U>,
- {
- match self {
- Smart::Auto => Smart::Auto,
- Smart::Custom(x) => f(x),
- }
- }
-
- /// Returns the contained custom value or a provided default value.
- pub fn unwrap_or(self, default: T) -> T {
- match self {
- Self::Auto => default,
- Self::Custom(x) => x,
- }
- }
-
- /// Returns the contained custom value or computes a default value.
- pub fn unwrap_or_else<F>(self, f: F) -> T
- where
- F: FnOnce() -> T,
- {
- match self {
- Self::Auto => f(),
- Self::Custom(x) => x,
- }
- }
-
- /// Returns the contained custom value or the default value.
- pub fn unwrap_or_default(self) -> T
- where
- T: Default,
- {
- // we want to do this; the Clippy lint is not type-aware
- #[allow(clippy::unwrap_or_default)]
- self.unwrap_or_else(T::default)
- }
-}
-
-impl<T> Smart<Smart<T>> {
- /// Removes a single level of nesting, returns `Auto` if the inner or outer value is `Auto`.
- pub fn flatten(self) -> Smart<T> {
- match self {
- Smart::Custom(Smart::Auto) | Smart::Auto => Smart::Auto,
- Smart::Custom(Smart::Custom(v)) => Smart::Custom(v),
- }
- }
-}
-
-impl<T> Default for Smart<T> {
- fn default() -> Self {
- Self::Auto
- }
-}
-
-impl<T: Reflect> Reflect for Smart<T> {
- fn input() -> CastInfo {
- T::input() + AutoValue::input()
- }
-
- fn output() -> CastInfo {
- T::output() + AutoValue::output()
- }
-
- fn castable(value: &Value) -> bool {
- AutoValue::castable(value) || T::castable(value)
- }
-}
-
-impl<T: IntoValue> IntoValue for Smart<T> {
- fn into_value(self) -> Value {
- match self {
- Smart::Custom(v) => v.into_value(),
- Smart::Auto => Value::Auto,
- }
- }
-}
-
-impl<T: FromValue> FromValue for Smart<T> {
- fn from_value(value: Value) -> StrResult<Self> {
- match value {
- Value::Auto => Ok(Self::Auto),
- v if T::castable(&v) => Ok(Self::Custom(T::from_value(v)?)),
- _ => Err(Self::error(&value)),
- }
- }
-}
-
-impl<T: Resolve> Resolve for Smart<T> {
- type Output = Smart<T::Output>;
-
- fn resolve(self, styles: StyleChain) -> Self::Output {
- self.map(|v| v.resolve(styles))
- }
-}
-
-impl<T> Fold for Smart<T>
-where
- T: Fold,
- T::Output: Default,
-{
- type Output = Smart<T::Output>;
-
- fn fold(self, outer: Self::Output) -> Self::Output {
- self.map(|inner| inner.fold(outer.unwrap_or_default()))
- }
-}
diff --git a/crates/typst/src/model/content.rs b/crates/typst/src/model/content.rs
index f853fc51..1d7a1978 100644
--- a/crates/typst/src/model/content.rs
+++ b/crates/typst/src/model/content.rs
@@ -16,9 +16,9 @@ use super::{
};
use crate::diag::{SourceResult, StrResult};
use crate::doc::Meta;
+use crate::eval::repr::pretty_array_like;
use crate::eval::{func, scope, ty, Dict, FromValue, IntoValue, Repr, Str, Value, Vm};
use crate::syntax::Span;
-use crate::util::pretty_array_like;
/// A piece of document content.
///
@@ -256,7 +256,7 @@ impl Content {
{
let vtable = self.elem().vtable()(TypeId::of::<C>())?;
let data = Arc::as_ptr(&self.0) as *const ();
- Some(unsafe { &*crate::util::fat::from_raw_parts(data, vtable) })
+ Some(unsafe { &*fat::from_raw_parts(data, vtable) })
}
/// Cast to a mutable trait object if the contained element has the given
@@ -268,7 +268,7 @@ impl Content {
// Safety: We ensure the element is not shared.
let vtable = self.elem().vtable()(TypeId::of::<C>())?;
let data = self.make_mut() as *mut dyn NativeElement as *mut ();
- Some(unsafe { &mut *crate::util::fat::from_raw_parts_mut(data, vtable) })
+ Some(unsafe { &mut *fat::from_raw_parts_mut(data, vtable) })
}
/// Whether the content is a sequence.
@@ -749,3 +749,66 @@ fn missing_field_no_default(field: &str) -> EcoString {
field.repr()
)
}
+
+/// Fat pointer handling.
+///
+/// This assumes the memory representation of fat pointers. Although it is not
+/// guaranteed by Rust, it's improbable that it will change. Still, when the
+/// pointer metadata APIs are stable, we should definitely move to them:
+/// <https://github.com/rust-lang/rust/issues/81513>
+pub mod fat {
+ use std::alloc::Layout;
+ use std::mem;
+
+ /// Create a fat pointer from a data address and a vtable address.
+ ///
+ /// # Safety
+ /// Must only be called when `T` is a `dyn Trait`. The data address must point
+ /// to a value whose type implements the trait of `T` and the `vtable` must have
+ /// been extracted with [`vtable`].
+ #[track_caller]
+ pub unsafe fn from_raw_parts<T: ?Sized>(
+ data: *const (),
+ vtable: *const (),
+ ) -> *const T {
+ let fat = FatPointer { data, vtable };
+ debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
+ mem::transmute_copy::<FatPointer, *const T>(&fat)
+ }
+
+ /// Create a mutable fat pointer from a data address and a vtable address.
+ ///
+ /// # Safety
+ /// Must only be called when `T` is a `dyn Trait`. The data address must point
+ /// to a value whose type implements the trait of `T` and the `vtable` must have
+ /// been extracted with [`vtable`].
+ #[track_caller]
+ pub unsafe fn from_raw_parts_mut<T: ?Sized>(
+ data: *mut (),
+ vtable: *const (),
+ ) -> *mut T {
+ let fat = FatPointer { data, vtable };
+ debug_assert_eq!(Layout::new::<*mut T>(), Layout::new::<FatPointer>());
+ mem::transmute_copy::<FatPointer, *mut T>(&fat)
+ }
+
+ /// Extract the address to a trait object's vtable.
+ ///
+ /// # Safety
+ /// Must only be called when `T` is a `dyn Trait`.
+ #[track_caller]
+ pub unsafe fn vtable<T: ?Sized>(ptr: *const T) -> *const () {
+ debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
+ mem::transmute_copy::<*const T, FatPointer>(&ptr).vtable
+ }
+
+ /// The memory representation of a trait object pointer.
+ ///
+ /// Although this is not guaranteed by Rust, it's improbable that it will
+ /// change.
+ #[repr(C)]
+ struct FatPointer {
+ data: *const (),
+ vtable: *const (),
+ }
+}
diff --git a/crates/typst/src/model/mod.rs b/crates/typst/src/model/mod.rs
index 0c91f386..de50f24a 100644
--- a/crates/typst/src/model/mod.rs
+++ b/crates/typst/src/model/mod.rs
@@ -14,7 +14,7 @@ use ecow::EcoVec;
pub use typst_macros::elem;
pub use self::block::{Block, Blockable};
-pub use self::content::{Content, MetaElem, PlainText};
+pub use self::content::{fat, Content, MetaElem, PlainText};
pub use self::element::{
Construct, Element, ElementFields, LocalName, NativeElement, NativeElementData, Set,
};
diff --git a/crates/typst/src/model/selector.rs b/crates/typst/src/model/selector.rs
index 89c518bc..c71569e6 100644
--- a/crates/typst/src/model/selector.rs
+++ b/crates/typst/src/model/selector.rs
@@ -7,11 +7,11 @@ use smallvec::SmallVec;
use super::{Content, Element, Label, Locatable, Location};
use crate::diag::{bail, StrResult};
+use crate::eval::repr::pretty_array_like;
use crate::eval::{
cast, func, item, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Repr,
Str, Symbol, Type, Value,
};
-use crate::util::pretty_array_like;
/// A helper macro to create a field selector used in [`Selector::Elem`]
///
diff --git a/crates/typst/src/util/fat.rs b/crates/typst/src/util/fat.rs
deleted file mode 100644
index d3c9bb20..00000000
--- a/crates/typst/src/util/fat.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-//! Fat pointer handling.
-//!
-//! This assumes the memory representation of fat pointers. Although it is not
-//! guaranteed by Rust, it's improbable that it will change. Still, when the
-//! pointer metadata APIs are stable, we should definitely move to them:
-//! <https://github.com/rust-lang/rust/issues/81513>
-
-use std::alloc::Layout;
-use std::mem;
-
-/// Create a fat pointer from a data address and a vtable address.
-///
-/// # Safety
-/// Must only be called when `T` is a `dyn Trait`. The data address must point
-/// to a value whose type implements the trait of `T` and the `vtable` must have
-/// been extracted with [`vtable`].
-#[track_caller]
-pub unsafe fn from_raw_parts<T: ?Sized>(data: *const (), vtable: *const ()) -> *const T {
- let fat = FatPointer { data, vtable };
- debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
- mem::transmute_copy::<FatPointer, *const T>(&fat)
-}
-
-/// Create a mutable fat pointer from a data address and a vtable address.
-///
-/// # Safety
-/// Must only be called when `T` is a `dyn Trait`. The data address must point
-/// to a value whose type implements the trait of `T` and the `vtable` must have
-/// been extracted with [`vtable`].
-#[track_caller]
-pub unsafe fn from_raw_parts_mut<T: ?Sized>(data: *mut (), vtable: *const ()) -> *mut T {
- let fat = FatPointer { data, vtable };
- debug_assert_eq!(Layout::new::<*mut T>(), Layout::new::<FatPointer>());
- mem::transmute_copy::<FatPointer, *mut T>(&fat)
-}
-
-/// Extract the address to a trait object's vtable.
-///
-/// # Safety
-/// Must only be called when `T` is a `dyn Trait`.
-#[track_caller]
-pub unsafe fn vtable<T: ?Sized>(ptr: *const T) -> *const () {
- debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>());
- mem::transmute_copy::<*const T, FatPointer>(&ptr).vtable
-}
-
-/// The memory representation of a trait object pointer.
-///
-/// Although this is not guaranteed by Rust, it's improbable that it will
-/// change.
-#[repr(C)]
-struct FatPointer {
- data: *const (),
- vtable: *const (),
-}
diff --git a/crates/typst/src/util/mod.rs b/crates/typst/src/util/mod.rs
index 573d6b1c..53534490 100644
--- a/crates/typst/src/util/mod.rs
+++ b/crates/typst/src/util/mod.rs
@@ -1,11 +1,8 @@
//! Utilities.
-pub mod fat;
-pub mod fmt;
-mod str;
+mod pico;
-pub use self::fmt::{pretty_array_like, pretty_comma_list, separated_list};
-pub use self::str::PicoStr;
+pub use self::pico::PicoStr;
use std::fmt::{Debug, Formatter};
use std::hash::Hash;
diff --git a/crates/typst/src/util/str.rs b/crates/typst/src/util/pico.rs
index 398392f8..398392f8 100644
--- a/crates/typst/src/util/str.rs
+++ b/crates/typst/src/util/pico.rs
diff --git a/tests/src/tests.rs b/tests/src/tests.rs
index 0271839c..3b33a729 100644
--- a/tests/src/tests.rs
+++ b/tests/src/tests.rs
@@ -23,10 +23,10 @@ use walkdir::WalkDir;
use typst::diag::{bail, FileError, FileResult, Severity, StrResult};
use typst::doc::{Document, Frame, FrameItem, Meta};
use typst::eval::{
- eco_format, func, Bytes, Datetime, Library, NoneValue, Repr, Tracer, Value,
+ eco_format, func, Bytes, Datetime, Library, NoneValue, Repr, Smart, Tracer, Value,
};
use typst::font::{Font, FontBook};
-use typst::geom::{Abs, Color, Smart, Transform};
+use typst::geom::{Abs, Color, Transform};
use typst::syntax::{FileId, PackageVersion, Source, SyntaxNode, VirtualPath};
use typst::{World, WorldExt};
use typst_library::layout::{Margin, PageElem};