More useful Debug impls

This commit is contained in:
Laurenz 2023-11-19 17:42:43 +01:00
parent 2da619e17c
commit c97a01616a
33 changed files with 688 additions and 402 deletions

View File

@ -1,5 +1,6 @@
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::path::Path;
use std::sync::Arc;
@ -296,7 +297,7 @@ impl LocalName for BibliographyElem {
/// A loaded bibliography.
#[ty]
#[derive(Debug, Clone, PartialEq)]
#[derive(Clone, PartialEq)]
pub struct Bibliography {
map: Arc<IndexMap<PicoStr, hayagriva::Entry>>,
hash: u128,
@ -378,6 +379,12 @@ impl Bibliography {
}
}
impl Debug for Bibliography {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_set().entries(self.map.keys()).finish()
}
}
impl Hash for Bibliography {
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state);

View File

@ -48,18 +48,6 @@ pub struct Args {
pub items: EcoVec<Arg>,
}
/// An argument to a function call: `12` or `draw: false`.
#[derive(Debug, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Arg {
/// The span of the whole argument.
pub span: Span,
/// The name of the argument (`None` for positional arguments).
pub name: Option<Str>,
/// The value of the argument.
pub value: Spanned<Value>,
}
impl Args {
/// Create positional arguments from a span and values.
pub fn new<T: IntoValue>(span: Span, values: impl IntoIterator<Item = T>) -> Self {
@ -274,12 +262,6 @@ impl Args {
}
}
impl PartialEq for Args {
fn eq(&self, other: &Self) -> bool {
self.to_pos() == other.to_pos() && self.to_named() == other.to_named()
}
}
impl Debug for Args {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_list().entries(&self.items).finish()
@ -293,9 +275,33 @@ impl Repr for Args {
}
}
impl PartialEq for Arg {
impl PartialEq for Args {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.value.v == other.value.v
self.to_pos() == other.to_pos() && self.to_named() == other.to_named()
}
}
/// An argument to a function call: `12` or `draw: false`.
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Arg {
/// The span of the whole argument.
pub span: Span,
/// The name of the argument (`None` for positional arguments).
pub name: Option<Str>,
/// The value of the argument.
pub value: Spanned<Value>,
}
impl Debug for Arg {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if let Some(name) = &self.name {
name.fmt(f)?;
f.write_str(": ")?;
self.value.v.fmt(f)
} else {
self.value.v.fmt(f)
}
}
}
@ -308,3 +314,9 @@ impl Repr for Arg {
}
}
}
impl PartialEq for Arg {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.value.v == other.value.v
}
}

View File

@ -1,5 +1,5 @@
use ecow::EcoString;
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use crate::diag::StrResult;
use crate::eval::{ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value};
@ -14,7 +14,7 @@ use crate::model::{Fold, Resolve, StyleChain};
/// parameter. Setting it to `{auto}` lets Typst automatically determine the
/// direction from the [text language]($text.lang).
#[ty(name = "auto")]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AutoValue;
impl IntoValue for AutoValue {
@ -46,6 +46,12 @@ impl Reflect for AutoValue {
}
}
impl Debug for AutoValue {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("Auto")
}
}
impl Repr for AutoValue {
fn repr(&self) -> EcoString {
"auto".into()

View File

@ -1,5 +1,5 @@
use std::borrow::Cow;
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, AddAssign, Deref};
use std::sync::Arc;
@ -38,7 +38,7 @@ use crate::eval::{cast, func, scope, ty, Array, Reflect, Repr, Str, Value};
/// #str(data.slice(1, 4))
/// ```
#[ty(scope)]
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>);
impl Bytes {
@ -153,15 +153,15 @@ impl Bytes {
}
}
impl From<&[u8]> for Bytes {
fn from(slice: &[u8]) -> Self {
Self(Arc::new(Prehashed::new(slice.to_vec().into())))
impl Debug for Bytes {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Bytes({})", self.len())
}
}
impl From<Vec<u8>> for Bytes {
fn from(vec: Vec<u8>) -> Self {
Self(Arc::new(Prehashed::new(vec.into())))
impl Repr for Bytes {
fn repr(&self) -> EcoString {
eco_format!("bytes({})", self.len())
}
}
@ -179,9 +179,15 @@ impl AsRef<[u8]> for Bytes {
}
}
impl Repr for Bytes {
fn repr(&self) -> EcoString {
eco_format!("bytes({})", self.len())
impl From<&[u8]> for Bytes {
fn from(slice: &[u8]) -> Self {
Self(Arc::new(Prehashed::new(slice.to_vec().into())))
}
}
impl From<Vec<u8>> for Bytes {
fn from(vec: Vec<u8>) -> Self {
Self(Arc::new(Prehashed::new(vec.into())))
}
}

View File

@ -1,6 +1,6 @@
use ecow::{eco_format, EcoString};
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, Div, Mul, Neg, Sub};
use time::ext::NumericalDuration;
@ -8,7 +8,7 @@ use crate::eval::{func, repr, scope, ty, Repr};
/// Represents a positive or negative span of time.
#[ty(scope)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Duration(time::Duration);
impl Duration {
@ -110,6 +110,12 @@ impl Duration {
}
}
impl Debug for Duration {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl Repr for Duration {
fn repr(&self) -> EcoString {
let mut tmp = self.0;

View File

@ -1,11 +1,9 @@
use ecow::{eco_format, EcoString};
use crate::diag::StrResult;
use crate::eval::Version;
use crate::eval::{IntoValue, Type, Value, Version};
use crate::geom::{Align, Length, Rel, Stroke};
use crate::eval::{IntoValue, Type, Value};
/// Try to access a field on a value.
///
/// This function is exclusively for types which have predefined fields, such as

View File

@ -1,4 +1,4 @@
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
use comemo::{Prehashed, Tracked, TrackedMut};
@ -128,7 +128,7 @@ pub use typst_macros::func;
/// [`array.push(value)`]($array.push). These can modify the values they are
/// called on.
#[ty(scope, name = "function")]
#[derive(Debug, Clone, Hash)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Func {
/// The internal representation.
@ -138,7 +138,7 @@ pub struct Func {
}
/// The different kinds of function representations.
#[derive(Debug, Clone, PartialEq, Hash)]
#[derive(Clone, PartialEq, Hash)]
enum Repr {
/// A native Rust function.
Native(Static<NativeFuncData>),
@ -390,6 +390,12 @@ impl Func {
}
}
impl Debug for Func {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Func({})", self.name().unwrap_or(".."))
}
}
impl super::Repr for Func {
fn repr(&self) -> EcoString {
match self.name() {

View File

@ -1,4 +1,4 @@
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
use ecow::{eco_format, EcoString};
@ -24,7 +24,7 @@ use crate::eval::{ty, Content, Scope, Value};
/// >>> #(-3)
/// ```
#[ty]
#[derive(Debug, Clone, Hash)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Module {
/// The module's name.
@ -100,6 +100,16 @@ impl Module {
}
}
impl Debug for Module {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("Module")
.field("name", &self.name)
.field("scope", &self.inner.scope)
.field("content", &self.inner.content)
.finish()
}
}
impl super::Repr for Module {
fn repr(&self) -> EcoString {
eco_format!("<module {}>", self.name())

View File

@ -1,5 +1,5 @@
use ecow::EcoString;
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use serde::{Serialize, Serializer};
@ -19,7 +19,7 @@ use crate::eval::{cast, ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type,
/// Not visible: #none
/// ```
#[ty(name = "none")]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NoneValue;
impl Reflect for NoneValue {
@ -51,6 +51,12 @@ impl FromValue for NoneValue {
}
}
impl Debug for NoneValue {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("None")
}
}
impl Repr for NoneValue {
fn repr(&self) -> EcoString {
"none".into()

View File

@ -68,7 +68,7 @@ pub use ecow::eco_format;
/// - `[\t]` for a tab
/// - `[\u{1f600}]` for a hexadecimal Unicode escape sequence
#[ty(scope, title = "String")]
#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct Str(EcoString);
@ -598,77 +598,6 @@ impl Str {
}
}
/// A value that can be cast to a string.
pub enum ToStr {
/// A string value ready to be used as-is.
Str(Str),
/// An integer about to be formatted in a given base.
Int(i64),
}
cast! {
ToStr,
v: i64 => Self::Int(v),
v: f64 => Self::Str(repr::format_float(v, None, "").into()),
v: Version => Self::Str(format_str!("{}", v)),
v: Bytes => Self::Str(
std::str::from_utf8(&v)
.map_err(|_| "bytes are not valid utf-8")?
.into()
),
v: Label => Self::Str(v.as_str().into()),
v: Type => Self::Str(v.long_name().into()),
v: Str => Self::Str(v),
}
/// The out of bounds access error message.
#[cold]
fn out_of_bounds(index: i64, len: usize) -> EcoString {
eco_format!("string index out of bounds (index: {}, len: {})", index, len)
}
/// The out of bounds access error message when no default value was given.
#[cold]
fn no_default_and_out_of_bounds(index: i64, len: usize) -> EcoString {
eco_format!("no default value was specified and string index out of bounds (index: {}, len: {})", index, len)
}
/// The char boundary access error message.
#[cold]
fn not_a_char_boundary(index: i64) -> EcoString {
eco_format!("string index {} is not a character boundary", index)
}
/// The error message when the string is empty.
#[cold]
fn string_is_empty() -> EcoString {
"string is empty".into()
}
/// Convert an item of std's `match_indices` to a dictionary.
fn match_to_dict((start, text): (usize, &str)) -> Dict {
dict! {
"start" => start,
"end" => start + text.len(),
"text" => text,
"captures" => Array::new(),
}
}
/// Convert regex captures to a dictionary.
fn captures_to_dict(cap: regex::Captures) -> Dict {
let m = cap.get(0).expect("missing first match");
dict! {
"start" => m.start(),
"end" => m.end(),
"text" => m.as_str(),
"captures" => cap.iter()
.skip(1)
.map(|opt| opt.map_or(Value::None, |m| m.as_str().into_value()))
.collect::<Array>(),
}
}
impl Deref for Str {
type Target = str;
@ -677,9 +606,15 @@ impl Deref for Str {
}
}
impl Debug for Str {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self.as_str(), f)
}
}
impl Display for Str {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(self)
Display::fmt(self.as_str(), f)
}
}
@ -689,6 +624,29 @@ impl Repr for Str {
}
}
impl Repr for EcoString {
fn repr(&self) -> EcoString {
self.as_ref().repr()
}
}
impl Repr for &str {
fn repr(&self) -> EcoString {
let mut r = EcoString::with_capacity(self.len() + 2);
r.push('"');
for c in self.chars() {
match c {
'\0' => r.push_str(r"\u{0}"),
'\'' => r.push('\''),
'"' => r.push_str(r#"\""#),
_ => c.escape_debug().for_each(|c| r.push(c)),
}
}
r.push('"');
r
}
}
impl Add for Str {
type Output = Self;
@ -793,29 +751,77 @@ cast! {
v: Str => v.into(),
}
impl Repr for &str {
fn repr(&self) -> EcoString {
let mut r = EcoString::with_capacity(self.len() + 2);
r.push('"');
for c in self.chars() {
match c {
'\0' => r.push_str(r"\u{0}"),
'\'' => r.push('\''),
'"' => r.push_str(r#"\""#),
_ => c.escape_debug().for_each(|c| r.push(c)),
}
}
r.push('"');
r
/// A value that can be cast to a string.
pub enum ToStr {
/// A string value ready to be used as-is.
Str(Str),
/// An integer about to be formatted in a given base.
Int(i64),
}
cast! {
ToStr,
v: i64 => Self::Int(v),
v: f64 => Self::Str(repr::format_float(v, None, "").into()),
v: Version => Self::Str(format_str!("{}", v)),
v: Bytes => Self::Str(
std::str::from_utf8(&v)
.map_err(|_| "bytes are not valid utf-8")?
.into()
),
v: Label => Self::Str(v.as_str().into()),
v: Type => Self::Str(v.long_name().into()),
v: Str => Self::Str(v),
}
/// Convert an item of std's `match_indices` to a dictionary.
fn match_to_dict((start, text): (usize, &str)) -> Dict {
dict! {
"start" => start,
"end" => start + text.len(),
"text" => text,
"captures" => Array::new(),
}
}
impl Repr for EcoString {
fn repr(&self) -> EcoString {
self.as_ref().repr()
/// Convert regex captures to a dictionary.
fn captures_to_dict(cap: regex::Captures) -> Dict {
let m = cap.get(0).expect("missing first match");
dict! {
"start" => m.start(),
"end" => m.end(),
"text" => m.as_str(),
"captures" => cap.iter()
.skip(1)
.map(|opt| opt.map_or(Value::None, |m| m.as_str().into_value()))
.collect::<Array>(),
}
}
/// The out of bounds access error message.
#[cold]
fn out_of_bounds(index: i64, len: usize) -> EcoString {
eco_format!("string index out of bounds (index: {}, len: {})", index, len)
}
/// The out of bounds access error message when no default value was given.
#[cold]
fn no_default_and_out_of_bounds(index: i64, len: usize) -> EcoString {
eco_format!("no default value was specified and string index out of bounds (index: {}, len: {})", index, len)
}
/// The char boundary access error message.
#[cold]
fn not_a_char_boundary(index: i64) -> EcoString {
eco_format!("string index {} is not a character boundary", index)
}
/// The error message when the string is empty.
#[cold]
fn string_is_empty() -> EcoString {
"string is empty".into()
}
/// A regular expression.
///
/// Can be used as a [show rule selector]($styling/#show-rules) and with

View File

@ -47,7 +47,7 @@ pub use typst_macros::symbols;
pub struct Symbol(Repr);
/// The internal representation.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Clone, Eq, PartialEq, Hash)]
enum Repr {
Single(char),
Const(&'static [(&'static str, char)]),
@ -55,7 +55,7 @@ enum Repr {
}
/// A collection of symbols.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Clone, Eq, PartialEq, Hash)]
enum List {
Static(&'static [(&'static str, char)]),
Runtime(Box<[(EcoString, char)]>),
@ -214,6 +214,25 @@ impl Display for Symbol {
}
}
impl Debug for Repr {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Single(c) => Debug::fmt(c, f),
Self::Const(list) => list.fmt(f),
Self::Multi(lists) => lists.fmt(f),
}
}
}
impl Debug for List {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Static(list) => list.fmt(f),
Self::Runtime(list) => list.fmt(f),
}
}
}
impl super::Repr for Symbol {
fn repr(&self) -> EcoString {
eco_format!("\"{}\"", self.get())

View File

@ -53,7 +53,7 @@ pub use typst_macros::{scope, ty};
/// - 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)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Type(Static<NativeTypeData>);
impl Type {
@ -139,6 +139,12 @@ impl Type {
}
}
impl Debug for Type {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Type({})", self.long_name())
}
}
impl Repr for Type {
fn repr(&self) -> EcoString {
self.long_name().into()

View File

@ -1,6 +1,6 @@
use std::any::Any;
use std::cmp::Ordering;
use std::fmt::{self, Debug};
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
@ -22,7 +22,7 @@ use crate::model::{Label, Styles};
use crate::syntax::{ast, Span};
/// A computational value.
#[derive(Debug, Default, Clone)]
#[derive(Default, Clone)]
pub enum Value {
/// The value that indicates the absence of a meaningful value.
#[default]
@ -218,6 +218,42 @@ impl Value {
}
}
impl Debug for Value {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::None => Debug::fmt(&NoneValue, f),
Self::Auto => Debug::fmt(&AutoValue, f),
Self::Bool(v) => Debug::fmt(v, f),
Self::Int(v) => Debug::fmt(v, f),
Self::Float(v) => Debug::fmt(v, f),
Self::Length(v) => Debug::fmt(v, f),
Self::Angle(v) => Debug::fmt(v, f),
Self::Ratio(v) => Debug::fmt(v, f),
Self::Relative(v) => Debug::fmt(v, f),
Self::Fraction(v) => Debug::fmt(v, f),
Self::Color(v) => Debug::fmt(v, f),
Self::Gradient(v) => Debug::fmt(v, f),
Self::Symbol(v) => Debug::fmt(v, f),
Self::Version(v) => Debug::fmt(v, f),
Self::Str(v) => Debug::fmt(v, f),
Self::Bytes(v) => Debug::fmt(v, f),
Self::Label(v) => Debug::fmt(v, f),
Self::Datetime(v) => Debug::fmt(v, f),
Self::Duration(v) => Debug::fmt(v, f),
Self::Content(v) => Debug::fmt(v, f),
Self::Styles(v) => Debug::fmt(v, f),
Self::Array(v) => Debug::fmt(v, f),
Self::Dict(v) => Debug::fmt(v, f),
Self::Func(v) => Debug::fmt(v, f),
Self::Args(v) => Debug::fmt(v, f),
Self::Type(v) => Debug::fmt(v, f),
Self::Module(v) => Debug::fmt(v, f),
Self::Plugin(v) => Debug::fmt(v, f),
Self::Dyn(v) => Debug::fmt(v, f),
}
}
}
impl Repr for Value {
fn repr(&self) -> EcoString {
match self {
@ -446,7 +482,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
}
/// A value that is not part of the built-in enum.
#[derive(Debug, Clone, Hash)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Dynamic(Arc<dyn Bounds>);
@ -475,6 +511,12 @@ impl Dynamic {
}
}
impl Debug for Dynamic {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl Repr for Dynamic {
fn repr(&self) -> EcoString {
self.0.repr()

View File

@ -1,5 +1,6 @@
use std::cmp::Reverse;
use std::collections::BTreeMap;
use std::fmt::{self, Debug, Formatter};
use serde::{Deserialize, Serialize};
use ttf_parser::{name_id, PlatformId, Tag};
@ -442,7 +443,7 @@ fn shared_prefix_words(left: &str, right: &str) -> usize {
/// - 2 codepoints inside (18, 19)
///
/// So the resulting encoding is `[2, 3, 4, 3, 3, 1, 2, 2]`.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Coverage(Vec<u32>);
@ -498,6 +499,12 @@ impl Coverage {
}
}
impl Debug for Coverage {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("Coverage(..)")
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -1,7 +1,7 @@
use super::*;
/// An absolute length.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Abs(Scalar);
impl Abs {
@ -133,6 +133,12 @@ impl Numeric for Abs {
}
}
impl Debug for Abs {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:?}pt", self.to_pt())
}
}
impl Repr for Abs {
fn repr(&self) -> EcoString {
format_float(self.to_pt(), Some(2), "pt")

View File

@ -12,7 +12,7 @@ use super::*;
/// #rotate(10deg)[Hello there!]
/// ```
#[ty(scope)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Angle(Scalar);
impl Angle {
@ -119,6 +119,12 @@ impl Numeric for Angle {
}
}
impl Debug for Angle {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:?}deg", self.to_deg())
}
}
impl Repr for Angle {
fn repr(&self) -> EcoString {
format_float(self.to_deg(), Some(2), "deg")

View File

@ -154,7 +154,7 @@ const ANGLE_EPSILON: f32 = 1e-5;
/// }))
/// ```
#[ty(scope)]
#[derive(Debug, Copy, Clone)]
#[derive(Copy, Clone)]
pub enum Color {
/// A 32-bit luma color.
Luma(Luma),
@ -174,54 +174,6 @@ pub enum Color {
Hsv(Hsv),
}
impl From<Luma> for Color {
fn from(c: Luma) -> Self {
Self::Luma(c)
}
}
impl From<Oklab> for Color {
fn from(c: Oklab) -> Self {
Self::Oklab(c)
}
}
impl From<Oklch> for Color {
fn from(c: Oklch) -> Self {
Self::Oklch(c)
}
}
impl From<Rgb> for Color {
fn from(c: Rgb) -> Self {
Self::Rgb(c)
}
}
impl From<LinearRgb> for Color {
fn from(c: LinearRgb) -> Self {
Self::LinearRgb(c)
}
}
impl From<Cmyk> for Color {
fn from(c: Cmyk) -> Self {
Self::Cmyk(c)
}
}
impl From<Hsl> for Color {
fn from(c: Hsl) -> Self {
Self::Hsl(c)
}
}
impl From<Hsv> for Color {
fn from(c: Hsv) -> Self {
Self::Hsv(c)
}
}
#[scope]
impl Color {
/// The module of preset color maps.
@ -1379,6 +1331,48 @@ impl Color {
}
}
impl Debug for Color {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Luma(v) => write!(f, "Luma({})", v.luma),
Self::Oklab(v) => write!(f, "Oklab({}, {}, {}, {})", v.l, v.a, v.b, v.alpha),
Self::Oklch(v) => {
write!(
f,
"Oklch({}, {}, {:?}, {})",
v.l,
v.chroma,
hue_angle(v.hue.into_degrees()),
v.alpha
)
}
Self::Rgb(v) => {
write!(f, "Rgb({}, {}, {}, {})", v.red, v.green, v.blue, v.alpha)
}
Self::LinearRgb(v) => {
write!(f, "LinearRgb({}, {}, {}, {})", v.red, v.green, v.blue, v.alpha)
}
Self::Cmyk(v) => write!(f, "Cmyk({}, {}, {}, {})", v.c, v.m, v.y, v.k),
Self::Hsl(v) => write!(
f,
"Hsl({:?}, {}, {}, {})",
hue_angle(v.hue.into_degrees()),
v.saturation,
v.lightness,
v.alpha
),
Self::Hsv(v) => write!(
f,
"Hsv({:?}, {}, {}, {})",
hue_angle(v.hue.into_degrees()),
v.saturation,
v.value,
v.alpha
),
}
}
}
impl Repr for Color {
fn repr(&self) -> EcoString {
match self {
@ -1435,20 +1429,14 @@ impl Repr for Color {
"oklch({}, {}, {})",
Ratio::new(c.l as _).repr(),
format_float(c.chroma as _, Some(3), ""),
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
)
.repr()
hue_angle(c.hue.into_degrees()).repr(),
)
} else {
eco_format!(
"oklch({}, {}, {}, {})",
Ratio::new(c.l as _).repr(),
format_float(c.chroma as _, Some(3), ""),
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
)
.repr(),
hue_angle(c.hue.into_degrees()).repr(),
Ratio::new(c.alpha as _).repr(),
)
}
@ -1457,20 +1445,14 @@ impl Repr for Color {
if c.alpha == 1.0 {
eco_format!(
"color.hsl({}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
)
.repr(),
hue_angle(c.hue.into_degrees()).repr(),
Ratio::new(c.saturation as _).repr(),
Ratio::new(c.lightness as _).repr(),
)
} else {
eco_format!(
"color.hsl({}, {}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
)
.repr(),
hue_angle(c.hue.into_degrees()).repr(),
Ratio::new(c.saturation as _).repr(),
Ratio::new(c.lightness as _).repr(),
Ratio::new(c.alpha as _).repr(),
@ -1481,20 +1463,14 @@ impl Repr for Color {
if c.alpha == 1.0 {
eco_format!(
"color.hsv({}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
)
.repr(),
hue_angle(c.hue.into_degrees()).repr(),
Ratio::new(c.saturation as _).repr(),
Ratio::new(c.value as _).repr(),
)
} else {
eco_format!(
"color.hsv({}, {}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
)
.repr(),
hue_angle(c.hue.into_degrees()).repr(),
Ratio::new(c.saturation as _).repr(),
Ratio::new(c.value as _).repr(),
Ratio::new(c.alpha as _).repr(),
@ -1505,6 +1481,10 @@ impl Repr for Color {
}
}
fn hue_angle(degrees: f32) -> Angle {
Angle::deg(degrees.rem_euclid(360.0 + ANGLE_EPSILON) as _)
}
impl PartialEq for Color {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
@ -1579,6 +1559,54 @@ impl FromStr for Color {
}
}
impl From<Luma> for Color {
fn from(c: Luma) -> Self {
Self::Luma(c)
}
}
impl From<Oklab> for Color {
fn from(c: Oklab) -> Self {
Self::Oklab(c)
}
}
impl From<Oklch> for Color {
fn from(c: Oklch) -> Self {
Self::Oklch(c)
}
}
impl From<Rgb> for Color {
fn from(c: Rgb) -> Self {
Self::Rgb(c)
}
}
impl From<LinearRgb> for Color {
fn from(c: LinearRgb) -> Self {
Self::LinearRgb(c)
}
}
impl From<Cmyk> for Color {
fn from(c: Cmyk) -> Self {
Self::Cmyk(c)
}
}
impl From<Hsl> for Color {
fn from(c: Hsl) -> Self {
Self::Hsl(c)
}
}
impl From<Hsv> for Color {
fn from(c: Hsv) -> Self {
Self::Hsv(c)
}
}
/// An 8-bit CMYK color.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cmyk {
@ -1681,25 +1709,18 @@ cast! {
pub enum ColorSpace {
/// The perceptual Oklab color space.
Oklab,
/// The perceptual Oklch color space.
Oklch,
/// The standard RGB color space.
Srgb,
/// The D65-gray color space.
D65Gray,
/// The linear RGB color space.
LinearRgb,
/// The HSL color space.
Hsl,
/// The HSV color space.
Hsv,
/// The CMYK color space.
Cmyk,
}

View File

@ -2,7 +2,7 @@ use super::*;
use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
/// A container with components for the four corners of a rectangle.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Corners<T> {
/// The value for the top left corner.
pub top_left: T,
@ -96,57 +96,19 @@ impl<T> Get<Corner> for Corners<T> {
}
}
/// The four corners of a rectangle.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Corner {
/// The top left corner.
TopLeft,
/// The top right corner.
TopRight,
/// The bottom right corner.
BottomRight,
/// The bottom left corner.
BottomLeft,
}
impl Corner {
/// The next corner, clockwise.
pub fn next_cw(self) -> Self {
match self {
Self::TopLeft => Self::TopRight,
Self::TopRight => Self::BottomRight,
Self::BottomRight => Self::BottomLeft,
Self::BottomLeft => Self::TopLeft,
}
}
/// The next corner, counter-clockwise.
pub fn next_ccw(self) -> Self {
match self {
Self::TopLeft => Self::BottomLeft,
Self::TopRight => Self::TopLeft,
Self::BottomRight => Self::TopRight,
Self::BottomLeft => Self::BottomRight,
}
}
/// The next side, clockwise.
pub fn side_cw(self) -> Side {
match self {
Self::TopLeft => Side::Top,
Self::TopRight => Side::Right,
Self::BottomRight => Side::Bottom,
Self::BottomLeft => Side::Left,
}
}
/// The next side, counter-clockwise.
pub fn side_ccw(self) -> Side {
match self {
Self::TopLeft => Side::Left,
Self::TopRight => Side::Top,
Self::BottomRight => Side::Right,
Self::BottomLeft => Side::Bottom,
impl<T: Debug + PartialEq> Debug for Corners<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.is_uniform() {
f.write_str("Corners::splat(")?;
self.top_left.fmt(f)?;
f.write_str(")")
} else {
f.debug_struct("Corners")
.field("top_left", &self.top_left)
.field("top_right", &self.top_right)
.field("bottom_right", &self.bottom_right)
.field("bottom_left", &self.bottom_left)
.finish()
}
}
}
@ -262,3 +224,58 @@ impl<T: Fold> Fold for Corners<Option<T>> {
})
}
}
/// The four corners of a rectangle.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Corner {
/// The top left corner.
TopLeft,
/// The top right corner.
TopRight,
/// The bottom right corner.
BottomRight,
/// The bottom left corner.
BottomLeft,
}
impl Corner {
/// The next corner, clockwise.
pub fn next_cw(self) -> Self {
match self {
Self::TopLeft => Self::TopRight,
Self::TopRight => Self::BottomRight,
Self::BottomRight => Self::BottomLeft,
Self::BottomLeft => Self::TopLeft,
}
}
/// The next corner, counter-clockwise.
pub fn next_ccw(self) -> Self {
match self {
Self::TopLeft => Self::BottomLeft,
Self::TopRight => Self::TopLeft,
Self::BottomRight => Self::TopRight,
Self::BottomLeft => Self::BottomRight,
}
}
/// The next side, clockwise.
pub fn side_cw(self) -> Side {
match self {
Self::TopLeft => Side::Top,
Self::TopRight => Side::Right,
Self::BottomRight => Side::Bottom,
Self::BottomLeft => Side::Left,
}
}
/// The next side, counter-clockwise.
pub fn side_ccw(self) -> Side {
match self {
Self::TopLeft => Side::Left,
Self::TopRight => Side::Top,
Self::BottomRight => Side::Right,
Self::BottomLeft => Side::Bottom,
}
}
}

View File

@ -3,7 +3,7 @@ use super::*;
/// A length that is relative to the font size.
///
/// `1em` is the same as the font size.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Em(Scalar);
impl Em {
@ -68,6 +68,12 @@ impl Numeric for Em {
}
}
impl Debug for Em {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:?}em", self.get())
}
}
impl Repr for Em {
fn repr(&self) -> EcoString {
format_float(self.get(), None, "em")

View File

@ -13,7 +13,7 @@ use super::*;
/// Left #h(1fr) Left-ish #h(2fr) Right
/// ```
#[ty(name = "fraction")]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Fr(Scalar);
impl Fr {
@ -63,6 +63,12 @@ impl Numeric for Fr {
}
}
impl Debug for Fr {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:?}fr", self.get())
}
}
impl Repr for Fr {
fn repr(&self) -> EcoString {
format_float(self.get(), Some(2), "fr")

View File

@ -159,7 +159,7 @@ use crate::syntax::{Span, Spanned};
/// Typst predefines color maps that you can use with your gradients. See the
/// [`color`]($color/#predefined-color-maps) documentation for more details.
#[ty(scope)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Gradient {
Linear(Arc<LinearGradient>),
Radial(Arc<RadialGradient>),
@ -828,6 +828,16 @@ impl Gradient {
}
}
impl Debug for Gradient {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Linear(v) => v.fmt(f),
Self::Radial(v) => v.fmt(f),
Self::Conic(v) => v.fmt(f),
}
}
}
impl Repr for Gradient {
fn repr(&self) -> EcoString {
match self {

View File

@ -31,7 +31,7 @@ use crate::syntax::Span;
/// (that is, excluding the `em` component).
/// - `em`: The amount of `em` units in this length, as a [float]($float).
#[ty(scope)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Length {
/// The absolute part.
pub abs: Abs,
@ -126,6 +126,16 @@ impl Length {
}
}
impl Debug for Length {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match (self.abs.is_zero(), self.em.is_zero()) {
(false, false) => write!(f, "{:?} + {:?}", self.abs, self.em),
(true, false) => self.em.fmt(f),
(_, true) => self.abs.fmt(f),
}
}
}
impl Repr for Length {
fn repr(&self) -> EcoString {
match (self.abs.is_zero(), self.em.is_zero()) {

View File

@ -1,7 +1,7 @@
use super::*;
/// How a fill or stroke should be painted.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum Paint {
/// A solid color.
Solid(Color),
@ -32,15 +32,12 @@ impl Paint {
}
}
impl<T: Into<Color>> From<T> for Paint {
fn from(t: T) -> Self {
Self::Solid(t.into())
}
}
impl From<Gradient> for Paint {
fn from(gradient: Gradient) -> Self {
Self::Gradient(gradient)
impl Debug for Paint {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Solid(v) => v.fmt(f),
Self::Gradient(v) => v.fmt(f),
}
}
}
@ -53,6 +50,18 @@ impl Repr for Paint {
}
}
impl<T: Into<Color>> From<T> for Paint {
fn from(t: T) -> Self {
Self::Solid(t.into())
}
}
impl From<Gradient> for Paint {
fn from(gradient: Gradient) -> Self {
Self::Gradient(gradient)
}
}
cast! {
Paint,
self => match self {

View File

@ -12,7 +12,7 @@ use super::*;
/// ]
/// ```
#[ty]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ratio(Scalar);
impl Ratio {
@ -62,6 +62,12 @@ impl Ratio {
}
}
impl Debug for Ratio {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:?}%", self.get())
}
}
impl Repr for Ratio {
fn repr(&self) -> EcoString {
format_float(self.get() * 100.0, Some(2), "%")

View File

@ -18,7 +18,7 @@ use super::*;
/// - `length`: Its length component.
/// - `ratio`: Its ratio component.
#[ty(name = "relative", title = "Relative Length")]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Rel<T: Numeric = Length> {
/// The relative part.
pub rel: Ratio,
@ -80,6 +80,16 @@ impl Rel<Length> {
}
}
impl<T: Numeric + Debug> Debug for Rel<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match (self.rel.is_zero(), self.abs.is_zero()) {
(false, false) => write!(f, "{:?} + {:?}", self.rel, self.abs),
(false, true) => self.rel.fmt(f),
(true, _) => self.abs.fmt(f),
}
}
}
impl<T: Numeric + Repr> Repr for Rel<T> {
fn repr(&self) -> EcoString {
match (self.rel.is_zero(), self.abs.is_zero()) {

View File

@ -3,7 +3,7 @@ use super::*;
/// A 64-bit float that implements `Eq`, `Ord` and `Hash`.
///
/// Panics if it's `NaN` during any of those operations.
#[derive(Debug, Default, Copy, Clone)]
#[derive(Default, Copy, Clone)]
pub struct Scalar(f64);
// We have to detect NaNs this way since `f64::is_nan` isnt const
@ -49,15 +49,9 @@ impl Numeric for Scalar {
}
}
impl From<f64> for Scalar {
fn from(float: f64) -> Self {
Self::new(float)
}
}
impl From<Scalar> for f64 {
fn from(scalar: Scalar) -> Self {
scalar.0
impl Debug for Scalar {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
@ -101,6 +95,18 @@ impl Hash for Scalar {
}
}
impl From<f64> for Scalar {
fn from(float: f64) -> Self {
Self::new(float)
}
}
impl From<Scalar> for f64 {
fn from(scalar: Scalar) -> Self {
scalar.0
}
}
impl Neg for Scalar {
type Output = Self;

View File

@ -1,8 +1,10 @@
use std::fmt::{self, Debug, Formatter};
use super::*;
use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
/// A container with left, top, right and bottom components.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Sides<T> {
/// The value for the left side.
pub left: T,
@ -121,84 +123,21 @@ impl<T> Get<Side> for Sides<T> {
}
}
/// The four sides of objects.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Side {
/// The left side.
Left,
/// The top side.
Top,
/// The right side.
Right,
/// The bottom side.
Bottom,
}
impl Side {
/// The opposite side.
pub fn inv(self) -> Self {
match self {
Self::Left => Self::Right,
Self::Top => Self::Bottom,
Self::Right => Self::Left,
Self::Bottom => Self::Top,
impl<T: Debug + PartialEq> Debug for Sides<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.is_uniform() {
f.write_str("Sides::splat(")?;
self.left.fmt(f)?;
f.write_str(")")
} else {
f.debug_struct("Sides")
.field("left", &self.left)
.field("top", &self.top)
.field("right", &self.right)
.field("bottom", &self.bottom)
.finish()
}
}
/// The next side, clockwise.
pub fn next_cw(self) -> Self {
match self {
Self::Left => Self::Top,
Self::Top => Self::Right,
Self::Right => Self::Bottom,
Self::Bottom => Self::Left,
}
}
/// The next side, counter-clockwise.
pub fn next_ccw(self) -> Self {
match self {
Self::Left => Self::Bottom,
Self::Top => Self::Left,
Self::Right => Self::Top,
Self::Bottom => Self::Right,
}
}
/// The first corner of the side in clockwise order.
pub fn start_corner(self) -> Corner {
match self {
Self::Left => Corner::BottomLeft,
Self::Top => Corner::TopLeft,
Self::Right => Corner::TopRight,
Self::Bottom => Corner::BottomRight,
}
}
/// The second corner of the side in clockwise order.
pub fn end_corner(self) -> Corner {
self.next_cw().start_corner()
}
/// Return the corresponding axis.
pub fn axis(self) -> Axis {
match self {
Self::Left | Self::Right => Axis::Y,
Self::Top | Self::Bottom => Axis::X,
}
}
}
cast! {
Side,
self => Align::from(self).into_value(),
align: Align => match align {
Align::LEFT => Self::Left,
Align::RIGHT => Self::Right,
Align::TOP => Self::Top,
Align::BOTTOM => Self::Bottom,
_ => bail!("cannot convert this alignment to a side"),
},
}
impl<T: Reflect> Reflect for Sides<Option<T>> {
@ -291,3 +230,83 @@ impl<T: Fold> Fold for Sides<Option<T>> {
})
}
}
/// The four sides of objects.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Side {
/// The left side.
Left,
/// The top side.
Top,
/// The right side.
Right,
/// The bottom side.
Bottom,
}
impl Side {
/// The opposite side.
pub fn inv(self) -> Self {
match self {
Self::Left => Self::Right,
Self::Top => Self::Bottom,
Self::Right => Self::Left,
Self::Bottom => Self::Top,
}
}
/// The next side, clockwise.
pub fn next_cw(self) -> Self {
match self {
Self::Left => Self::Top,
Self::Top => Self::Right,
Self::Right => Self::Bottom,
Self::Bottom => Self::Left,
}
}
/// The next side, counter-clockwise.
pub fn next_ccw(self) -> Self {
match self {
Self::Left => Self::Bottom,
Self::Top => Self::Left,
Self::Right => Self::Top,
Self::Bottom => Self::Right,
}
}
/// The first corner of the side in clockwise order.
pub fn start_corner(self) -> Corner {
match self {
Self::Left => Corner::BottomLeft,
Self::Top => Corner::TopLeft,
Self::Right => Corner::TopRight,
Self::Bottom => Corner::BottomRight,
}
}
/// The second corner of the side in clockwise order.
pub fn end_corner(self) -> Corner {
self.next_cw().start_corner()
}
/// Return the corresponding axis.
pub fn axis(self) -> Axis {
match self {
Self::Left | Self::Right => Axis::Y,
Self::Top | Self::Bottom => Axis::X,
}
}
}
cast! {
Side,
self => Align::from(self).into_value(),
align: Align => match align {
Align::LEFT => Self::Left,
Align::RIGHT => Self::Right,
Align::TOP => Self::Top,
Align::BOTTOM => Self::Bottom,
_ => bail!("cannot convert this alignment to a side"),
},
}

View File

@ -27,6 +27,12 @@ impl Block {
}
}
impl Debug for Block {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl Hash for Block {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.dyn_hash(state);
@ -39,12 +45,6 @@ impl Clone for Block {
}
}
impl Debug for Block {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
/// A value that can be stored in a block.
///
/// Auto derived for all types that implement [`Any`], [`Clone`], [`Hash`],

View File

@ -1,5 +1,5 @@
use std::any::TypeId;
use std::fmt::Debug;
use std::fmt::{self, Debug, Formatter};
use std::iter::{self, Sum};
use std::ops::{Add, AddAssign};
use std::sync::Arc;
@ -65,7 +65,7 @@ use crate::syntax::Span;
/// elements the content is composed of and what fields they have.
/// Alternatively, you can inspect the output of the [`repr`]($repr) function.
#[ty(scope)]
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Content(Arc<dyn NativeElement>);
impl Content {
@ -534,6 +534,12 @@ impl Default for Content {
}
}
impl Debug for Content {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: NativeElement> From<T> for Content {
fn from(value: T) -> Self {
Self::new(value)

View File

@ -117,7 +117,7 @@ impl Element {
impl Debug for Element {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(self.name())
write!(f, "Element({})", self.name())
}
}

View File

@ -66,7 +66,7 @@ impl Label {
impl Repr for Label {
fn repr(&self) -> EcoString {
eco_format!("<{}>", self.0.resolve())
eco_format!("<{}>", self.as_str())
}
}

View File

@ -1,5 +1,5 @@
use std::borrow::Cow;
use std::fmt::{self, Debug, Formatter, Write};
use std::fmt::{self, Debug, Formatter};
use std::iter;
use std::mem;
use std::ptr;
@ -16,7 +16,7 @@ use crate::syntax::Span;
/// A list of style properties.
#[ty]
#[derive(Debug, Default, PartialEq, Clone, Hash)]
#[derive(Default, PartialEq, Clone, Hash)]
pub struct Styles(EcoVec<Prehashed<Style>>);
impl Styles {
@ -89,6 +89,13 @@ impl From<Style> for Styles {
}
}
impl Debug for Styles {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("Styles ")?;
f.debug_list().entries(&self.0).finish()
}
}
impl Repr for Styles {
fn repr(&self) -> EcoString {
"..".into()
@ -175,8 +182,14 @@ impl Property {
impl Debug for Property {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "set {}({}: {:?})", self.elem.name(), self.id, self.value)?;
Ok(())
write!(
f,
"Set({}.{}: ",
self.elem.name(),
self.elem.field_name(self.id).unwrap()
)?;
self.value.fmt(f)?;
write!(f, ")")
}
}
@ -244,12 +257,11 @@ impl Recipe {
impl Debug for Recipe {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("show")?;
f.write_str("Show(")?;
if let Some(selector) = &self.selector {
f.write_char(' ')?;
selector.fmt(f)?;
f.write_str(", ")?;
}
f.write_str(": ")?;
self.transform.fmt(f)
}
}
@ -469,10 +481,10 @@ impl<'a> StyleChain<'a> {
impl Debug for StyleChain<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
for entry in self.entries().collect::<Vec<_>>().into_iter().rev() {
writeln!(f, "{:?}", entry)?;
}
Ok(())
f.write_str("StyleChain ")?;
f.debug_list()
.entries(self.entries().collect::<Vec<_>>().into_iter().rev())
.finish()
}
}

View File

@ -35,7 +35,6 @@ impl<T: Send + Sync + 'static> Deferred<T> {
// Ensure that we yield to give the deferred value a chance to compute
// single-threaded platforms (for WASM compatibility).
while let Some(rayon::Yield::Executed) = rayon::yield_now() {}
self.0.wait()
}
}