1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
//! HotDrink implemented in Rust. //! //! HotDrink lets you describe relations between values declaratively and how to enforce them, //! and can then automatically do so when the value of a variable changes. //! //! [![Crates.io][crates-badge]][crates-url] //! [![docs.rs](https://docs.rs/hotdrink-rs/badge.svg)](https://docs.rs/hotdrink-rs) //! //! [crates-badge]: https://img.shields.io/crates/v/hotdrink-rs.svg //! [crates-url]: https://crates.io/crates/hotdrink-rs //! //! # Introduction //! //! Before getting started, here is a quick introduction to the terminology and how it works. //! A [`Component`](crate::model::Component) is a set of variables with a set of [`Constraint`](crate::model::Constraint)s between them. //! A `Constraint` consists of a set of [`Method`](crate::model::Method)s that are essentially functions that enforce the constraint //! by reading from some subset of the variables of the `Component` and writing to another. //! `Components` can be gathered in a [`ConstraintSystem`](crate::model::ConstraintSystem), which provides an API //! for interacting with multiple `Component`s at once, such as [`update`](crate::model::ConstraintSystem::update). //! //! ## Components //! //! A *component* is a collection of variables and constraints between them that should be enforced. //! One can easily be created by using the [`component!`] macro, as shown in the example below. //! //! ## Constraints //! //! A *constraint* represents a relation between variables we want to maintain. //! It contains a collection of *constraint satisfaction methods* that describe the different ways to do so. //! In the example, we want the relation `a + b = c` to hold at all times. //! One way to enforce it is to re-compute `a + b` and set `c` to that value. //! //! ## Methods //! //! A *constraint satisfaction method* describes one way to enforce a constraint. //! It reads the values of some variables, and write to others. //! //! ## Usage //! //! Add the following to your `Cargo.toml`: //! //! ```text //! hotdrink-rs = "0.1.1" //! ``` //! //! Then you are ready to begin! //! //! ```rust //! use hotdrink_rs::{component, model::ConstraintSystem, ret, Event}; //! //! // Define a set of variables and relations between them //! let mut component = component! { //! // Define a component `Component`. //! component Component { //! // Define variables and their default values. //! // The value can be omitted for any type that implements `Default`. //! let a: i32 = 0, b: i32, c: i32 = 3; //! // Define a constraint `Sum` that must hold between variables. //! constraint Sum { //! // Provide three ways to enforce the constraint. //! // Only one will be selected, so each one *MUST* enforce the constraint. //! abc(a: &i32, b: &i32) -> [c] = ret![*a + *b]; //! acb(a: &i32, c: &i32) -> [b] = ret![*c - *a]; //! bca(b: &i32, c: &i32) -> [a] = ret![*c - *b]; //! } //! } //! }; //! //! // Describe what should happen when `a` changes. //! component.subscribe("a", |event| match event { //! Event::Pending => println!("A new value for `a` is being computed"), //! Event::Ready(value) => println!("New value for `a`: {}", value), //! Event::Error(errors) => println!("Computation for `a` failed: {:?}", errors), //! }); //! //! // Change the value of `a` //! component.set_variable("a", 3); //! //! // Enforce all the constraints by selecting a method for each one, //! // and then executing the methods in topological order. //! component.update(); //! //! // Add the component to a constraint system. //! // One constraint system can contain many components. //! let mut cs = ConstraintSystem::new(); //! cs.add_component(component); //! //! // Update every component in the constraint system. //! cs.update(); //! ``` //! //! # Examples //! //! The project uses multiple nightly features, and must be built using nightly Rust. //! I recommend using `rustup`, which can be downloaded [here](https://rustup.rs/). //! //! The examples in `./examples` can then be run with `cargo run --example <name>`. #![warn( missing_copy_implementations, missing_debug_implementations, rust_2018_idioms, missing_docs )] #![feature(test)] #![feature(result_flattening)] #![feature(stmt_expr_attributes)] #![feature(drain_filter)] #![feature(concat_idents)] #![feature(vec_into_raw_parts)] #[macro_use] pub mod macros; pub mod builders; pub(crate) mod event; pub mod examples; pub mod model; pub mod planner; pub mod solver; pub mod thread; pub mod util; pub(crate) mod variable_ranking; pub use event::Event;