Skip to main content

token_value_map/
lib.rs

1//! A time-based data mapping library for animation and interpolation.
2//!
3//! This crate provides types for storing and manipulating data that changes
4//! over time. It supports both uniform (static) and animated (time-varying)
5//! values with automatic interpolation between keyframes.
6//!
7//! # Core Types
8//!
9//! - [`Token`]: A string key type wrapping [`Ustr`](ustr::Ustr) (with `ustr`
10//!   feature) or [`String`] (without) used for lookups.
11//! - [`Value`]: A value that can be either uniform or animated over time.
12//! - [`Data`]: A variant enum containing all supported data types.
13//! - [`AnimatedData`]: Time-indexed data with interpolation support.
14//! - [`TimeDataMap`]: A mapping from time to data values.
15//! - [`TokenValueMap`]: A collection of named values indexed by tokens.
16//!
17//! # Data Types
18//!
19//! The library supports scalar types ([`Boolean`], [`Integer`], [`Real`],
20//! [`String`]), vector types ([`Vector2`], [`Vector3`], [`Color`],
21//! [`Matrix3`]), and collections of these types ([`BooleanVec`],
22//! [`IntegerVec`], etc.).
23//!
24//! # Motion Blur Sampling
25//!
26//! Use the [`Sample`] trait with a [`Shutter`] to generate motion blur samples
27//! for animated values during rendering.
28//!
29//! # Interpolation (Optional Feature)
30//!
31//! When the `interpolation` feature is enabled, [`TimeDataMap`] supports
32//! advanced interpolation modes including bezier curves with tangent control.
33//! This enables integration with professional animation systems like Dopamine.
34//!
35//! # Curve Types (Optional `curves` Feature)
36//!
37//! When the `curves` feature is enabled (on by default), the crate provides
38//! [`RealCurve`] and [`ColorCurve`] types for position-keyed parameter
39//! mappings. These use [`KeyDataMap<Position, T>`](KeyDataMap) under the hood,
40//! where [`Position`] is a normalized \[0, 1\] key type.
41//!
42//! ```rust
43//! use token_value_map::*;
44//!
45//! // Create a falloff curve: ramps linearly from 0 → 1.
46//! let curve = RealCurve::linear();
47//! assert_eq!(curve.evaluate(0.0), 0.0);
48//! assert_eq!(curve.evaluate(1.0), 1.0);
49//!
50//! // Create a black-to-white color gradient.
51//! let gradient = ColorCurve::black_to_white();
52//! let mid = gradient.evaluate(0.5);  // ~[0.5, 0.5, 0.5, 1.0]
53//! assert!(mid[0] > 0.4 && mid[0] < 0.6);
54//! ```
55//!
56//! # Examples
57//!
58//! ```rust
59//! use frame_tick::Tick;
60//! use token_value_map::*;
61//!
62//! // Create a uniform value.
63//! let uniform = Value::uniform(42.0);
64//!
65//! // Create an animated value.
66//! let animated =
67//!     Value::animated(vec![(Tick::new(0), 0.0), (Tick::new(10), 10.0)])
68//!         .unwrap();
69//!
70//! // Sample at a specific time.
71//! let interpolated = animated.interpolate(Tick::new(5));
72//! ```
73
74// AIDEV-NOTE: trivial_bounds is required because BTreeMap1 (from mitsein) generates
75// rkyv derive bounds that the compiler considers trivially true. Without this feature
76// gate, `cargo check --features rkyv` fails on AnimatedData's derived impls.
77#![cfg_attr(feature = "rkyv", feature(trivial_bounds))]
78
79#[cfg(feature = "facet")]
80use facet::Facet;
81#[cfg(feature = "builtin-types")]
82use function_name::named;
83#[cfg(feature = "rkyv")]
84use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
85#[cfg(feature = "serde")]
86use serde::{Deserialize, Serialize};
87use smallvec::SmallVec;
88use std::fmt::Debug;
89use std::hash::Hash;
90#[cfg(feature = "builtin-types")]
91use std::hash::Hasher;
92
93// Internal macro module.
94#[cfg(feature = "builtin-types")]
95mod macros;
96#[cfg(feature = "builtin-types")]
97use macros::impl_sample_for_value;
98
99// Math backend abstraction.
100#[cfg(feature = "builtin-types")]
101pub mod math;
102
103// Built-in types (feature-gated).
104#[cfg(feature = "builtin-types")]
105mod animated_data;
106#[cfg(feature = "builtin-types")]
107mod data;
108#[cfg(feature = "builtin-types")]
109mod data_types;
110#[cfg(feature = "builtin-types")]
111mod token_value_map;
112#[cfg(feature = "builtin-types")]
113mod value;
114
115// Generic types (always available).
116mod define_data_macro;
117mod generic_token_value_map;
118mod generic_value;
119mod traits;
120
121// Position type for curve domains.
122#[cfg(feature = "curves")]
123mod position;
124
125// Token type.
126mod token;
127
128// Other modules.
129#[cfg(feature = "egui-keyframe")]
130mod egui_keyframe_integration;
131mod error;
132#[cfg(feature = "interpolation")]
133mod interpolation;
134#[cfg(all(feature = "lua", feature = "builtin-types"))]
135mod lua;
136mod shutter;
137mod time_data_map;
138
139// Re-exports: built-in types (feature-gated).
140#[cfg(feature = "builtin-types")]
141pub use animated_data::*;
142#[cfg(feature = "builtin-types")]
143pub use data::*;
144#[cfg(feature = "builtin-types")]
145pub use data_types::*;
146#[cfg(feature = "builtin-types")]
147pub use token_value_map::*;
148#[cfg(feature = "builtin-types")]
149pub use value::*;
150
151// Re-exports: always available.
152pub use error::*;
153pub use generic_token_value_map::*;
154pub use generic_value::*;
155#[cfg(feature = "interpolation")]
156pub use interpolation::*;
157#[cfg(all(feature = "lua", feature = "builtin-types"))]
158pub use lua::*;
159#[cfg(feature = "curves")]
160pub use position::*;
161pub use shutter::*;
162pub use time_data_map::*;
163pub use token::*;
164pub use traits::*;
165
166/// A time value represented as a fixed-point [`Tick`](frame_tick::Tick).
167pub type Time = frame_tick::Tick;
168
169/// Trait for getting data type information.
170///
171/// This trait is only available with the `builtin-types` feature.
172#[cfg(feature = "builtin-types")]
173pub trait DataTypeOps {
174    /// Returns the [`DataType`] variant for this value.
175    fn data_type(&self) -> DataType;
176    /// Returns a string name for this data type.
177    fn type_name(&self) -> &'static str;
178}
179
180#[cfg(feature = "builtin-types")]
181impl DataTypeOps for Value {
182    fn data_type(&self) -> DataType {
183        match self {
184            Value::Uniform(data) => data.data_type(),
185            Value::Animated(animated_data) => animated_data.data_type(),
186        }
187    }
188
189    fn type_name(&self) -> &'static str {
190        match self {
191            Value::Uniform(data) => data.type_name(),
192            Value::Animated(animated_data) => animated_data.type_name(),
193        }
194    }
195}