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
|
||||
=============
|
||||
|
||||
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
|
||||
--------------------
|
||||
|
||||
* Minimum compiler version is now 1.51.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* `from_dynamic` now supports deserializing `Option`.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
@ -40,15 +48,6 @@ Deprecated and Gated API's
|
||||
* `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
|
||||
=============
|
||||
|
||||
|
@ -7,6 +7,9 @@ use crate::{def_package, Blob, Dynamic, EvalAltResult, NativeCallContext, Positi
|
||||
use std::prelude::v1::*;
|
||||
use std::{any::TypeId, mem};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::FLOAT;
|
||||
|
||||
def_package!(crate:BasicBlobPackage:"Basic BLOB utilities.", lib, {
|
||||
lib.standard = true;
|
||||
|
||||
@ -188,10 +191,10 @@ mod blob_functions {
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
let blob_len = blob.len();
|
||||
start
|
||||
.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() {
|
||||
blob.extend(replace.into_iter());
|
||||
return;
|
||||
@ -215,10 +218,10 @@ mod blob_functions {
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
let blob_len = blob.len();
|
||||
start
|
||||
.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() {
|
||||
return Blob::new();
|
||||
} else {
|
||||
@ -246,10 +249,10 @@ mod blob_functions {
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
let blob_len = blob.len();
|
||||
start
|
||||
.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() {
|
||||
return Blob::new();
|
||||
} else {
|
||||
@ -288,10 +291,10 @@ mod blob_functions {
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
let blob_len = blob.len();
|
||||
start
|
||||
.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() {
|
||||
return Blob::new();
|
||||
} else {
|
||||
@ -314,10 +317,10 @@ mod blob_functions {
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
let blob_len = blob.len();
|
||||
start
|
||||
.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() {
|
||||
return mem::take(blob);
|
||||
} else {
|
||||
@ -351,4 +354,192 @@ mod blob_functions {
|
||||
pub fn not_equals(blob1: &mut Blob, blob2: Blob) -> bool {
|
||||
!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(())
|
||||
}
|
||||
|
||||
#[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