Skip to main content

Crate whereexpr

Crate whereexpr 

Source
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

TypeRole
AttributesTrait your struct implements to expose its fields
AttributeIndexOpaque index that identifies a field
ValueThe runtime value of a field (tagged union)
ValueKindThe type tag of a field (no data)
ConditionMaps one attribute to a Predicate
PredicateA compiled single-field test (operation + reference value)
OperationThe comparison operator (is, >, contains, glob, …)
ExpressionBuilderFluent builder: registers conditions and compiles the boolean expression
ExpressionThe compiled, reusable filter — call .matches(&obj) to evaluate
ErrorAll 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/**/*.log

List 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:

OperatorAliasesExample
AND&&, ANDcond_a && cond_b
OR||, ORcond_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.

FamilyOperations
Equalityis, is-not
Membershipis-one-of, is-not-one-of
String prefixstarts-with, not-starts-with, starts-with-one-of, not-starts-with-one-of
String suffixends-with, not-ends-with, ends-with-one-of, not-ends-with-one-of
Substringcontains, not-contains, contains-one-of, not-contains-one-of
Glob patternglob, not-glob
Numeric>, >=, <, <=, in-range, not-in-range

§Supported value types

See Value and ValueKind for details. In brief: String, Path, u8u64, i8i64, f32, f64, Hash128, Hash160, Hash256, IpAddr, DateTime (Unix timestamp), Bool.


§Feature flags

FlagEffect
error_descriptionImplements std::fmt::Display for Error, providing annotated error messages with ^ underlines pointing at the problematic token.
enable_type_checkEnables type checking at runtime. This is useful for debugging and for ensuring that the correct type is used when evaluating an expression.

Structs§

AttributeIndex
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 T to a Predicate.
Expression
A compiled, type-safe boolean expression that can be evaluated against objects implementing Attributes.
ExpressionBuilder
A builder for constructing a type-safe Expression.
Predicate
A compiled, type-erased test that evaluates a single Value against an Operation and a reference value (or list of reference values).

Enums§

Error
All errors that can be returned by ExpressionBuilder::build or by Predicate constructors.
Operation
The comparison operation used in a condition.
Value
A runtime value returned by Attributes::get for a specific field of type T.
ValueKind
The type tag of a Value, without carrying any data.

Traits§

Attributes
Exposes the fields of a type T to the expression engine.