summaryrefslogtreecommitdiff
path: root/src/library/maps/mod.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-12-13 23:59:01 +0100
committerLaurenz <laurmaedje@gmail.com>2019-12-13 23:59:01 +0100
commit665b4d2aca81af48b8e0eaca4e709ef2e7825844 (patch)
tree4ada33f607455f14b6a170fe4b7fbe173056567b /src/library/maps/mod.rs
parent971ff3a2dcff1e68bf7e19017113469aad5a30c2 (diff)
More consistent library code and functions 🎄
Diffstat (limited to 'src/library/maps/mod.rs')
-rw-r--r--src/library/maps/mod.rs103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/library/maps/mod.rs b/src/library/maps/mod.rs
new file mode 100644
index 00000000..284c7181
--- /dev/null
+++ b/src/library/maps/mod.rs
@@ -0,0 +1,103 @@
+//! 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.0.as_str() {
+ $($patterns)*
+ _ => error!("expected {}", <Self as ExpressionKind>::NAME),
+ })
+ }
+ }
+
+ impl ExpressionKind for $type {
+ const NAME: &'static str = $name;
+
+ fn from_expr(expr: Spanned<Expression>) -> ParseResult<Self> {
+ if let Expression::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);
+
+/// 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()
+ }
+}
+
+key!(Direction, "direction",
+ "left-to-right" | "ltr" => LeftToRight,
+ "right-to-left" | "rtl" => RightToLeft,
+ "top-to-bottom" | "ttb" => TopToBottom,
+ "bottom-to-top" | "btt" => BottomToTop,
+);