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
This commit is contained in:
Sebastian Schmidt 2022-07-15 13:44:31 +03:00
parent 3d60c66305
commit 4cc86e7683
2 changed files with 50 additions and 2 deletions

View File

@ -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. //! 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. //! 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::{ use crate::{
function::Function, 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<Item = (String, Value)>;
/// The iterator type for iterating over variable names.
type VariableNameIterator: 'a + Iterator<Item = String>;
/// 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. /*/// A context that allows to retrieve functions programmatically.
pub trait GetFunctionContext: Context { pub trait GetFunctionContext: Context {
/// Returns the function that is linked to the given identifier. /// 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<String>;
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. /// 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.* /// *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<std::collections::hash_map::Keys<'a, String, Value>>;
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. /// This macro provides a convenient syntax for creating a static context.
/// ///
/// # Examples /// # Examples

View File

@ -536,7 +536,7 @@ extern crate serde_derive;
pub use crate::{ pub use crate::{
context::{ context::{
Context, ContextWithMutableFunctions, ContextWithMutableVariables, EmptyContext, Context, ContextWithMutableFunctions, ContextWithMutableVariables, EmptyContext,
HashMapContext, HashMapContext, IterateVariablesContext,
}, },
error::{EvalexprError, EvalexprResult}, error::{EvalexprError, EvalexprResult},
function::Function, function::Function,