use crate::function::*;
use crate::marker::*;
use crate::values::*;
use crate::Error;
use crate::ValueType;
use std::collections::HashMap;
#[derive(Debug, Default)]
pub struct VariableBindings<'f> {
entries: HashMap<String, VariableBinding<'f>>,
}
impl<'f> VariableBindings<'f> {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
}
}
}
impl<'f> VariableBindings<'f> {
pub fn bind<T>(&mut self, name: impl Into<String>, value: T) -> Result<&mut Self, Error>
where
T: IntoValue + TypedValue,
{
self.entries
.insert(name.into(), VariableBinding::from_value(value));
Ok(self)
}
pub fn bind_with_value(
&mut self,
name: impl Into<String>,
value_type: ValueType,
value: Value,
) -> Result<&mut Self, Error> {
self.entries
.insert(name.into(), VariableBinding::Value((value_type, value)));
Ok(self)
}
pub fn bind_provider<F, Fm>(
&mut self,
name: impl Into<String>,
provider: F,
) -> Result<&mut Self, Error>
where
F: IntoFunction<'f, Fm>,
Fm: FnMarker,
{
self.entries
.insert(name.into(), VariableBinding::from_provider(provider));
Ok(self)
}
pub fn find(&self, name: &str) -> Option<&VariableBinding<'f>> {
self.entries.get(name)
}
pub fn find_mut(&mut self, name: &str) -> Option<&mut VariableBinding<'f>> {
self.entries.get_mut(name)
}
pub fn entries(&self) -> impl Iterator<Item = (&str, &VariableBinding<'f>)> {
self.entries
.iter()
.map(|(name, entry)| (name.as_str(), entry))
}
pub fn entries_mut(&mut self) -> impl Iterator<Item = (&str, &mut VariableBinding<'f>)> {
self.entries
.iter_mut()
.map(|(name, entry)| (name.as_str(), entry))
}
pub fn remove(&mut self, name: &str) -> Result<(), Error> {
if self.entries.remove(name).is_none() {
return Err(Error::not_found(format!("Variable {name} not found")));
}
Ok(())
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[derive(Debug, Clone)]
pub enum VariableBinding<'f> {
Value((ValueType, Value)),
Provider(Function<'f>),
}
impl<'f> VariableBinding<'f> {
pub fn from_value<T: IntoValue + TypedValue>(value: T) -> Self {
Self::Value((T::value_type(), value.into_value()))
}
pub fn from_provider<F, Fm>(provider: F) -> Self
where
F: IntoFunction<'f, Fm>,
Fm: FnMarker,
{
Self::Provider(provider.into_function())
}
pub fn value_type(&self) -> ValueType {
match self {
Self::Value((ty, _)) => ty.clone(),
Self::Provider(f) => f.function_type().result().clone(),
}
}
pub fn is_value(&self) -> bool {
matches!(self, Self::Value(_))
}
pub fn is_provider(&self) -> bool {
matches!(self, Self::Provider(_))
}
pub fn as_value(&self) -> Option<&Value> {
match self {
Self::Value((_, value)) => Some(value),
Self::Provider(_) => None,
}
}
pub fn as_provider(&self) -> Option<&Function<'f>> {
match self {
Self::Value(_) => None,
Self::Provider(f) => Some(f),
}
}
pub fn into_value(self) -> Option<Value> {
match self {
Self::Value((_, value)) => Some(value),
Self::Provider(_) => None,
}
}
pub fn into_provider(self) -> Option<Function<'f>> {
match self {
Self::Value(_) => None,
Self::Provider(f) => Some(f),
}
}
}