exprtk_rs/
lib.rs

1//! This crate provides bindings for the [ExprTk](http://www.partow.net/programming/exprtk/index.html)
2//! library.
3//!
4//! For an overview of the data structures [see the ExprTk main page](http://www.partow.net/programming/exprtk/index.html).
5//! While `exprtk-sys` maps most functions of the library to Rust, the high level bindings
6//! were considerably simplified. Each [Expression](struct.Expression.html) owns a
7//! [SymbolTable](struct.SymbolTable.html), they cannot be shared between different instances,
8//! and multiple symbol tables per expression are not possible.
9//!
10//! Variables are owned by the `SymbolTable` instance. The functions for adding variables
11//! ([add_variable()](exprtk/struct.SymbolTable.html#method.add_variable)), strings
12//! ([add_stringvar()](exprtk/struct.SymbolTable.html#method.add_stringvar)), vectors
13//! ([add_vector()](exprtk/struct.SymbolTable.html#method.add_vector)) all return
14//! `usize`, which is a _variable ID_ representing the index in of the value in
15//! an internal data structure. It can be used to later get symbol values and modify them.
16//! Scalars are either modified via mutable references, or via `std::cell::Cell` types without
17//! the requirement of mutable access to the `SymbolTable`.
18//! Strings are changed using [set_string()](exprtk/struct.SymbolTable.html#method.set_string),
19//! which requires mutable access.
20//! Since access and mutation through variable IDs requires a bounds check, these operations
21//! are slower than direct modification through pointers, as done in C++. The performance impact
22//! is naturally more severe for small expressions with fast running times, but seems not too
23//! problematic in most cases. Run `cargo bench` to see the impact (compare with unsafe variant).
24//! For each data type (scalars, strings and vectors), access IDs start at zero
25//! and are incremented on addition of new variables of the given type.
26//!
27//! As there is no guarantee that `double` is always `f64`, the `c_double` type is used all
28//! over the library. Other precisions are currently not supported.
29//!
30//! ExprTk does not handle non-ASCII encodings, therefore variable names and formulae are
31//! checked for non-ASCII characters or null bytes and will fail with an error.
32//!
33//! # Examples:
34//!
35//! This code corresponds to the [example 1](http://www.partow.net/programming/exprtk/index.html#simpleexample01)
36//! in the ExprTk documentation:
37//!
38//! ```no_run
39//! use exprtk_rs::*;
40//!
41//! let expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
42//!
43//! let mut symbol_table = SymbolTable::new();
44//! symbol_table.add_constants();
45//! let var_id = symbol_table.add_variable("x", 0.).unwrap().unwrap();
46//!
47//! let mut expression = Expression::new(expression_string, symbol_table).unwrap();
48//!
49//! // this value is a reference to a std::cell::Cell that can be changed
50//! expression.symbols().value_cell(var_id).set(-5.);
51//!
52//! while expression.symbols().value(var_id) <= 5. {
53//!     let y = expression.value();
54//!     println!("{}\t{}", expression.symbols().value(var_id), y);
55//!     *expression.symbols_mut().value_mut(var_id) += 0.001;
56//! }
57//! ```
58//!
59//! # Unknown variables
60//!
61//! Unknown variables encountered in an expression can be automatically added to the symbol table.
62//! The function `Expression::parse_vars` will return a `Vec` containing the newly added variable
63//! names and their variable IDs.
64//! This works only for regular variables, not for strings or vectors.
65//!
66//! ```
67//! use exprtk_rs::*;
68//!
69//! let expr_string = "a*x^2 + b*x + c";
70//!
71//! let (mut expr, unknown_vars) = Expression::parse_vars(expr_string, SymbolTable::new()).unwrap();
72//!
73//! assert_eq!(
74//!     unknown_vars,
75//!     vec![("a".to_string(), 0), ("x".to_string(), 1), ("b".to_string(), 2), ("c".to_string(), 3)]
76//! );
77//!
78//! // modify the values
79//! expr.symbols().value_cell(0).set(2.); // a
80//! expr.symbols().value_cell(2).set(3.); // b
81//! expr.symbols().value_cell(3).set(1.); // c
82//! expr.symbols().value_cell(1).set(5.); // x
83//!
84//! assert_eq!(expr.value(), 66.);
85//! ```
86//!
87//! # Example using strings
88//!
89//! ```
90//! use exprtk_rs::*;
91//!
92//! let mut symbol_table = SymbolTable::new();
93//! let s1_id = symbol_table.add_stringvar("s1", "Hello").unwrap().unwrap();
94//! let s2_id = symbol_table.add_stringvar("s2",  "world!").unwrap().unwrap();
95//!
96//! // concatenation
97//! let mut expr = Expression::new("s1 + ' ' + s2 == 'Hello world!'", symbol_table).unwrap();
98//! // a boolean `true` is represented by `1`
99//! assert_eq!(expr.value(), 1.);
100//!
101//! // Modifying a string
102//! expr.symbols_mut().set_string(s1_id, "");
103//! assert_eq!(expr.value(), 0.);
104//! ```
105//!
106//! # Functions
107//!
108//! There is currently the possibility to add functions/closures with up to ten scalar arguments.
109//! Example:
110//!
111//! ```
112//! use exprtk_rs::*;
113//!
114//! let mut symbol_table = SymbolTable::new();
115//! symbol_table.add_func2("add", |x, y| x + y);
116//! symbol_table.add_variable("x", 1.).unwrap();
117//!
118//! let mut expr = Expression::new("add(x, 1)", symbol_table).unwrap();
119//! assert_eq!(expr.value(), 2.);
120//! ```
121
122#[macro_use]
123extern crate enum_primitive;
124
125pub use error::*;
126pub use exprtk::*;
127pub use libc::c_double;
128
129macro_rules! string_from_ptr {
130    ($s:expr) => {
131        CStr::from_ptr($s).to_string_lossy().into_owned()
132    };
133}
134
135mod error;
136mod exprtk;
137
138#[cfg(test)]
139mod tests;