diff options
Diffstat (limited to 'src/library/maps')
| -rw-r--r-- | src/library/maps/alignment.rs | 77 | ||||
| -rw-r--r-- | src/library/maps/axis.rs | 130 | ||||
| -rw-r--r-- | src/library/maps/mod.rs | 128 | ||||
| -rw-r--r-- | src/library/maps/padding.rs | 95 |
4 files changed, 0 insertions, 430 deletions
diff --git a/src/library/maps/alignment.rs b/src/library/maps/alignment.rs deleted file mode 100644 index 8654e280..00000000 --- a/src/library/maps/alignment.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::*; -use AlignmentKey::*; - - -/// An argument key which describes a target alignment. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum AlignmentKey { - Align(Alignment), - Left, - Top, - Right, - Bottom, -} - -impl AlignmentKey { - /// The generic axis this alignment key corresponds to in the given system - /// of layouting axes. `None` if the alignment is generic. - pub fn axis(self, axes: LayoutAxes) -> Option<GenericAxis> { - match self { - Left | Right => Some(Horizontal.to_generic(axes)), - Top | Bottom => Some(Vertical.to_generic(axes)), - Align(_) => None, - } - } - - /// The generic version of this alignment in the given system of layouting - /// axes. - /// - /// Returns an error if the alignment is invalid for the given axis. - pub fn to_generic(self, axes: LayoutAxes, axis: GenericAxis) -> LayoutResult<Alignment> { - let specific = axis.to_specific(axes); - let start = match axes.get(axis).is_positive() { - true => Origin, - false => End, - }; - - Ok(match (self, specific) { - (Align(alignment), _) => alignment, - (Left, Horizontal) | (Top, Vertical) => start, - (Right, Horizontal) | (Bottom, Vertical) => start.inv(), - - _ => error!( - "invalid alignment `{}` for {} axis", - format!("{:?}", self).to_lowercase(), - format!("{:?}", axis).to_lowercase() - ) - }) - } - - /// The specific version of this alignment in the given system of layouting - /// axes. - pub fn to_specific(self, axes: LayoutAxes, axis: SpecificAxis) -> AlignmentKey { - let direction = axes.get_specific(axis); - if let Align(alignment) = self { - match (direction, alignment) { - (LeftToRight, Origin) | (RightToLeft, End) => Left, - (LeftToRight, End) | (RightToLeft, Origin) => Right, - (TopToBottom, Origin) | (BottomToTop, End) => Top, - (TopToBottom, End) | (BottomToTop, Origin) => Bottom, - (_, Center) => self, - } - } else { - self - } - } -} - -key!(AlignmentKey, "alignment", - "origin" => Align(Origin), - "center" => Align(Center), - "end" => Align(End), - - "left" => Left, - "top" => Top, - "right" => Right, - "bottom" => Bottom, -); diff --git a/src/library/maps/axis.rs b/src/library/maps/axis.rs deleted file mode 100644 index 3c3a8c11..00000000 --- a/src/library/maps/axis.rs +++ /dev/null @@ -1,130 +0,0 @@ -use super::*; -use AxisKey::*; - - -/// An argument key which identifies a layouting axis. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum AxisKey { - Generic(GenericAxis), - Specific(SpecificAxis), -} - -impl AxisKey { - /// The generic version of this axis key in the given system of axes. - pub fn to_generic(self, axes: LayoutAxes) -> GenericAxis { - match self { - Generic(axis) => axis, - Specific(axis) => axis.to_generic(axes), - } - } - - /// The specific version of this axis key in the given system of axes. - pub fn to_specific(self, axes: LayoutAxes) -> SpecificAxis { - match self { - Generic(axis) => axis.to_specific(axes), - Specific(axis) => axis, - } - } -} - -key!(AxisKey, "axis", - "horizontal" | "h" => Specific(Horizontal), - "vertical" | "v" => Specific(Vertical), - "primary" | "p" => Generic(Primary), - "secondary" | "s" => Generic(Secondary), -); - -key!(Direction, "direction", - "left-to-right" | "ltr" => LeftToRight, - "right-to-left" | "rtl" => RightToLeft, - "top-to-bottom" | "ttb" => TopToBottom, - "bottom-to-top" | "btt" => BottomToTop, -); - -/// A map for storing extents along axes. -#[derive(Debug, Clone, PartialEq)] -pub struct ExtentMap<E: ExpressionKind + Copy>(ConsistentMap<AxisKey, E>); - -impl<E: ExpressionKind + Copy> ExtentMap<E> { - /// Parse an extent map from the function args. - /// - /// If `all` is true other arguments will create an error, otherwise - /// they are left intact. - pub fn new(args: &mut FuncArgs, all: bool) -> ParseResult<ExtentMap<E>> { - let mut map = ConsistentMap::new(); - - for arg in args.iter_keys() { - let key = match arg.key.v.as_str() { - "width" | "w" => AxisKey::Specific(Horizontal), - "height" | "h" => AxisKey::Specific(Vertical), - "primary-size" | "ps" => AxisKey::Generic(Primary), - "secondary-size" | "ss" => AxisKey::Generic(Secondary), - - _ => if all { - error!("expected dimension") - } else { - args.add_key_pair(arg); - continue; - } - }; - - let e = E::from_expr(arg.value)?; - map.add(key, e)?; - } - - Ok(ExtentMap(map)) - } - - /// Deduplicate from generic to specific axes. - pub fn dedup(&self, axes: LayoutAxes) -> LayoutResult<ConsistentMap<SpecificAxis, E>> { - self.0.dedup(|key, &val| Ok((key.to_specific(axes), val))) - } -} - -/// An argument key which identifies an axis, but allows for positional -/// arguments with unspecified axes. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum PosAxisKey { - /// The first positional argument. - First, - /// The second positional argument. - Second, - /// An axis keyword argument. - Keyword(AxisKey), -} - -/// A map for storing some data for via keyword or positionally given axes. -#[derive(Debug, Clone, PartialEq)] -pub struct PosAxisMap<E: ExpressionKind + Copy>(ConsistentMap<PosAxisKey, E>); - -impl<E: ExpressionKind + Copy> PosAxisMap<E> { - /// Parse a positional axis map from the function args. - pub fn new(args: &mut FuncArgs) -> ParseResult<PosAxisMap<E>> { - let mut map = ConsistentMap::new(); - - map.add_opt(PosAxisKey::First, args.get_pos_opt::<E>()?)?; - map.add_opt(PosAxisKey::Second, args.get_pos_opt::<E>()?)?; - - for arg in args.iter_keys() { - let axis = AxisKey::from_ident(&arg.key)?; - let value = E::from_expr(arg.value)?; - - map.add(PosAxisKey::Keyword(axis), value)?; - } - - Ok(PosAxisMap(map)) - } - - /// Deduplicate from positional or specific to generic axes. - pub fn dedup<F>(&self, axes: LayoutAxes, f: F) -> LayoutResult<ConsistentMap<GenericAxis, E>> - where F: Fn(E) -> Option<GenericAxis> { - self.0.dedup(|key, &e| { - Ok((match key { - PosAxisKey::First => f(e).unwrap_or(Primary), - PosAxisKey::Second => f(e).unwrap_or(Secondary), - PosAxisKey::Keyword(AxisKey::Specific(axis)) => axis.to_generic(axes), - PosAxisKey::Keyword(AxisKey::Generic(axis)) => *axis, - }, e)) - }) - } -} diff --git a/src/library/maps/mod.rs b/src/library/maps/mod.rs deleted file mode 100644 index 3538def7..00000000 --- a/src/library/maps/mod.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! Deduplicating maps and keys for argument parsing. - -use std::collections::HashMap; -use std::hash::Hash; - -use crate::func::prelude::*; - - -macro_rules! key { - ($type:ty, $name:expr, $($patterns:tt)*) => { - impl $type { - /// Parse this key from an identifier. - pub fn from_ident(ident: &Spanned<Ident>) -> ParseResult<Self> { - Ok(match ident.v.as_str() { - $($patterns)* - _ => error!("expected {}", <Self as ExpressionKind>::NAME), - }) - } - } - - impl ExpressionKind for $type { - const NAME: &'static str = $name; - - fn from_expr(expr: Spanned<Expr>) -> ParseResult<Self> { - if let Expr::Ident(ident) = expr.v { - Self::from_ident(&Spanned::new(ident, expr.span)) - } else { - error!("expected {}", Self::NAME); - } - } - } - }; -} - -pub_use_mod!(axis); -pub_use_mod!(alignment); -pub_use_mod!(padding); - - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum DefaultKey<T> { - Some(T), - None, -} - -impl<T> Into<Option<T>> for DefaultKey<T> { - fn into(self) -> Option<T> { - match self { - DefaultKey::Some(v) => Some(v), - DefaultKey::None => None, - } - } -} - -impl<T> ExpressionKind for DefaultKey<T> where T: ExpressionKind { - const NAME: &'static str = T::NAME; - - fn from_expr(expr: Spanned<Expr>) -> ParseResult<DefaultKey<T>> { - if let Expr::Ident(ident) = &expr.v { - match ident.as_str() { - "default" => return Ok(DefaultKey::None), - _ => {}, - } - } - - T::from_expr(expr).map(|v| DefaultKey::Some(v)) - } -} - -/// A deduplicating map type useful for storing possibly redundant arguments. -#[derive(Debug, Clone, PartialEq)] -pub struct ConsistentMap<K, V> where K: Hash + Eq { - map: HashMap<K, V>, -} - -impl<K, V> ConsistentMap<K, V> where K: Hash + Eq { - pub fn new() -> ConsistentMap<K, V> { - ConsistentMap { map: HashMap::new() } - } - - /// Add a key-value pair. - pub fn add(&mut self, key: K, value: V) -> ParseResult<()> { - match self.map.insert(key, value) { - Some(_) => error!("duplicate argument"), - None => Ok(()) - } - } - - /// Add a key-value pair if the value is not `None`. - pub fn add_opt(&mut self, key: K, value: Option<V>) -> ParseResult<()> { - Ok(if let Some(value) = value { - self.add(key, value)?; - }) - } - - /// Get the value at a key if it is present. - pub fn get(&self, key: K) -> Option<&V> { - self.map.get(&key) - } - - /// Call a function with the value if the key is present. - pub fn with<F>(&self, key: K, callback: F) where F: FnOnce(&V) { - if let Some(value) = self.map.get(&key) { - callback(value); - } - } - - /// Create a new consistent map where keys and values are mapped to new keys - /// and values. - /// - /// Returns an error if a new key is duplicate. - pub fn dedup<F, K2, V2>(&self, f: F) -> LayoutResult<ConsistentMap<K2, V2>> - where F: Fn(&K, &V) -> ParseResult<(K2, V2)>, K2: Hash + Eq { - let mut map = ConsistentMap::new(); - - for (key, value) in self.map.iter() { - let (key, value) = f(key, value)?; - map.add(key, value)?; - } - - Ok(map) - } - - /// Iterate over the (key, value) pairs. - pub fn iter(&self) -> std::collections::hash_map::Iter<'_, K, V> { - self.map.iter() - } -} diff --git a/src/library/maps/padding.rs b/src/library/maps/padding.rs deleted file mode 100644 index e2d0ea09..00000000 --- a/src/library/maps/padding.rs +++ /dev/null @@ -1,95 +0,0 @@ -use super::*; -use AxisKey::*; -use AlignmentKey::*; -use PaddingKey::*; - - -/// An argument key which identifies a margin or padding target. -/// -/// A is the used axis type. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum PaddingKey<A> { - /// All four sides should have the specified padding. - All, - /// Both sides of the given axis should have the specified padding. - Both(A), - /// Only the given side of the given axis should have the specified padding. - Side(A, AlignmentKey), -} - -key!(PaddingKey<AxisKey>, "axis or side", - "horizontal" | "h" => Both(Specific(Horizontal)), - "vertical" | "v" => Both(Specific(Vertical)), - "primary" | "p" => Both(Generic(Primary)), - "secondary" | "s" => Both(Generic(Secondary)), - - "left" => Side(Specific(Horizontal), Left), - "right" => Side(Specific(Horizontal), Right), - "top" => Side(Specific(Vertical), Top), - "bottom" => Side(Specific(Vertical), Bottom), - - "primary-origin" => Side(Generic(Primary), Align(Origin)), - "primary-end" => Side(Generic(Primary), Align(End)), - "secondary-origin" => Side(Generic(Secondary), Align(Origin)), - "secondary-end" => Side(Generic(Secondary), Align(End)), - "horizontal-origin" => Side(Specific(Horizontal), Align(Origin)), - "horizontal-end" => Side(Specific(Horizontal), Align(End)), - "vertical-origin" => Side(Specific(Vertical), Align(Origin)), - "vertical-end" => Side(Specific(Vertical), Align(End)), -); - -/// A map for storing padding at sides. -#[derive(Debug, Clone, PartialEq)] -pub struct PaddingMap(ConsistentMap<PaddingKey<AxisKey>, Option<PSize>>); - -impl PaddingMap { - /// Parse a padding map from the function args. - pub fn new(args: &mut FuncArgs) -> ParseResult<PaddingMap> { - let mut map = ConsistentMap::new(); - map.add_opt(PaddingKey::All, - args.get_pos_opt::<DefaultKey<PSize>>()?.map(Into::into))?; - - for arg in args.iter_keys() { - let key = PaddingKey::from_ident(&arg.key)?; - let size = DefaultKey::<PSize>::from_expr(arg.value)?.into(); - map.add(key, size)?; - } - - Ok(PaddingMap(map)) - } - - /// Apply the specified padding on the size box. - pub fn apply(&self, axes: LayoutAxes, padding: &mut ValueBox<Option<PSize>>) - -> LayoutResult<()> { - use PaddingKey::*; - - let map = self.0.dedup(|key, &val| { - Ok((match key { - All => All, - Both(axis) => Both(axis.to_specific(axes)), - Side(axis, alignment) => { - let axis = axis.to_specific(axes); - Side(axis, alignment.to_specific(axes, axis)) - } - }, val)) - })?; - - map.with(All, |&val| padding.set_all(val)); - map.with(Both(Horizontal), |&val| padding.set_horizontal(val)); - map.with(Both(Vertical), |&val| padding.set_vertical(val)); - - for (key, &val) in map.iter() { - if let Side(_, alignment) = key { - match alignment { - AlignmentKey::Left => padding.left = val, - AlignmentKey::Right => padding.right = val, - AlignmentKey::Top => padding.top = val, - AlignmentKey::Bottom => padding.bottom = val, - _ => {}, - } - } - } - - Ok(()) - } -} |
