Rust's core strength is its ability to provide memory safety and performance guarantees at compile-time, which is achieved through its ownership and borrowing system. But ability for the developer to handle a dynamic data types defined at run-time for the applications written in Rust is still important endeavor and it is improving versatility of the application while providing an ability to handle a wide range of use cases.
Various interpreted DSL languages created in Rust uses run-time dynamic data type system created for the specific language. Excellent crate Serde also implements trait Value that's allow to handle dynamic datatypes in run-time. But none of those solutions is not perfect for a Rust developers as they ether focus on specific DSL or handling JSON values.
rustdynamic is a crate, created for Rust language, implementing primitives that will be helping to Rust developer with the specific issue of handling dynamic data types defined at run-time. Currently, rustdynamic supports following data types:
Dynamic values are wrapped and stored inside a Value structure and could be cast-able back into original Rust value.
```rust use rust_dynamic::value::Value;
let mut value = Value::from(42).unwrap(); println!("Type of the stored value is {}", &value.typename()); println!("Dynamic value of the value is {:?}", &value.castinteger());
```
rust_dynamic crate supports a number of function-primitives that will take a raw value and return a wrapped Dynamic object.
| Function name | Description |
|---|---|
| Value::fromfloat() | Create dynamic object from f64 float number |
| Value::fromfloat32() | Create dynamic object from f32 float number |
| Value::frominteger() | Create dynamic object from i64 float number |
| Value::frominteger32() | Create dynamic object from i32 float number |
| Value::frombool() | Create dynamic object from boolean value |
| Value::fromstring() | Create dynamic object from Rust String |
| Value::fromstr() | Create dynamic object from Rust &str |
| Value::frombin() | Create dynamic object of type BINARY from Vec
There are generic function Value::from() that will automatically cast proper data type and ether return object or error message.
rust_dynamic supports a number of casting functions that will try to extract wrapped value from the object that holds dynamically-typed value.
| Function name | Description |
|---|---|
| Value::castfloat() | Return f64 number from FLOAT object |
| Value::castinteger() | Return i64 number from INTEGER object |
| Value::castbool() | Return boolean from BOOL object |
| Value::caststring() | Return String from STRING object |
| Value::castbin() | Return Vec
Example:
```rust use rust_dynamic::value::Value;
// First we create a dynamically-typed value from a raw static value let mut value = Value::from(42).unwrap();
// Then we can cast raw value back from the dynamic object let rawvalue = value.castinteger().unwrap() ```
There are two serialization formats that rust_dynamic presently supports: JSON and Bincode.
| Function name | Description |
|---|---|
| Value::tojson() | Return JSON representation of dynamically-typed value |
| Value::tobinary() | Return Bincode representation of dynamically-typed value |
| Value::fromjson() | Takes string containing JSON representation of the dynamically-typed object and return re-created Value object |
| Value::frombinary() | Takes Vec
Example:
rust
// This call will create a new dynamic value
let mut data = Value::from(42 as i64).unwrap();
// This call will serialize object to Bincode format
let bin_out = data.to_binary().unwrap();
// This will re-create an object from it's Bincode representation
let mut data2 = Value::from_binary(bin_out).unwrap();
While rust_dynamic crate is not strive to provide a full-featured functional interface to the dynamic values, some functionality that specific to a Functional programming has been implemented.
| Function name | Description | |---|---| | Value::bind() | Takes a reference to a function that accepts Value as a parameter, that function is called with passed current object and new Value object returned | | Value::map() | Execute function to each element of the LIST or to the value and return new Value | | Value::map_float() | Execute function to each FLOAT element of the LIST or to the value and return new Value | | Value::push() | Ether add a new value to the list, or return a new Value |
```rust use std::collections::HashMap;
// This call will create a key object. Key object can be of any supported type let key = Value::from(42.0 as f64).unwrap();
// Then we are creating a HashMap
let mut h: HashMap
// and store a key->value association h.insert(key, "value".to_string()); ```
rust
let mut c = 0.0;
// Let's create a object of LIST type and push two elements into list
let v = Value::list()
.push(Value::from(1.0 as f64).unwrap())
.push(Value::from(41.0 as f64).unwrap());
// We can iterate over dynamically-typed object
for i in v {
c += i.cast_float().unwrap();
}
In this example we are applying f64::sin function to all iterable values of the dynamically-typed object
rust
let mut v = Value::from(42.0).unwrap();
v = v.map_float(f64::sin);