Skip to content

Commit 181566b

Browse files
committed
Add helpers to manipulate execution context without references to the scheme
1 parent 124cb5a commit 181566b

File tree

1 file changed

+60
-21
lines changed

1 file changed

+60
-21
lines changed

engine/src/execution_context.rs

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
scheme::{Field, List, Scheme, SchemeMismatchError},
33
types::{GetType, LhsValue, LhsValueSeed, Type, TypeMismatchError},
4-
ListMatcher,
4+
ListMatcher, UnknownFieldError,
55
};
66
use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, Visitor};
77
use serde::ser::{SerializeMap, SerializeSeq, Serializer};
@@ -16,11 +16,15 @@ use thiserror::Error;
1616
pub enum SetFieldValueError {
1717
/// An error that occurs when trying to assign a value of the wrong type to a field.
1818
#[error("{0}")]
19-
TypeMismatchError(#[source] TypeMismatchError),
19+
TypeMismatch(#[source] TypeMismatchError),
2020

2121
/// An error that occurs when trying to set the value of a field from a different scheme.
2222
#[error("{0}")]
23-
SchemeMismatchError(#[source] SchemeMismatchError),
23+
SchemeMismatch(#[source] SchemeMismatchError),
24+
25+
/// An error that occurs when specifying an unknown field name.
26+
#[error("{0}")]
27+
UnknownField(#[source] UnknownFieldError),
2428
}
2529

2630
/// An error that occurs when previously defined list gets redefined.
@@ -82,7 +86,7 @@ impl<'e, U> ExecutionContext<'e, U> {
8286
value: V,
8387
) -> Result<Option<LhsValue<'e>>, SetFieldValueError> {
8488
if !std::ptr::eq(self.scheme, field.scheme()) {
85-
return Err(SetFieldValueError::SchemeMismatchError(SchemeMismatchError));
89+
return Err(SetFieldValueError::SchemeMismatch(SchemeMismatchError));
8690
}
8791
let value = value.into();
8892

@@ -92,7 +96,32 @@ impl<'e, U> ExecutionContext<'e, U> {
9296
if field_type == value_type {
9397
Ok(self.values[field.index()].replace(value))
9498
} else {
95-
Err(SetFieldValueError::TypeMismatchError(TypeMismatchError {
99+
Err(SetFieldValueError::TypeMismatch(TypeMismatchError {
100+
expected: field_type.into(),
101+
actual: value_type,
102+
}))
103+
}
104+
}
105+
106+
/// Sets a runtime value for a given field name.
107+
pub fn set_field_value_from_name<'v: 'e, V: Into<LhsValue<'v>>>(
108+
&mut self,
109+
name: &str,
110+
value: V,
111+
) -> Result<Option<LhsValue<'e>>, SetFieldValueError> {
112+
let field = self
113+
.scheme
114+
.get_field(name)
115+
.map_err(SetFieldValueError::UnknownField)?;
116+
let value = value.into();
117+
118+
let field_type = field.get_type();
119+
let value_type = value.get_type();
120+
121+
if field_type == value_type {
122+
Ok(self.values[field.index()].replace(value))
123+
} else {
124+
Err(SetFieldValueError::TypeMismatch(TypeMismatchError {
96125
expected: field_type.into(),
97126
actual: value_type,
98127
}))
@@ -138,13 +167,25 @@ impl<'e, U> ExecutionContext<'e, U> {
138167
&*self.list_matchers[list.index()]
139168
}
140169

170+
/// Get the list matcher object for the specified type.
171+
pub fn get_list_matcher_from_type(&self, ty: &Type) -> Option<&dyn ListMatcher> {
172+
let list = self.scheme.get_list(ty)?;
173+
Some(&*self.list_matchers[list.index()])
174+
}
175+
141176
/// Get the list matcher object for the specified list type.
142177
pub fn get_list_matcher_mut(&mut self, list: List<'_>) -> &mut dyn ListMatcher {
143178
assert!(self.scheme() == list.scheme());
144179

145180
&mut *self.list_matchers[list.index()]
146181
}
147182

183+
/// Get the list matcher object for the specified type.
184+
pub fn get_list_matcher_mut_from_type(&mut self, ty: &Type) -> Option<&mut dyn ListMatcher> {
185+
let list = self.scheme.get_list(ty)?;
186+
Some(&mut *self.list_matchers[list.index()])
187+
}
188+
148189
/// Get immutable reference to user data stored in
149190
/// this execution context with [`ExecutionContext::new_with`].
150191
#[inline]
@@ -285,18 +326,18 @@ impl<'de, U> DeserializeSeed<'de> for &mut ExecutionContext<'de, U> {
285326
.map_err(|_| de::Error::custom(format!("unknown field: {key}")))?;
286327
let value = access
287328
.next_value_seed::<LhsValueSeed<'_>>(LhsValueSeed(&field.get_type()))?;
288-
let field = self
289-
.0
290-
.scheme()
291-
.get_field(&key)
292-
.map_err(|_| de::Error::custom(format!("unknown field: {key}")))?;
293-
self.0.set_field_value(field, value).map_err(|e| match e {
294-
SetFieldValueError::TypeMismatchError(e) => de::Error::custom(format!(
295-
"invalid type: {:?}, expected {:?}",
296-
e.actual, e.expected
297-
)),
298-
SetFieldValueError::SchemeMismatchError(_) => unreachable!(),
299-
})?;
329+
self.0
330+
.set_field_value_from_name(&key, value)
331+
.map_err(|e| match e {
332+
SetFieldValueError::UnknownField(UnknownFieldError) => {
333+
de::Error::custom(format!("unknown field name `{key}`",))
334+
}
335+
SetFieldValueError::TypeMismatch(e) => de::Error::custom(format!(
336+
"invalid type: {:?}, expected {:?}",
337+
e.actual, e.expected
338+
)),
339+
SetFieldValueError::SchemeMismatch(_) => unreachable!(),
340+
})?;
300341
}
301342
}
302343

@@ -361,7 +402,7 @@ fn test_field_value_type_mismatch() {
361402

362403
assert_eq!(
363404
ctx.set_field_value(scheme.get_field("foo").unwrap(), LhsValue::Bool(false)),
364-
Err(SetFieldValueError::TypeMismatchError(TypeMismatchError {
405+
Err(SetFieldValueError::TypeMismatch(TypeMismatchError {
365406
expected: Type::Int.into(),
366407
actual: Type::Bool,
367408
}))
@@ -378,9 +419,7 @@ fn test_scheme_mismatch() {
378419

379420
assert_eq!(
380421
ctx.set_field_value(scheme2.get_field("foo").unwrap(), LhsValue::Bool(false)),
381-
Err(SetFieldValueError::SchemeMismatchError(
382-
SchemeMismatchError {}
383-
))
422+
Err(SetFieldValueError::SchemeMismatch(SchemeMismatchError {}))
384423
);
385424
}
386425

0 commit comments

Comments
 (0)