From 4cc86e7683776ecdfe8d8731833fb150eecdfb08 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 15 Jul 2022 13:44:31 +0300 Subject: [PATCH] Add trait to allow iterating over all variables in a context. Both iterating with and without values is supported. Due to limitations in the language, currently only iterating by cloning is supported. When GATs are stabilised, this should change. Relates to #108 --- src/context/mod.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 2 +- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/context/mod.rs b/src/context/mod.rs index 200ae93..e05f893 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -4,7 +4,7 @@ //! This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier and cannot be manipulated, and the `HashMapContext`, that stores its mappings in hash maps. //! The HashMapContext is type-safe and returns an error if the user tries to assign a value of a different type than before to an identifier. -use std::collections::HashMap; +use std::{collections::HashMap, iter}; use crate::{ function::Function, @@ -40,6 +40,22 @@ pub trait ContextWithMutableFunctions: Context { } } +/// A context that allows to iterate over its variable names with their values. +/// +/// **Note:** this trait will change after GATs are stabilised, because then we can get rid of the lifetime in the trait definition. +pub trait IterateVariablesContext<'a> { + /// The iterator type for iterating over variable name-value pairs. + type VariableIterator: 'a + Iterator; + /// The iterator type for iterating over variable names. + type VariableNameIterator: 'a + Iterator; + + /// Returns an iterator over pairs of variable names and values. + fn iter_variables(&'a self) -> Self::VariableIterator; + + /// Returns an iterator over variable names. + fn iter_variable_names(&'a self) -> Self::VariableNameIterator; +} + /*/// A context that allows to retrieve functions programmatically. pub trait GetFunctionContext: Context { /// Returns the function that is linked to the given identifier. @@ -65,6 +81,19 @@ impl Context for EmptyContext { } } +impl<'a> IterateVariablesContext<'a> for EmptyContext { + type VariableIterator = iter::Empty<(String, Value)>; + type VariableNameIterator = iter::Empty; + + fn iter_variables(&self) -> Self::VariableIterator { + iter::empty() + } + + fn iter_variable_names(&self) -> Self::VariableNameIterator { + iter::empty() + } +} + /// A context that stores its mappings in hash maps. /// /// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.* @@ -125,6 +154,25 @@ impl ContextWithMutableFunctions for HashMapContext { } } +impl<'a> IterateVariablesContext<'a> for HashMapContext { + type VariableIterator = std::iter::Map< + std::collections::hash_map::Iter<'a, String, Value>, + fn((&String, &Value)) -> (String, Value), + >; + type VariableNameIterator = + std::iter::Cloned>; + + fn iter_variables(&'a self) -> Self::VariableIterator { + self.variables + .iter() + .map(|(string, value)| (string.clone(), value.clone())) + } + + fn iter_variable_names(&'a self) -> Self::VariableNameIterator { + self.variables.keys().cloned() + } +} + /// This macro provides a convenient syntax for creating a static context. /// /// # Examples diff --git a/src/lib.rs b/src/lib.rs index 3a6e2af..e492ac5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -536,7 +536,7 @@ extern crate serde_derive; pub use crate::{ context::{ Context, ContextWithMutableFunctions, ContextWithMutableVariables, EmptyContext, - HashMapContext, + HashMapContext, IterateVariablesContext, }, error::{EvalexprError, EvalexprResult}, function::Function,