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;