diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-02-04 09:35:29 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-02-04 09:35:29 +0100 |
| commit | f655656fb8cb6135b26e7960ce0b7adf96d6f567 (patch) | |
| tree | 218ace99f2c38aa51a5d503414046ca6c295ad91 /src/syntax/func/keys.rs | |
| parent | ec60795575c29ee7fc2ea7507cfcc38958fe67bf (diff) | |
Streamline Key + Value traits 🌊
Diffstat (limited to 'src/syntax/func/keys.rs')
| -rw-r--r-- | src/syntax/func/keys.rs | 72 |
1 files changed, 32 insertions, 40 deletions
diff --git a/src/syntax/func/keys.rs b/src/syntax/func/keys.rs index d77447c8..cb12ee1b 100644 --- a/src/syntax/func/keys.rs +++ b/src/syntax/func/keys.rs @@ -16,9 +16,9 @@ use self::PaddingKey::*; /// ^^^ /// ``` /// -/// A key type has an associated output type, which is returned when parsing -/// this key from a string. Most of the time, the output type is simply the key -/// itself, as in the implementation for the [`AxisKey`]: +/// # Example implementation +/// An implementation for the `AxisKey` that identifies layouting axes might +/// look as follows: /// ``` /// # use typstc::syntax::func::Key; /// # use typstc::syntax::span::Spanned; @@ -27,9 +27,7 @@ use self::PaddingKey::*; /// # use Axis::*; /// # use AxisKey::*; /// impl Key for AxisKey { -/// type Output = Self; -/// -/// fn parse(key: Spanned<&str>) -> Option<Self::Output> { +/// fn parse(key: Spanned<&str>) -> Option<Self> { /// match key.v { /// "horizontal" | "h" => Some(Specific(Horizontal)), /// "vertical" | "v" => Some(Specific(Vertical)), @@ -40,41 +38,28 @@ use self::PaddingKey::*; /// } /// } /// ``` -/// -/// The axis key would also be useful to identify axes when describing -/// dimensions of objects, as in `width=3cm`, because these are also properties -/// that are stored per axis. However, here the used keyword arguments are -/// actually different (`width` instead of `horizontal`)! Therefore we cannot -/// just use the axis key. -/// -/// To fix this, there is another type [`ExtentKey`] which implements `Key` and -/// has the associated output type axis key. The extent key struct itself has no -/// fields and is only used to extract the axis key. This way, we can specify -/// which argument kind we want without duplicating the type in the background. -pub trait Key { - /// The type to parse into. - type Output: Eq; - - /// Parse a key string into the output type if the string is valid for this - /// key. - fn parse(key: Spanned<&str>) -> Option<Self::Output>; +pub trait Key: Sized + Eq { + /// Parse a key string into this type if it is valid for it. + fn parse(key: Spanned<&str>) -> Option<Self>; } -impl<K: Key> Key for Spanned<K> { - type Output = Spanned<K::Output>; +impl Key for String { + fn parse(key: Spanned<&str>) -> Option<Self> { + Some(key.v.to_string()) + } +} - fn parse(key: Spanned<&str>) -> Option<Self::Output> { +impl<K: Key> Key for Spanned<K> { + fn parse(key: Spanned<&str>) -> Option<Self> { K::parse(key).map(|v| Spanned { v, span: key.span }) } } /// Implements [`Key`] for types that just need to match on strings. macro_rules! key { - ($type:ty, $output:ty, $($($p:pat)|* => $r:expr),* $(,)?) => { + ($type:ty, $($($p:pat)|* => $r:expr),* $(,)?) => { impl Key for $type { - type Output = $output; - - fn parse(key: Spanned<&str>) -> Option<Self::Output> { + fn parse(key: Spanned<&str>) -> Option<Self> { match key.v { $($($p)|* => Some($r)),*, _ => None, @@ -110,24 +95,31 @@ impl AxisKey { } } -key!(AxisKey, Self, +key!(AxisKey, "horizontal" | "h" => Specific(Horizontal), "vertical" | "v" => Specific(Vertical), "primary" | "p" => Generic(Primary), "secondary" | "s" => Generic(Secondary), ); -/// A key which parses into an [`AxisKey`] but uses typical extent keywords +/// A key which is equivalent to a [`AxisKey`] but uses typical extent keywords /// instead of axis keywords, e.g. `width` instead of `horizontal`. -pub struct ExtentKey; +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct ExtentKey(AxisKey); -key!(ExtentKey, AxisKey, - "width" | "w" => Specific(Horizontal), - "height" | "h" => Specific(Vertical), - "primary-size" | "ps" => Generic(Primary), - "secondary-size" | "ss" => Generic(Secondary), +key!(ExtentKey, + "width" | "w" => ExtentKey(Specific(Horizontal)), + "height" | "h" => ExtentKey(Specific(Vertical)), + "primary-size" | "ps" => ExtentKey(Generic(Primary)), + "secondary-size" | "ss" => ExtentKey(Generic(Secondary)), ); +impl From<ExtentKey> for AxisKey { + fn from(key: ExtentKey) -> AxisKey { + key.0 + } +} + /// A key which identifies an axis, but alternatively allows for two positional /// arguments with unspecified axes. /// @@ -156,7 +148,7 @@ pub enum PaddingKey<Axis> { Side(Axis, AlignmentValue), } -key!(PaddingKey<AxisKey>, Self, +key!(PaddingKey<AxisKey>, "horizontal" | "h" => Both(Specific(Horizontal)), "vertical" | "v" => Both(Specific(Vertical)), "primary" | "p" => Both(Generic(Primary)), |
