Expand description
§whereexpr
A library for building and evaluating type-safe, compiled boolean filter expressions over arbitrary Rust structs.
Expressions are written as human-readable strings — e.g.
"age > 30 && name is-one-of [Alice, Bob]" — parsed once at build time,
and then evaluated at zero-allocation cost against any number of objects.
§Quick start
§1. Implement Attributes for your type
Declare one AttributeIndex constant per field and implement the three
trait methods:
use whereexpr::{Attributes, AttributeIndex, Value, ValueKind};
struct Person {
name: String,
age: u32,
}
impl Person {
const NAME: AttributeIndex = AttributeIndex::new(0);
const AGE: AttributeIndex = AttributeIndex::new(1);
}
impl Attributes for Person {
const TYPE_ID: u64 = 0x517652f2; // unique ID for Person type (a hash or other unique identifier)
const TYPE_NAME: &'static str = "Person";
fn get(&self, idx: AttributeIndex) -> Option<Value<'_>> {
match idx {
Self::NAME => Some(Value::String(&self.name)),
Self::AGE => Some(Value::U32(self.age)),
_ => None,
}
}
fn kind(idx: AttributeIndex) -> Option<ValueKind> {
match idx {
Self::NAME => Some(ValueKind::String),
Self::AGE => Some(ValueKind::U32),
_ => None,
}
}
fn index(name: &str) -> Option<AttributeIndex> {
match name {
"name" => Some(Self::NAME),
"age" => Some(Self::AGE),
_ => None,
}
}
}§2. Build an expression
Use ExpressionBuilder to register named conditions, then compile them
into a reusable Expression with a boolean expression string:
let expr = ExpressionBuilder::<Person>::new()
.add("has_name", Condition::from_str("name is-one-of [Alice, Bob] {ignore-case}"))
.add("is_adult", Condition::from_str("age >= 18"))
.build("has_name && is_adult")
.unwrap();§3. Evaluate
Call Expression::matches to test any object:
let people = vec![
Person { name: "Alice".into(), age: 30 },
Person { name: "Charlie".into(), age: 25 },
];
let matches: Vec<_> = people.iter().filter(|p| expr.matches(*p)).collect();
// → only Alice§Core concepts
| Type | Role |
|---|---|
Attributes | Trait your struct implements to expose its fields |
AttributeIndex | Opaque index that identifies a field |
Value | The runtime value of a field (tagged union) |
ValueKind | The type tag of a field (no data) |
Condition | Maps one attribute to a Predicate |
Predicate | A compiled single-field test (operation + reference value) |
Operation | The comparison operator (is, >, contains, glob, …) |
ExpressionBuilder | Fluent builder: registers conditions and compiles the boolean expression |
Expression | The compiled, reusable filter — call .matches(&obj) to evaluate |
Error | All errors that can occur during building or predicate construction |
§Condition string syntax
A condition string has the form:
<attribute> <operation> <value> [<modifiers>]Single value:
age > 30
name is Alice
status is-not deleted
filename ends-with .log
path glob /var/log/**/*.logList value (one or more comma-separated entries in [ ]):
status is-one-of [active, pending, paused]
extension ends-with-one-of [.jpg, .jpeg, .png]
message contains-one-of [error, fatal, critical]Range (exactly two values in [ ]):
age in-range [18, 65]
score not-in-range [0, 10]
port in-range [1024, 65535]Modifiers (appended in { }):
name is-one-of [alice, bob] {ignore-case}
path starts-with /Home {ignore-case}§Boolean expression syntax
The string passed to ExpressionBuilder::build combines named conditions
using standard boolean operators:
| Operator | Aliases | Example |
|---|---|---|
| AND | &&, AND | cond_a && cond_b |
| OR | ||, OR | cond_a || cond_b |
| NOT | !, NOT | !cond_a |
| Grouping | ( ) | (cond_a || cond_b) && cond_c |
&& and || cannot be mixed at the same nesting level without
parentheses — this is intentional to avoid precedence ambiguity:
// ✗ error: mixed operators
cond_a && cond_b || cond_c
// ✓ ok: grouped explicitly
(cond_a && cond_b) || cond_c
cond_a && (cond_b || cond_c)§Available operations
See Operation for the full list with per-variant aliases and examples.
| Family | Operations |
|---|---|
| Equality | is, is-not |
| Membership | is-one-of, is-not-one-of |
| String prefix | starts-with, not-starts-with, starts-with-one-of, not-starts-with-one-of |
| String suffix | ends-with, not-ends-with, ends-with-one-of, not-ends-with-one-of |
| Substring | contains, not-contains, contains-one-of, not-contains-one-of |
| Glob pattern | glob, not-glob |
| Numeric | >, >=, <, <=, in-range, not-in-range |
§Supported value types
See Value and ValueKind for details. In brief:
String, Path, u8–u64, i8–i64, f32, f64,
Hash128, Hash160, Hash256, IpAddr, DateTime (Unix timestamp),
Bool.
§Feature flags
| Flag | Effect |
|---|---|
error_description | Implements std::fmt::Display for Error, providing annotated error messages with ^ underlines pointing at the problematic token. |
enable_type_check | Enables type checking at runtime. This is useful for debugging and for ensuring that the correct type is used when evaluating an expression. |
Structs§
- Attribute
Index - An opaque, zero-cost index that uniquely identifies an attribute within a
type that implements
Attributes. - Condition
- A single condition that maps one attribute of a type
Tto aPredicate. - Expression
- A compiled, type-safe boolean expression that can be evaluated against objects
implementing
Attributes. - Expression
Builder - A builder for constructing a type-safe
Expression. - Predicate
- A compiled, type-erased test that evaluates a single
Valueagainst anOperationand a reference value (or list of reference values).
Enums§
- Error
- All errors that can be returned by
ExpressionBuilder::buildor byPredicateconstructors. - Operation
- The comparison operation used in a condition.
- Value
- A runtime value returned by
Attributes::getfor a specific field of typeT. - Value
Kind - The type tag of a
Value, without carrying any data.
Traits§
- Attributes
- Exposes the fields of a type
Tto the expression engine.