Skip to main content

ph_curves/
lib.rs

1//! `no_std`, zero-allocation curve lookup tables and tickless scheduling for
2//! embedded Rust.
3//!
4//! `ph-curves` stores pre-computed forward (and optionally inverse) lookup
5//! tables as `static` arrays so that curve evaluation reduces to a single
6//! array index.  Combined with the tickless scheduler, interrupt-driven
7//! firmware can sleep between value transitions instead of polling at a
8//! fixed tick rate.
9//!
10//! # Quick start
11//!
12//! Use the companion CLI (`ph-curves-gen`) to generate `static` LUTs from a
13//! TOML definition file, then `include!` the output in your crate:
14//!
15//! ```ignore
16//! use ph_curves::{Curve, MonotonicCurve, Tickless, Rounding};
17//!
18//! include!("curves.rs");
19//!
20//! // Forward evaluation — a single table lookup.
21//! let brightness: u8 = GAMMA_22.eval(input);
22//!
23//! // Inverse lookup (monotonic curves only).
24//! let input: u8 = GAMMA_22.inv(brightness);
25//!
26//! // Tickless scheduling — sleep until the next quantized value change.
27//! let schedule = EASE_IN_QUAD.tickless_schedule(
28//!     0,     // t0_ms
29//!     1000,  // duration_ms
30//!     0,     // start_val
31//!     255,   // end_val
32//!     10,    // step (quantization)
33//!     Rounding::Nearest,
34//!     0,     // min_dt_ms
35//! );
36//!
37//! for deadline in schedule.iter(0) {
38//!     set_timer(deadline.deadline_ms);
39//!     set_output(deadline.current_val);
40//! }
41//! ```
42//!
43//! # Key types
44//!
45//! Everything is re-exported at the crate root.
46//!
47//! - **Curves** — [`Curve`] / [`MonotonicCurve`] traits and the LUT-backed
48//!   [`CurveLut`] / [`MonotonicCurveLut`] types.
49//! - **Tickless scheduling** — [`Tickless`] extension trait,
50//!   [`TicklessSchedule`], and the [`TicklessIter`] iterator.
51//! - **Math helpers** — [`UnitValue`] trait, [`lerp_u8`], [`lerp_u16`],
52//!   [`map_u8_to_u16`], [`quantize`], and [`next_target_value`].
53
54#![no_std]
55#![deny(missing_docs)]
56#![allow(unsafe_code)]
57#![deny(unsafe_op_in_unsafe_fn)]
58// Clippy lint levels live here; thresholds and config are in clippy.toml.
59#![deny(clippy::correctness)]
60#![warn(
61    clippy::suspicious,
62    clippy::style,
63    clippy::complexity,
64    clippy::perf,
65    clippy::cloned_instead_of_copied,
66    clippy::explicit_iter_loop,
67    clippy::implicit_clone,
68    clippy::inconsistent_struct_constructor,
69    clippy::manual_assert,
70    clippy::manual_let_else,
71    clippy::match_same_arms,
72    clippy::needless_pass_by_value,
73    clippy::semicolon_if_nothing_returned,
74    clippy::uninlined_format_args,
75    clippy::unnested_or_patterns,
76    clippy::std_instead_of_core,
77    clippy::std_instead_of_alloc,
78    clippy::alloc_instead_of_core
79)]
80#![allow(
81    clippy::mod_module_files,
82    clippy::self_named_module_files,
83    clippy::similar_names,
84    clippy::too_many_arguments,
85    clippy::struct_excessive_bools,
86    clippy::fn_params_excessive_bools,
87    clippy::type_complexity,
88    clippy::must_use_candidate,
89    clippy::assertions_on_constants,
90    clippy::cast_possible_truncation,
91    clippy::cast_possible_wrap,
92    clippy::cast_sign_loss,
93    clippy::cast_precision_loss,
94    clippy::cast_lossless,
95    clippy::panic_in_result_fn,
96    clippy::unwrap_used,
97    clippy::expect_used,
98    clippy::module_name_repetitions,
99    clippy::wildcard_imports,
100    clippy::items_after_statements,
101    clippy::let_underscore_future
102)]
103
104mod curve;
105mod math;
106mod tickless;
107
108pub use curve::{
109    Curve, CurveLut, CurveLut256, CurveLut65536, MonotonicCurve, MonotonicCurveLut,
110    MonotonicCurveLut256, MonotonicCurveLut65536,
111};
112pub use math::{
113    Rounding, UnitValue, lerp_u8, lerp_u16, map_u8_to_u16, next_target_value, quantize,
114};
115pub use tickless::{RepeatMode, Tickless, TicklessDeadline, TicklessIter, TicklessSchedule};
116
117#[cfg(test)]
118mod tests;