Skip to main content

Module query

Module query 

Source
Available on crate feature query only.
Expand description

Predicates and cardinality helpers for native iterators.

Start with a replayable collection, borrow it with .iter(), and keep inline closures on native Iterator::filter. Use QueryIteratorExt::matching for a named Matcher or typed FilterExpr, then apply exact cardinality without collecting or exhausting more than two items:

use libtmux::query::{Matcher, QueryIteratorExt};

struct IsPending;

impl Matcher<(&'static str, bool)> for IsPending {
    fn matches(&self, candidate: &(&'static str, bool)) -> bool {
        !candidate.1
    }
}

let tasks = vec![("build", false), ("test", true)];
let visible = tasks.iter().filter(|task| task.0.starts_with('b'));
assert_eq!(visible.collect::<Vec<_>>(), vec![&tasks[0]]);
assert_eq!(tasks.iter().matching(IsPending).exactly_one(), Ok(&tasks[0]));

QueryIteratorExt::exactly_one distinguishes zero from multiple items; QueryIteratorExt::one_or_none permits zero but rejects multiple items. Both preserve the iterator’s item type and pull at most two items. To take ownership, use .into_iter() with QueryIteratorExt::matching_owned; selected values need not be Clone.

Portable expressions are owned, inert local values. With derive, typed handles can be generated for downstream data without exposing the hidden expansion constructors:

use libtmux::query::{Filterable as _, QueryIteratorExt as _};

#[derive(libtmux::Filterable)]
#[filterable(target = "task")]
struct Task {
    name: String,
    done: bool,
}

let tasks = vec![Task { name: "build".into(), done: false }];
let fields = Task::filter_fields();
let expression = fields.name.eq("build").and(fields.done.eq(false));
assert_eq!(tasks.iter().matching(&expression).count(), 1);

Local matching is synchronous, ordered, and never performs tmux I/O or native pushdown. Text predicates require strict candidate UTF-8, so every text predicate returns false for invalid bytes, including not_in([]); an outer FilterExpr::not may invert that result. Relations inspect only already-hydrated candidate data: empty to-many data makes any false and all and none true, while absent to-one data makes is false.

The optional derive and serde features are independent. Serde uses the closed version 1 grammar, whose membership values are arrays even though Rust authoring accepts any IntoIterator. Decoding accepts at most 64 expression levels, 4,096 expression nodes, and 4,096 membership values. Regex operators use Rust syntax and reject Python-only look-around and backreferences with source-less, value-free errors. Dynamic field__operator parsing and remote pushdown belong to later ingress and execution layers.

Scalar field handles expose only operators valid for their field type. A boolean field rejects string equality and membership:

ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.eq("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.is_in(["true"]);
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.not_in(["true"]);

Boolean fields also have none of the text-only operators:

ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.eq_ignore_case("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.contains("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.contains_ignore_case("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.starts_with("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.starts_with_ignore_case("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.ends_with("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.ends_with_ignore_case("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.regex("true");
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::bool_field::<Row>("row", "done");
let _ = field.regex_ignore_case("true");

Platform-width integers are intentionally outside the portable grammar:

ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::integer_field::<Row, isize>("row", "count");
let _ = field.eq(0_isize);
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::integer_field::<Row, isize>("row", "count");
let _ = field.is_in([0_isize]);
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::integer_field::<Row, isize>("row", "count");
let _ = field.not_in([0_isize]);
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::integer_field::<Row, usize>("row", "count");
let _ = field.eq(0_usize);
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::integer_field::<Row, usize>("row", "count");
let _ = field.is_in([0_usize]);
ⓘ
use libtmux::query::__private;

struct Row;
let field = __private::integer_field::<Row, usize>("row", "count");
let _ = field.not_in([0_usize]);

Relation handles accept only portable expressions for their related type, never closures or arbitrary matchers:

ⓘ
use libtmux::query::__private;

struct Parent;
struct Child;
let relation = __private::many_relation::<Parent, Child>("parent", "children");
let _ = relation.any(|_: &Child| true);
ⓘ
use libtmux::query::{Matcher, OneRelation};
use libtmux::query::__private;

struct Parent;
struct Child;
struct ChildMatcher;
impl Matcher<Child> for ChildMatcher {
    fn matches(&self, _: &Child) -> bool { true }
}
let relation: OneRelation<Parent, Child> =
    __private::one_relation("parent", "child");
let _ = relation.is(ChildMatcher);

A relation expression cannot cross related schemas:

ⓘ
use libtmux::query::{FilterExpressionError, Filterable};
use libtmux::query::__private::{self, Predicate};

struct Parent;
struct Child;
struct Other;
macro_rules! filterable {
    ($type:ty, $target:literal) => {
        impl Filterable for $type {
            type Fields = ();
            const FILTER_TARGET: &'static str = $target;
            fn filter_fields() {}
            fn __filter_matches(&self, _: &Predicate) -> bool { false }
            fn __filter_validate(_: &Predicate) -> Result<(), FilterExpressionError> {
                Ok(())
            }
        }
    };
}
filterable!(Child, "child");
filterable!(Other, "other");
let relation = __private::many_relation::<Parent, Child>("parent", "children");
let other = __private::bool_field::<Other>("other", "enabled").eq(true);
let _ = relation.any(other);
ⓘ
use libtmux::query::{FilterExpressionError, Filterable};
use libtmux::query::__private::{self, Predicate};

struct Parent;
struct Child;
struct Other;
macro_rules! filterable {
    ($type:ty, $target:literal) => {
        impl Filterable for $type {
            type Fields = ();
            const FILTER_TARGET: &'static str = $target;
            fn filter_fields() {}
            fn __filter_matches(&self, _: &Predicate) -> bool { false }
            fn __filter_validate(_: &Predicate) -> Result<(), FilterExpressionError> {
                Ok(())
            }
        }
    };
}
filterable!(Child, "child");
filterable!(Other, "other");
let relation = __private::one_relation::<Parent, Child>("parent", "child");
let other = __private::bool_field::<Other>("other", "enabled").eq(true);
let _ = relation.is(other);

To-many and to-one relations expose disjoint quantifier families:

ⓘ
use libtmux::query::__private;

struct Parent;
struct Child;
let relation = __private::many_relation::<Parent, Child>("parent", "children");
let child = __private::bool_field::<Child>("child", "enabled").eq(true);
let _ = relation.is(child);
ⓘ
use libtmux::query::__private;

struct Parent;
struct Child;
let relation = __private::one_relation::<Parent, Child>("parent", "child");
let child = __private::bool_field::<Child>("child", "enabled").eq(true);
let _ = relation.any(child);
ⓘ
use libtmux::query::__private;

struct Parent;
struct Child;
let relation = __private::one_relation::<Parent, Child>("parent", "child");
let child = __private::bool_field::<Child>("child", "enabled").eq(true);
let _ = relation.all(child);
ⓘ
use libtmux::query::__private;

struct Parent;
struct Child;
let relation = __private::one_relation::<Parent, Child>("parent", "child");
let child = __private::bool_field::<Child>("child", "enabled").eq(true);
let _ = relation.none(child);

Expression error kinds are non-exhaustive for downstream callers:

ⓘ
use libtmux::query::FilterExpressionErrorKind;

fn label(kind: FilterExpressionErrorKind) -> &'static str {
    match kind {
        FilterExpressionErrorKind::InvalidRegex => "invalid regex",
        FilterExpressionErrorKind::UnsupportedVersion => "unsupported version",
        FilterExpressionErrorKind::InvalidTarget => "invalid target",
        FilterExpressionErrorKind::UnknownField => "unknown field",
        FilterExpressionErrorKind::UnknownOperator => "unknown operator",
        FilterExpressionErrorKind::UnknownQuantifier => "unknown quantifier",
        FilterExpressionErrorKind::InvalidLiteral => "invalid literal",
        FilterExpressionErrorKind::InvalidStructure => "invalid structure",
    }
}

Structs§

BoolField
A typed handle for a portable boolean field on T.
EnumField
A typed handle for a custom enum field E on T.
FilterExpr
An opaque, portable predicate over candidates of type T.
FilterExpressionError
A source-less, value-free portable expression validation error.
IntegerField
A typed handle for a fixed-width integer field N on T.
ManyRelation
A value-only handle for a to-many relation from From to To.
MultipleItemsError
An error indicating that an iterator contained more than one item.
OneRelation
A value-only handle for a to-one relation from From to To.
TextField
A typed handle for a portable text field on T.

Enums§

ExactlyOneError
The ways an iterator can fail to contain exactly one item.
FilterExpressionErrorKind
The category of an invalid portable filter expression.

Traits§

FilterEnum
Stable string semantics for a custom enum filter field.
FilterSchema
A filter target whose portable expression grammar can be described.
Filterable
A type with a stable schema that can evaluate portable filter predicates.
Matcher
A predicate that evaluates a borrowed candidate.
QueryIteratorExt
Cardinality and named-predicate operations for native iterators.
ReadField
A field handle whose value a Target snapshot holds.