fable
fable is a tiny typed language for inspecting and mutating
facet-reflected Rust values, then lowering toward canonical
Weavy IR. You write a small script that navigates a
struct by field name and assigns or tests scalar values; fable resolves every
path against the Facet shape at compile time, type-checks the expressions, and
produces a reusable bytecode plan that runs directly against a live &mut T
without any serialization round-trip.
The crate owns the syntax layer through a snark grammar and generated typed AST, plus the lowering and interpreter that compiles source to Weavy IR and executes it against Facet-reflected Rust values.
use facet:: Facet ;
use fable::{ FablePlan , FablePredicatePlan , FableQueryPlan , apply};
# [ derive ( Facet )]
struct Config {
name : String ,
max_retries : u32 ,
threshold : f64 ,
}
fn main () -> Result <(), Box < dyn std:: error:: Error >> {
let mut cfg = Config {
name : " acme " . into (),
max_retries : 100 ,
threshold : 0.5 ,
};
// Compile once, apply many times.
let plan = FablePlan ::< Config >:: compile (
r#"
root.name = trim(root.name);
root.max_retries = clamp(root.max_retries, 1, 10);
if root.threshold > 1.0 {
root.threshold = 1.0;
}
"# ,
) ?;
plan. apply ( & mut cfg) ?;
// One-shot convenience wrapper.
apply ( & mut cfg, r#"root.name = root.name + "-v2";"# ) ?;
let acceptable = FablePredicatePlan ::< Config >:: compile (
r#"root.max_retries <= 10 and root.threshold <= 1.0"# ,
) ?
. evaluate ( & cfg) ?;
assert! ( acceptable);
let label = FableQueryPlan ::< Config , String >:: compile (
r#"root.name + ":" + len(root.name)"# ,
) ?
. evaluate ( & cfg) ?;
assert_eq! ( label, "acme-v2:7" );
Ok (())
} How it fits with Facet and Weavy
Fable sits between the two: it reads struct layouts from facet-core
reflection (Shape, field offsets, scalar types) and emits Weavy IR
that the Weavy interpreter executes. Because field paths are resolved at
FablePlan::compile time, repeated apply calls pay only interpreter cost —
no parsing, no field lookup.
Supported scalar types cover the full Rust numeric tower (i8–i128, u8–u128,
f32, f64), bool, char, String, and Cow<str>. Built-in intrinsics
include min, max, clamp, len, trim, contains, starts_with, and
ends_with.
For read-only validation, filtering, and inspection, FablePredicatePlan<T> and
FableQueryPlan<T, Output> compile a source file whose final top-level
statement is the returned expression. Earlier statements can bind typed locals,
so predicates and queries share the same lowering and Weavy execution path as
mutating scripts and in to out transforms.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.