Skip to content

Commit

Permalink
Dev #95
Browse files Browse the repository at this point in the history
  • Loading branch information
vulogov committed Oct 26, 2024
1 parent f16968e commit 947c278
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 14 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ rust_dynamic, a crate developed for the Rust language, encompasses primitives de
* NODATA
* Error
* Metrics as a Vector of TIMESTAMP->F64 samples
* JSON - dynamic Value object containing JSON

Dynamic values are wrapped and stored inside a Value structure and could be castable back into the original Rust value.

Expand Down Expand Up @@ -68,6 +69,7 @@ rust_dynamic crate supports a number of function-primitives that will take a raw
| Value::from_list() | Create dynamic object of type LIST and initialize it from Vec<Value> |
| Value::from_dict() | Create dynamic object of type MAP and initialize it from HashMap<String, Value> |
| Value::dict() | Create dynamic empty object of type MAP |
| Value::json() | Create dynamic empty object for storing JSON values |
| Value::none() | Create dynamic object that wraps value of None |
| Value::nodata() | Create dynamic object that contains no data |
| Value::now() | Return dynamic object of type TIME containing current number of nanosecods from UNIX_EPOCH |
Expand Down Expand Up @@ -109,6 +111,7 @@ rust_dynamic supports a number of casting functions that will try to extract wra
| Value::cast_complex_int() | Return Complex<i64> from CINTEGER object |
| Value::cast_complex_float() | Return Complex<f64> from CFLOAT object |
| Value::export_float() | Return Vec<f64> from Value object |
| Value::cast_json_to_value() | Cast Dynamic value from JSON object |


Example:
Expand All @@ -123,6 +126,20 @@ let mut value = Value::from(42).unwrap();
let raw_value = value.cast_integer().unwrap()
```

And here is an example of creating and casting JSON data

```rust
//
// First, we will create a Value of JSON type
//
let data = Value::json(serde_json::json!(42));
//
// Now, we are converting JSON values to Dynamic types
//
let value = data.cast_json_to_value()
```


## How to set attributes to the Value

Value attributes is a Vector of the values that stored in the Value object. You can assign any number of the Value objects stored as attributes of the Value object. Attributes are serailize-able and wrap-able.
Expand All @@ -147,7 +164,7 @@ let v = Value::from(42 as i64).unwrap()

## How to serialize and deserialize dynamically-typed values

There are two serialization formats that rust_dynamic presently supports: JSON and Bincode.
There are two serialization formats that rust_dynamic presently supports: JSON and Bincode. If you are serialize to Biuncode, specail provisioning (wrapping) for objects holding JSON's will be done.

| Function name | Description |
|---|---|
Expand Down
73 changes: 63 additions & 10 deletions src/bincode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,38 @@ use crate::value::Value;
use crate::types::*;
use bincode2;
use nanoid::nanoid;
use easy_error::{Error, bail};

impl Value {
pub fn to_binary(&self) -> Result<Vec<u8>, bincode2::Error> {
bincode2::serialize(self)
pub fn to_binary(&self) -> Result<Vec<u8>, Error> {
if self.dt == JSON {
let str_json = match self.conv(STRING) {
Ok(str_json) => str_json,
Err(err) => {
bail!("to_binary() returns: {}", err);
}
};
let str_data = match str_json.cast_string() {
Ok(str_data) => str_data,
Err(err) => {
bail!("to_binary() returns: {}", err);
}
};
let wrapped_json = Value::json_wrap(str_data);
match bincode2::serialize(&wrapped_json) {
Ok(res) => return Ok(res),
Err(err) => {
bail!("bincode2::serialize() returns {}", err);
}
}
} else {
match bincode2::serialize(self) {
Ok(res) => return Ok(res),
Err(err) => {
bail!("bincode2::serialize() returns {}", err);
}
}
}
}
pub fn compile(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
if self.dt != LAMBDA {
Expand All @@ -20,20 +48,45 @@ impl Value {
}
}
}
pub fn from_binary(data: Vec<u8>) -> Result<Value, bincode2::Error> {
bincode2::deserialize::<Value>(&data)
pub fn from_binary(data: Vec<u8>) -> Result<Value, Error> {
match bincode2::deserialize::<Value>(&data) {
Ok(value) => {
if value.dt == JSON_WRAPPED {
match value.cast_string() {
Ok(str_data) => {
match serde_json::from_str(&str_data) {
Ok(json_val) => {
return Ok(Value::json(json_val));
}
Err(err) => {
bail!("{}", err);
}
}
}
Err(err) => {
bail!("{}", err);
}
}
} else {
return Ok(value)
}
}
Err(err) => {
bail!("{}", err);
}
}
}
pub fn wrap(&self) -> Result<Value, bincode2::Error> {
pub fn wrap(&self) -> Result<Value, Error> {
match self.to_binary() {
Ok(res) => {
return Result::Ok(Value::make_envelope(res));
}
Err(err) => return Err(err),
Err(err) => bail!("{}", err),
}
}
pub fn unwrap(&self) -> Result<Value, Box<dyn std::error::Error>> {
pub fn unwrap(&self) -> Result<Value, Error> {
if self.dt != ENVELOPE {
return Err("You requested to unwrap a non-envelope object".into());
bail!("You requested to unwrap a non-envelope object");
}
match &self.data {
Val::Binary(data) => {
Expand All @@ -42,10 +95,10 @@ impl Value {
res.id = nanoid!();
return Result::Ok(res);
}
Err(err) => return Err(err),
Err(err) => bail!("{}", err),
}
}
_ => Err(format!("Unwrappable object {}", self.id).into()),
_ => bail!("Unwrappable object {}", self.id),
}
}
}
102 changes: 102 additions & 0 deletions src/cast_json_to_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use crate::value::Value;
use crate::types::*;

impl Value {
pub fn cast_json_to_value(&self) -> Result<Value, Box<dyn std::error::Error>> {
if ! self.dt == JSON {
return Err(format!("This Dynamic type is not json: {}", self.dt).into());
}
match &self.data {
Val::Json(j_val) => {
if j_val.is_string() {
match j_val.as_str() {
Some(j_string) => {
return Ok(Value::from_string(j_string));
}
None => {
return Err(format!("This JSON is having a data that is not STRING").into());
}
}
} else if j_val.is_i64() {
match j_val.as_i64() {
Some(j_int) => {
return Ok(Value::from_int(j_int));
}
None => {
return Err(format!("This JSON is having a data that is not INT").into());
}
}
} else if j_val.is_f64() {
match j_val.as_f64() {
Some(j_float) => {
return Ok(Value::from_float(j_float));
}
None => {
return Err(format!("This JSON is having a data that is not FLOAT").into());
}
}
} else if j_val.is_null() {
return Ok(Value::none());
} else if j_val.is_boolean() {
match j_val.as_bool() {
Some(j_bool) => {
return Ok(Value::from_bool(j_bool));
}
None => {
return Err(format!("This JSON is having a data that is not BOOL").into());
}
}
} else if j_val.is_array() {
let mut res = Value::list();
match j_val.as_array() {
Some(j_arr) => {
for v in j_arr {
let jv = Value::json(v.clone());
match jv.cast_json_to_value() {
Ok(ja_val) => {
res.push(ja_val);
}
Err(err) => {
return Err(format!("JSON returns error during casting: {}", err).into());
}
}
}
}
None => {
return Err(format!("This JSON is having a data that is not ARRAY").into());
}
}
return Ok(res);
} else if j_val.is_object() {
let mut res = Value::dict();
match j_val.as_object() {
Some(j_val_obj) => {
for n in j_val_obj.keys() {
let j_val_value = match j_val_obj.get(n) {
Some(j_val_value) => j_val_value.clone(),
None => serde_json::json!(null),
};
let jv = Value::json(j_val_value);
match jv.cast_json_to_value() {
Ok(ja_val) => {
res.set(n, ja_val);
}
Err(err) => {
return Err(format!("JSON returns error during casting: {}", err).into());
}
}
}
}
None => {
return Err(format!("This JSON is having a data that is not OBJECT").into());
}
}
return Ok(res);
} else {
return Err(format!("This JSON is having a data that is not supportable").into());
}
}
_ => return Err(format!("This Dynamic type is not JSON: {}", self.dt).into()),
}
}
}
32 changes: 32 additions & 0 deletions src/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,45 @@ fn value_map_conversion(
}
}

fn value_json_conversion(
t: u16,
ot: u16,
val: &serde_json::Value,
) -> Result<Value, Box<dyn std::error::Error>> {
if ot != JSON {
return Err(format!(
"Source value is not JSON but {:?} and not suitable for conversion",
&ot
)
.into());
}

match t {
STRING | TEXTBUFFER => {
let Ok(str_json) = serde_json::to_string(val) else { return Err(format!("Error casting JSON to string").into()); };
return Ok(Value::from_string(str_json));
}
_ => {
match Value::json(val.clone()).cast_json_to_value() {
Ok(value) => {
return value.conv(ot);
}
Err(err) => {
return Err(format!("Can not convert json to INTEGER: {:?} due to: {}", &t, err).into());
}
}
}
}
}

impl Value {
pub fn conv(&self, t: u16) -> Result<Self, Box<dyn std::error::Error>> {
match &self.data {
Val::F64(f_val) => value_float_conversion(t, self.dt, *f_val),
Val::I64(i_val) => value_integer_conversion(t, self.dt, *i_val),
Val::String(s_val) => value_string_conversion(t, self.dt, &s_val),
Val::Bool(b_val) => value_bool_conversion(t, self.dt, *b_val),
Val::Json(j_val) => value_json_conversion(t, self.dt, &j_val),
_ => match self.dt {
LIST | RESULT => match &self.data {
Val::List(l_val) => value_list_conversion(t, self.dt, l_val),
Expand Down
48 changes: 48 additions & 0 deletions src/create_special.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,52 @@ impl Value {
tags: HashMap::new(),
}
}
pub fn json(value: serde_json::Value) -> Self {
Self {
id: nanoid!(),
stamp: timestamp_ms(),
dt: JSON,
q: 100.0,
data: Val::Json(value),
attr: Vec::new(),
curr: -1,
tags: HashMap::new(),
}
}
pub fn json_array() -> Self {
Self {
id: nanoid!(),
stamp: timestamp_ms(),
dt: JSON,
q: 100.0,
data: Val::Json(serde_json::json!([])),
attr: Vec::new(),
curr: -1,
tags: HashMap::new(),
}
}
pub fn json_object() -> Self {
Self {
id: nanoid!(),
stamp: timestamp_ms(),
dt: JSON,
q: 100.0,
data: Val::Json(serde_json::json!({})),
attr: Vec::new(),
curr: -1,
tags: HashMap::new(),
}
}
pub fn json_wrap(data: String) -> Self {
Self {
id: nanoid!(),
stamp: timestamp_ms(),
dt: JSON_WRAPPED,
q: 100.0,
data: Val::String(data),
attr: Vec::new(),
curr: -1,
tags: HashMap::new(),
}
}
}
7 changes: 4 additions & 3 deletions src/dup.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use crate::value::Value;
use nanoid::nanoid;
use easy_error::{Error, bail};

impl Value {
pub fn dup(&self) -> Result<Value, bincode2::Error> {
pub fn dup(&self) -> Result<Value, Error> {
match self.to_binary() {
Ok(bin_rep) => {
match Value::from_binary(bin_rep) {
Ok(mut res) => {
res.id = nanoid!();
return Result::Ok(res);
}
Err(err) => Err(err),
Err(err) => bail!("dup() returns: {}", err),
}
}
Err(err) => Err(err),
Err(err) => bail!("dup() returns: {}", err),
}
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub mod bind;
pub mod bincode;
pub mod carcdr;
pub mod cast;
pub mod cast_json_to_value;
pub mod wrap_json;
pub mod cast_generic;
pub mod conv;
pub mod ctx;
Expand Down
Loading

0 comments on commit 947c278

Please sign in to comment.