diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-04-08 14:48:02 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-04-08 14:48:02 +0200 |
| commit | e1d7edb7c1845e6df6f5e23e3baf7bc88159eade (patch) | |
| tree | 4256919d2be06abdaf5267ac804cfc9d4d3a8dc5 /src | |
| parent | 4bb6240b401605ef6d905273db07545e14f9a21f (diff) | |
Property resolving
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/styles.rs | 72 | ||||
| -rw-r--r-- | src/eval/value.rs | 37 | ||||
| -rw-r--r-- | src/geom/relative.rs | 9 |
3 files changed, 100 insertions, 18 deletions
diff --git a/src/eval/styles.rs b/src/eval/styles.rs index b7f1889c..575518f5 100644 --- a/src/eval/styles.rs +++ b/src/eval/styles.rs @@ -4,8 +4,9 @@ use std::hash::Hash; use std::marker::PhantomData; use std::sync::Arc; -use super::{Args, Content, Func, Layout, Node, Span, Value}; +use super::{Args, Content, Func, Layout, Node, Smart, Span, Value}; use crate::diag::{At, TypResult}; +use crate::geom::{Numeric, Relative, Sides, Spec}; use crate::library::layout::PageNode; use crate::library::text::{FontFamily, ParNode, TextNode}; use crate::util::Prehashed; @@ -280,7 +281,10 @@ pub trait Key<'a>: 'static { /// Compute an output value from a sequence of values belong to this key, /// folding if necessary. - fn get(values: impl Iterator<Item = &'a Self::Value>) -> Self::Output; + fn get( + chain: StyleChain<'a>, + values: impl Iterator<Item = &'a Self::Value>, + ) -> Self::Output; } /// A property that is folded to determine its final value. @@ -292,6 +296,64 @@ pub trait Fold { fn fold(self, outer: Self::Output) -> Self::Output; } +/// A property that is resolved with other properties from the style chain. +pub trait Resolve { + /// The type of the resolved output. + type Output; + + /// Resolve the value using the style chain. + fn resolve(self, styles: StyleChain) -> Self::Output; +} + +impl<T: Resolve> Resolve for Option<T> { + type Output = Option<T::Output>; + + fn resolve(self, styles: StyleChain) -> Self::Output { + self.map(|v| v.resolve(styles)) + } +} + +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: Resolve> Resolve for Spec<T> { + type Output = Spec<T::Output>; + + fn resolve(self, styles: StyleChain) -> Self::Output { + self.map(|v| v.resolve(styles)) + } +} + +impl<T: Resolve> Resolve for Sides<T> { + type Output = Sides<T::Output>; + + fn resolve(self, styles: StyleChain) -> Self::Output { + Sides { + left: self.left.resolve(styles), + right: self.right.resolve(styles), + top: self.top.resolve(styles), + bottom: self.bottom.resolve(styles), + } + } +} + +impl<T> Resolve for Relative<T> +where + T: Resolve + Numeric, + <T as Resolve>::Output: Numeric, +{ + type Output = Relative<<T as Resolve>::Output>; + + fn resolve(self, styles: StyleChain) -> Self::Output { + self.map(|abs| abs.resolve(styles)) + } +} + /// A show rule recipe. #[derive(Clone, PartialEq, Hash)] struct Recipe { @@ -410,10 +472,10 @@ impl<'a> StyleChain<'a> { /// Get the output value of a style property. /// /// Returns the property's default value if no map in the chain contains an - /// entry for it. Also takes care of folding and returns references where - /// applicable. + /// entry for it. Also takes care of folding and resolving and returns + /// references where applicable. pub fn get<K: Key<'a>>(self, key: K) -> K::Output { - K::get(self.values(key)) + K::get(self, self.values(key)) } /// Execute and return the result of a user recipe for a node if there is diff --git a/src/eval/value.rs b/src/eval/value.rs index 44df89e2..12948d72 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -590,6 +590,19 @@ impl<T: Cast> Cast<Spanned<Value>> for Spanned<T> { } } +impl<T: Cast> Cast for Option<T> { + fn is(value: &Value) -> bool { + matches!(value, Value::None) || T::is(value) + } + + fn cast(value: Value) -> StrResult<Self> { + match value { + Value::None => Ok(None), + v => T::cast(v).map(Some).map_err(|msg| with_alternative(msg, "none")), + } + } +} + /// A value that can be automatically determined. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Smart<T> { @@ -601,6 +614,17 @@ pub enum Smart<T> { } impl<T> Smart<T> { + /// 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)), + } + } + /// Returns the contained custom value or a provided default value. pub fn unwrap_or(self, default: T) -> T { match self { @@ -627,19 +651,6 @@ impl<T> Default for Smart<T> { } } -impl<T: Cast> Cast for Option<T> { - fn is(value: &Value) -> bool { - matches!(value, Value::None) || T::is(value) - } - - fn cast(value: Value) -> StrResult<Self> { - match value { - Value::None => Ok(None), - v => T::cast(v).map(Some).map_err(|msg| with_alternative(msg, "none")), - } - } -} - impl<T: Cast> Cast for Smart<T> { fn is(value: &Value) -> bool { matches!(value, Value::Auto) || T::is(value) diff --git a/src/geom/relative.rs b/src/geom/relative.rs index 8e8897e7..066b8c15 100644 --- a/src/geom/relative.rs +++ b/src/geom/relative.rs @@ -34,6 +34,15 @@ impl<T: Numeric> Relative<T> { pub fn resolve(self, whole: T) -> T { self.rel.resolve(whole) + self.abs } + + /// Map the absolute part with `f`. + pub fn map<F, U>(self, f: F) -> Relative<U> + where + F: FnOnce(T) -> U, + U: Numeric, + { + Relative { rel: self.rel, abs: f(self.abs) } + } } impl<T: Numeric> Debug for Relative<T> { |
