use failure::Fail;
use scheme::{Field, Scheme};
use types::{GetType, LhsValue, Type};
#[derive(Debug, PartialEq, Fail)]
#[fail(
display = "the field should have {:?} type, but {:?} was provided",
field_type, value_type
)]
pub struct FieldValueTypeMismatchError {
pub field_type: Type,
pub value_type: Type,
}
pub struct ExecutionContext<'e> {
scheme: &'e Scheme,
values: Box<[Option<LhsValue<'e>>]>,
}
impl<'e> ExecutionContext<'e> {
pub fn new<'s: 'e>(scheme: &'s Scheme) -> Self {
ExecutionContext {
scheme,
values: vec![None; scheme.get_field_count()].into(),
}
}
pub fn scheme(&self) -> &'e Scheme {
self.scheme
}
pub(crate) fn get_field_value_unchecked(&self, field: Field<'e>) -> &LhsValue<'e> {
debug_assert!(self.scheme() == field.scheme());
self.values[field.index()].as_ref().unwrap_or_else(|| {
panic!(
"Field {} was registered but not given a value",
field.name()
);
})
}
pub fn set_field_value<'v: 'e, V: Into<LhsValue<'v>>>(
&mut self,
name: &str,
value: V,
) -> Result<(), FieldValueTypeMismatchError> {
let field = self.scheme.get_field_index(name).unwrap();
let value = value.into();
let field_type = field.get_type();
let value_type = value.get_type();
if field_type == value_type {
self.values[field.index()] = Some(value);
Ok(())
} else {
Err(FieldValueTypeMismatchError {
field_type,
value_type,
})
}
}
}
#[test]
fn test_field_value_type_mismatch() {
let scheme = Scheme! { foo: Int };
let mut ctx = ExecutionContext::new(&scheme);
assert_eq!(
ctx.set_field_value("foo", LhsValue::Bool(false)),
Err(FieldValueTypeMismatchError {
field_type: Type::Int,
value_type: Type::Bool
})
);
}