Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting Started

This chapter takes a small eligibility rule from a closure to a reusable, typed decision. The complete static version is also available as static_composition.rs.

Add the core crate to an application:

[dependencies]
specification-core = "0.1"

Specification<T> evaluates a borrowed candidate. A closure with the shape Fn(&T) -> bool implements the trait automatically, so a small rule needs no boilerplate type.

use specification_core::Specification;

struct User {
    age: u8,
    verified: bool,
}

let is_adult = |user: &User| user.age >= 18;
let is_verified = |user: &User| user.verified;
let eligible = is_adult.and(is_verified);

let user = User { age: 21, verified: true };
assert!(eligible.is_satisfied_by(&user));

eligible is a concrete And<...> value. The static composition path does not allocate or use dynamic dispatch, and and/or short-circuit from left to right. Rust receives &user because evaluation borrows the candidate rather than taking ownership of it.

use specification_core::Specification;

let is_adult = |age: &u8| *age >= 18;
let is_retired = |age: &u8| *age >= 65;
let working_age = is_adult.and(is_retired.not());

assert!(working_age.is_satisfied_by(&42));
assert!(!working_age.is_satisfied_by(&70));

AllOf and AnyOf apply the same behavior to a borrowed homogeneous slice; their empty identities are true and false, respectively.

Where to go next

The rust,ignore blocks in this book are illustrative because mdBook does not link standalone snippets to the workspace. Every complete workflow is backed by a Cargo example, integration test, or compiled rustdoc example; links to those sources are provided in the relevant chapter.