Add parse/write to blobs.
This commit is contained in:
parent
780c36e675
commit
6af406bafc
17
CHANGELOG.md
17
CHANGELOG.md
@ -4,11 +4,19 @@ Rhai Release Notes
|
|||||||
Version 1.3.0
|
Version 1.3.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
This version adds native support for `BLOB`'s (byte arrays), as well as a number of configuration
|
||||||
|
settings to fine-tun language features.
|
||||||
|
|
||||||
Compiler requirement
|
Compiler requirement
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
* Minimum compiler version is now 1.51.
|
* Minimum compiler version is now 1.51.
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* `from_dynamic` now supports deserializing `Option`.
|
||||||
|
|
||||||
New features
|
New features
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@ -40,15 +48,6 @@ Deprecated and Gated API's
|
|||||||
* `FnPtr::call_dynamic` is deprecated in favor of `FnPtr::call_raw`.
|
* `FnPtr::call_dynamic` is deprecated in favor of `FnPtr::call_raw`.
|
||||||
|
|
||||||
|
|
||||||
Version 1.2.2
|
|
||||||
=============
|
|
||||||
|
|
||||||
Bug fixes
|
|
||||||
---------
|
|
||||||
|
|
||||||
* `from_dynamic` now supports deserializing `Option`.
|
|
||||||
|
|
||||||
|
|
||||||
Version 1.2.1
|
Version 1.2.1
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ use crate::{def_package, Blob, Dynamic, EvalAltResult, NativeCallContext, Positi
|
|||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{any::TypeId, mem};
|
use std::{any::TypeId, mem};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use crate::FLOAT;
|
||||||
|
|
||||||
def_package!(crate:BasicBlobPackage:"Basic BLOB utilities.", lib, {
|
def_package!(crate:BasicBlobPackage:"Basic BLOB utilities.", lib, {
|
||||||
lib.standard = true;
|
lib.standard = true;
|
||||||
|
|
||||||
@ -188,10 +191,10 @@ mod blob_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let arr_len = blob.len();
|
let blob_len = blob.len();
|
||||||
start
|
start
|
||||||
.checked_abs()
|
.checked_abs()
|
||||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
} else if start as usize >= blob.len() {
|
} else if start as usize >= blob.len() {
|
||||||
blob.extend(replace.into_iter());
|
blob.extend(replace.into_iter());
|
||||||
return;
|
return;
|
||||||
@ -215,10 +218,10 @@ mod blob_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let arr_len = blob.len();
|
let blob_len = blob.len();
|
||||||
start
|
start
|
||||||
.checked_abs()
|
.checked_abs()
|
||||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
} else if start as usize >= blob.len() {
|
} else if start as usize >= blob.len() {
|
||||||
return Blob::new();
|
return Blob::new();
|
||||||
} else {
|
} else {
|
||||||
@ -246,10 +249,10 @@ mod blob_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let arr_len = blob.len();
|
let blob_len = blob.len();
|
||||||
start
|
start
|
||||||
.checked_abs()
|
.checked_abs()
|
||||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
} else if start as usize >= blob.len() {
|
} else if start as usize >= blob.len() {
|
||||||
return Blob::new();
|
return Blob::new();
|
||||||
} else {
|
} else {
|
||||||
@ -288,10 +291,10 @@ mod blob_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let arr_len = blob.len();
|
let blob_len = blob.len();
|
||||||
start
|
start
|
||||||
.checked_abs()
|
.checked_abs()
|
||||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
} else if start as usize >= blob.len() {
|
} else if start as usize >= blob.len() {
|
||||||
return Blob::new();
|
return Blob::new();
|
||||||
} else {
|
} else {
|
||||||
@ -314,10 +317,10 @@ mod blob_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let arr_len = blob.len();
|
let blob_len = blob.len();
|
||||||
start
|
start
|
||||||
.checked_abs()
|
.checked_abs()
|
||||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
} else if start as usize >= blob.len() {
|
} else if start as usize >= blob.len() {
|
||||||
return mem::take(blob);
|
return mem::take(blob);
|
||||||
} else {
|
} else {
|
||||||
@ -351,4 +354,192 @@ mod blob_functions {
|
|||||||
pub fn not_equals(blob1: &mut Blob, blob2: Blob) -> bool {
|
pub fn not_equals(blob1: &mut Blob, blob2: Blob) -> bool {
|
||||||
!equals(blob1, blob2)
|
!equals(blob1, blob2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn parse_int(blob: &mut Blob, start: INT, len: INT, is_le: bool) -> INT {
|
||||||
|
if blob.is_empty() || len <= 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let blob_len = blob.len();
|
||||||
|
|
||||||
|
let start = if start < 0 {
|
||||||
|
start
|
||||||
|
.checked_abs()
|
||||||
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
|
} else if start as usize >= blob_len {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
start as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = if len as usize > blob_len - start {
|
||||||
|
blob_len - start
|
||||||
|
} else {
|
||||||
|
len as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
const INT_BYTES: usize = mem::size_of::<INT>();
|
||||||
|
|
||||||
|
let len = usize::min(len, INT_BYTES);
|
||||||
|
|
||||||
|
let mut buf = [0_u8; INT_BYTES];
|
||||||
|
|
||||||
|
buf[..len].copy_from_slice(&blob[start..][..len]);
|
||||||
|
|
||||||
|
if is_le {
|
||||||
|
INT::from_le_bytes(buf)
|
||||||
|
} else {
|
||||||
|
INT::from_be_bytes(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_le_int(blob: &mut Blob, start: INT, len: INT) -> INT {
|
||||||
|
parse_int(blob, start, len, true)
|
||||||
|
}
|
||||||
|
pub fn parse_be_int(blob: &mut Blob, start: INT, len: INT) -> INT {
|
||||||
|
parse_int(blob, start, len, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_int(blob: &mut Blob, start: INT, len: INT, value: INT, is_le: bool) {
|
||||||
|
if blob.is_empty() || len <= 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let blob_len = blob.len();
|
||||||
|
|
||||||
|
let start = if start < 0 {
|
||||||
|
start
|
||||||
|
.checked_abs()
|
||||||
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
|
} else if start as usize >= blob_len {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
start as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = if len as usize > blob_len - start {
|
||||||
|
blob_len - start
|
||||||
|
} else {
|
||||||
|
len as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
const INT_BYTES: usize = mem::size_of::<INT>();
|
||||||
|
|
||||||
|
let len = usize::min(len, INT_BYTES);
|
||||||
|
|
||||||
|
let mut buf = [0_u8; INT_BYTES];
|
||||||
|
|
||||||
|
buf.copy_from_slice(&if is_le {
|
||||||
|
value.to_le_bytes()
|
||||||
|
} else {
|
||||||
|
value.to_be_bytes()
|
||||||
|
});
|
||||||
|
|
||||||
|
blob[start..][..len].copy_from_slice(&buf[..len]);
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "write_le")]
|
||||||
|
pub fn write_le_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
||||||
|
write_int(blob, start, len, value, true)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "write_be")]
|
||||||
|
pub fn write_be_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
||||||
|
write_int(blob, start, len, value, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[inline]
|
||||||
|
fn parse_float(blob: &mut Blob, start: INT, len: INT, is_le: bool) -> FLOAT {
|
||||||
|
if blob.is_empty() || len <= 0 {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
let blob_len = blob.len();
|
||||||
|
|
||||||
|
let start = if start < 0 {
|
||||||
|
start
|
||||||
|
.checked_abs()
|
||||||
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
|
} else if start as usize >= blob_len {
|
||||||
|
return 0.0;
|
||||||
|
} else {
|
||||||
|
start as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = if len as usize > blob_len - start {
|
||||||
|
blob_len - start
|
||||||
|
} else {
|
||||||
|
len as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
const FLOAT_BYTES: usize = mem::size_of::<FLOAT>();
|
||||||
|
|
||||||
|
let len = usize::min(len, FLOAT_BYTES);
|
||||||
|
|
||||||
|
let mut buf = [0_u8; FLOAT_BYTES];
|
||||||
|
|
||||||
|
buf[..len].copy_from_slice(&blob[start..][..len]);
|
||||||
|
|
||||||
|
if is_le {
|
||||||
|
FLOAT::from_le_bytes(buf)
|
||||||
|
} else {
|
||||||
|
FLOAT::from_be_bytes(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub fn parse_le_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
|
||||||
|
parse_float(blob, start, len, true)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub fn parse_be_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
|
||||||
|
parse_float(blob, start, len, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[inline]
|
||||||
|
fn write_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT, is_le: bool) {
|
||||||
|
if blob.is_empty() || len <= 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let blob_len = blob.len();
|
||||||
|
|
||||||
|
let start = if start < 0 {
|
||||||
|
start
|
||||||
|
.checked_abs()
|
||||||
|
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||||
|
} else if start as usize >= blob_len {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
start as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = if len as usize > blob_len - start {
|
||||||
|
blob_len - start
|
||||||
|
} else {
|
||||||
|
len as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
const FLOAT_BYTES: usize = mem::size_of::<FLOAT>();
|
||||||
|
|
||||||
|
let len = usize::min(len, FLOAT_BYTES);
|
||||||
|
|
||||||
|
let mut buf = [0_u8; FLOAT_BYTES];
|
||||||
|
|
||||||
|
buf.copy_from_slice(&if is_le {
|
||||||
|
value.to_le_bytes()
|
||||||
|
} else {
|
||||||
|
value.to_be_bytes()
|
||||||
|
});
|
||||||
|
|
||||||
|
blob[start..][..len].copy_from_slice(&buf[..len]);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[rhai_fn(name = "write_le")]
|
||||||
|
pub fn write_le_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
||||||
|
write_float(blob, start, len, value, true)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[rhai_fn(name = "write_be")]
|
||||||
|
pub fn write_be_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
||||||
|
write_float(blob, start, len, value, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,3 +74,66 @@ fn test_blobs() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blobs_parse() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,2,0)"
|
||||||
|
)?,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,2,9)"
|
||||||
|
)?,
|
||||||
|
0x0908070605040302
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_be_int(x,2,10)"
|
||||||
|
)?,
|
||||||
|
0x0203040506070809
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-5,99)"
|
||||||
|
)?,
|
||||||
|
0x0f0e0d0c0b
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-5,2)"
|
||||||
|
)?,
|
||||||
|
0x0c0b
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-99,99)"
|
||||||
|
)?,
|
||||||
|
0x0706050403020100
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } write_be(x, 3, 3, -98765432); parse_be_int(x, 3, 3)"
|
||||||
|
)?,
|
||||||
|
0xffffff0000000000_u64 as i64
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } write_le(x, 3, 3, -98765432); parse_le_int(x, 3, 3)"
|
||||||
|
)?,
|
||||||
|
0x1cf588
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user