Skip to main content

Module calc

Module calc 

Source
Expand description

Size expressions: CSS’s min(), max() and clamp() over lengths and percentages, resolved by layout against the parent’s content box (the same box a Percent sizing takes its cut of).

size   := number ["px"] | number "%" | fn "(" size ("," size)* ")"
fn     := "min" | "max" | "clamp"         -- clamp takes exactly three
number := digits ["." digits] | "." digits  -- no sign, no exponent

As CSS reads it: a unit straight after its number (80 % is refused), a function’s ( straight after its name, names and px in any case, and whitespace free around the commas and inside the parentheses. "clamp(400px, 80%, 1000px)" is 80% of the room, never under 400 nor over 1000, and, as CSS has it, the minimum wins when it is over the maximum. An expression with no percentage in it is a length ("min(300px, 400)" is Fixed(300)), a bare percentage is a Percent, and only what depends on the room becomes a Calc.

use kui_core::{NodeSpec, Sizing, calc};

let w = calc::sizing("clamp(400px, 80%, 1000px)").unwrap();
assert!(matches!(w, Sizing::Calc(_)));
assert_eq!(calc::sizing("min(300px, 400)").unwrap(), Sizing::Fixed(300.0));

let pane = NodeSpec::column().width(w).max_width(calc::bound("50%").unwrap());
if let Sizing::Calc(c) = pane.layout.width {
    assert_eq!(c.resolve(1500.0), 1000.0); // 80% of 1500 is capped
    assert_eq!(c.resolve(200.0), 400.0);   // and floored
}

The same expression as data, for a binding that would rather not spell it (from_value): a number is px, { pct = N } (or { percent: N } in JS) a percentage, { px = N } a length, and a function a one-key table of its arguments. Rust builds one with Expr and intern.

A Calc is a handle. LayoutSpec is Copy and copied per node per frame, so the tree it names lives in a process-wide table, one entry per distinct expression, which a frame that declares the same expression again finds rather than adds to. The table holds at most MAX_CALCS entries and never lets one go: a program that reaches the cap is spelling a new expression per frame (format!("clamp({n}px, ..)") fed a drag). Past it a new expression is refused with FULL in its error, which every binding reads as the prop left undeclared, and a crate::diag::SIZE_EXPRESSIONS_FULL warning says so. An expression already kept still resolves.

Structs§

Calc
An expression that depends on the room, by its place in the table. Copy, so a Sizing holding one still is.

Enums§

Expr
A parsed expression: lengths in logical px, percentages as fractions.

Constants§

FULL
What the error of an expression refused for want of room in the table starts with, under whatever a binding put before it: see is_full.
MAX_CALCS
How many distinct expressions the table keeps.
MAX_DEPTH
How deep an expression nests: at most this many functions inside one another, whatever built it — the grammar, data, prefix code, C’s builders or a Rust tree handed to intern. Every walk of a tree (evaluating, hashing, comparing, spelling, dropping) recurses, so a tree the table keeps is one those walks can finish.

Functions§

bound
What a spelling is as a clamp: a length, or a Calc for one that depends on the room.
bound_code
A size expression in prefix code, as a clamp.
bound_value
A size expression as data, as a clamp.
from_code
A size expression in prefix code, the form a transport that carries only numbers sends (the Node wire’s SIZE_MODE_TREE, v19): 1 px, 2 fraction, 3 n args… (min), 4 n args… (max), 5 a b c (clamp). The whole slice is one expression.
from_value
A size expression as data (see the module’s doc): a number, a string, { pct } / { percent } / { px }, or a one-key { min | max | clamp = [args] }.
intern
The handle for expr: the one an equal expression already has, or a new one.
is_full
Whether err is a refusal for want of room (FULL), not a bad spelling: a binding leaves the prop at its default on one — the expression was fine, the process has spelled too many — and fails on the other.
parse
Parses a size expression; the public grammar, which a host validating its own settings reuses so what it accepts is what kui draws.
refused
How many new expressions the table has refused since the process started, with the last one spelled.
sizing
What a spelling is as a sizing: a length, a percentage, or a Calc for anything else.
sizing_code
A size expression in prefix code, as a sizing.
sizing_of
An expression tree built by hand, as a sizing: C’s builders and a Rust view that composes one.
sizing_value
A size expression as data, as a sizing.