Move some things out of util

This commit is contained in:
Laurenz 2023-11-08 23:42:34 +01:00
parent d7fea7077e
commit 7f0fcda376
33 changed files with 298 additions and 296 deletions

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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::*;

View File

@ -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.

View File

@ -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);
}

View File

@ -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};

View File

@ -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};

View File

@ -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.
///

View File

@ -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]

View File

@ -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()))
}
}

View File

@ -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.
///

View File

@ -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.

View File

@ -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]

View File

@ -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)]

View File

@ -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.
///

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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 {

View File

@ -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]

View File

@ -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;

View File

@ -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.
///

View File

@ -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> {

View File

@ -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()))
}
}

View File

@ -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 (),
}
}

View File

@ -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,
};

View File

@ -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`]
///

View File

@ -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 (),
}

View File

@ -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;

View File

@ -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};