Add timestamp support.
This commit is contained in:
parent
d73cfb6da5
commit
5848339d5a
31
README.md
31
README.md
@ -362,6 +362,7 @@ The following primitive types are supported natively:
|
|||||||
| **Unicode string** | `String` (_not_ `&str`) | `"string"` | `"hello"` etc. |
|
| **Unicode string** | `String` (_not_ `&str`) | `"string"` | `"hello"` etc. |
|
||||||
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ? ? ? ]"` |
|
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ? ? ? ]"` |
|
||||||
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
||||||
|
| **Timestamp** (implemented in standard library) | `std::time::Instant` | `"timestamp"` | _not supported_ |
|
||||||
| **Dynamic value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
|
| **Dynamic value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
|
||||||
| **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. |
|
| **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. |
|
||||||
| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. |
|
| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. |
|
||||||
@ -1448,6 +1449,36 @@ let result = engine.eval_with_scope::<INT>(r#"map["^^^!!!"].len()"#)?;
|
|||||||
result == 3; // the object map is successfully used in the script
|
result == 3; // the object map is successfully used in the script
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`timestamp`'s
|
||||||
|
-------------
|
||||||
|
[`timestamp`]: #timestamp-s
|
||||||
|
|
||||||
|
Timestamps are provided by the standard library (excluded if using a [raw `Engine`]) via the `timestamp`
|
||||||
|
function.
|
||||||
|
|
||||||
|
The Rust type of a timestamp is `std::time::Instant`. [`type_of()`] a timestamp returns `"timestamp"`.
|
||||||
|
|
||||||
|
### Built-in functions
|
||||||
|
|
||||||
|
The following methods (defined in the standard library but excluded if using a [raw `Engine`]) operate on timestamps:
|
||||||
|
|
||||||
|
| Function | Parameter(s) | Description |
|
||||||
|
| ------------ | ---------------------------------- | -------------------------------------------------------- |
|
||||||
|
| `elapsed` | _none_ | returns the number of seconds since the timestamp |
|
||||||
|
| `-` operator | later timestamp, earlier timestamp | returns the number of seconds between the two timestamps |
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let now = timestamp();
|
||||||
|
|
||||||
|
// Do some lengthy operation...
|
||||||
|
|
||||||
|
if now.elapsed() > 30.0 {
|
||||||
|
print("takes too long (over 30 seconds)!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Comparison operators
|
Comparison operators
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// This script uses the Sieve of Eratosthenes to calculate prime numbers.
|
// This script uses the Sieve of Eratosthenes to calculate prime numbers.
|
||||||
|
|
||||||
|
let now = timestamp();
|
||||||
|
|
||||||
const MAX_NUMBER_TO_CHECK = 10_000; // 1229 primes <= 10000
|
const MAX_NUMBER_TO_CHECK = 10_000; // 1229 primes <= 10000
|
||||||
|
|
||||||
let prime_mask = [];
|
let prime_mask = [];
|
||||||
@ -24,3 +26,4 @@ for p in range(2, MAX_NUMBER_TO_CHECK) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
print("Total " + total_primes_found + " primes.");
|
print("Total " + total_primes_found + " primes.");
|
||||||
|
print("Run time = " + now.elapsed() + " seconds.");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// This script runs 1 million iterations
|
// This script runs 1 million iterations
|
||||||
// to test the speed of the scripting engine.
|
// to test the speed of the scripting engine.
|
||||||
|
|
||||||
|
let now = timestamp();
|
||||||
let x = 1_000_000;
|
let x = 1_000_000;
|
||||||
|
|
||||||
print("Ready... Go!");
|
print("Ready... Go!");
|
||||||
@ -9,4 +10,4 @@ while x > 0 {
|
|||||||
x = x - 1;
|
x = x - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Finished.");
|
print("Finished. Run time = " + now.elapsed() + " seconds.");
|
||||||
|
@ -27,6 +27,7 @@ use crate::stdlib::{
|
|||||||
format,
|
format,
|
||||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Range, Rem, Shl, Shr, Sub},
|
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Range, Rem, Shl, Shr, Sub},
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
|
time::Instant,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
{i32, i64, u32},
|
{i32, i64, u32},
|
||||||
};
|
};
|
||||||
@ -57,6 +58,34 @@ macro_rules! reg_op_result1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! reg_cmp {
|
||||||
|
($self:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
|
||||||
|
$(
|
||||||
|
$self.register_fn($x, $op as fn(x: $y, y: $y)->bool);
|
||||||
|
)*
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparison operators
|
||||||
|
fn lt<T: PartialOrd>(x: T, y: T) -> bool {
|
||||||
|
x < y
|
||||||
|
}
|
||||||
|
fn lte<T: PartialOrd>(x: T, y: T) -> bool {
|
||||||
|
x <= y
|
||||||
|
}
|
||||||
|
fn gt<T: PartialOrd>(x: T, y: T) -> bool {
|
||||||
|
x > y
|
||||||
|
}
|
||||||
|
fn gte<T: PartialOrd>(x: T, y: T) -> bool {
|
||||||
|
x >= y
|
||||||
|
}
|
||||||
|
fn eq<T: PartialEq>(x: T, y: T) -> bool {
|
||||||
|
x == y
|
||||||
|
}
|
||||||
|
fn ne<T: PartialEq>(x: T, y: T) -> bool {
|
||||||
|
x != y
|
||||||
|
}
|
||||||
|
|
||||||
impl Engine<'_> {
|
impl Engine<'_> {
|
||||||
/// Register the core built-in library.
|
/// Register the core built-in library.
|
||||||
pub(crate) fn register_core_lib(&mut self) {
|
pub(crate) fn register_core_lib(&mut self) {
|
||||||
@ -176,26 +205,6 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comparison operators
|
|
||||||
fn lt<T: PartialOrd>(x: T, y: T) -> bool {
|
|
||||||
x < y
|
|
||||||
}
|
|
||||||
fn lte<T: PartialOrd>(x: T, y: T) -> bool {
|
|
||||||
x <= y
|
|
||||||
}
|
|
||||||
fn gt<T: PartialOrd>(x: T, y: T) -> bool {
|
|
||||||
x > y
|
|
||||||
}
|
|
||||||
fn gte<T: PartialOrd>(x: T, y: T) -> bool {
|
|
||||||
x >= y
|
|
||||||
}
|
|
||||||
fn eq<T: PartialEq>(x: T, y: T) -> bool {
|
|
||||||
x == y
|
|
||||||
}
|
|
||||||
fn ne<T: PartialEq>(x: T, y: T) -> bool {
|
|
||||||
x != y
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logic operators
|
// Logic operators
|
||||||
fn and(x: bool, y: bool) -> bool {
|
fn and(x: bool, y: bool) -> bool {
|
||||||
x && y
|
x && y
|
||||||
@ -395,14 +404,6 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
macro_rules! reg_cmp {
|
|
||||||
($self:expr, $x:expr, $op:expr, $( $y:ty ),*) => (
|
|
||||||
$(
|
|
||||||
$self.register_fn($x, $op as fn(x: $y, y: $y)->bool);
|
|
||||||
)*
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
reg_cmp!(self, "<", lt, INT, String, char);
|
reg_cmp!(self, "<", lt, INT, String, char);
|
||||||
reg_cmp!(self, "<=", lte, INT, String, char);
|
reg_cmp!(self, "<=", lte, INT, String, char);
|
||||||
reg_cmp!(self, ">", gt, INT, String, char);
|
reg_cmp!(self, ">", gt, INT, String, char);
|
||||||
@ -433,7 +434,7 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `&&` and `||` are treated specially as they short-circuit.
|
// `&&` and `||` are treated specially as they short-circuit.
|
||||||
// They are implemented as special `Expr` instances, not function calls.
|
// They are implemented as special `Expr` Instants, not function calls.
|
||||||
//reg_op!(self, "||", or, bool);
|
//reg_op!(self, "||", or, bool);
|
||||||
//reg_op!(self, "&&", and, bool);
|
//reg_op!(self, "&&", and, bool);
|
||||||
|
|
||||||
@ -1031,5 +1032,39 @@ impl Engine<'_> {
|
|||||||
*s = trimmed.to_string();
|
*s = trimmed.to_string();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Register date/time functions
|
||||||
|
self.register_fn("timestamp", || Instant::now());
|
||||||
|
|
||||||
|
self.register_fn("-", |ts1: Instant, ts2: Instant| {
|
||||||
|
if ts2 > ts1 {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return -(ts2 - ts1).as_secs_f64();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
return -((ts2 - ts1).as_secs() as INT);
|
||||||
|
} else {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return (ts1 - ts2).as_secs_f64();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
return (ts1 - ts2).as_secs() as INT;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
reg_cmp!(self, "<", lt, Instant);
|
||||||
|
reg_cmp!(self, "<=", lte, Instant);
|
||||||
|
reg_cmp!(self, ">", gt, Instant);
|
||||||
|
reg_cmp!(self, ">=", gte, Instant);
|
||||||
|
reg_cmp!(self, "==", eq, Instant);
|
||||||
|
reg_cmp!(self, "!=", ne, Instant);
|
||||||
|
|
||||||
|
self.register_fn("elapsed", |timestamp: Instant| {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
return timestamp.elapsed().as_secs_f64();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
return timestamp.elapsed().as_secs() as INT;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ use crate::stdlib::{
|
|||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
time::Instant,
|
||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
@ -362,6 +363,7 @@ impl Engine<'_> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
(type_name::<Map>(), "map"),
|
(type_name::<Map>(), "map"),
|
||||||
(type_name::<String>(), "string"),
|
(type_name::<String>(), "string"),
|
||||||
|
(type_name::<Instant>(), "timestamp"),
|
||||||
(type_name::<Dynamic>(), "dynamic"),
|
(type_name::<Dynamic>(), "dynamic"),
|
||||||
(type_name::<Variant>(), "variant"),
|
(type_name::<Variant>(), "variant"),
|
||||||
]
|
]
|
||||||
@ -719,25 +721,26 @@ impl Engine<'_> {
|
|||||||
let value = self.get_dot_val_helper(scope, fn_lib, target, dot_rhs, level);
|
let value = self.get_dot_val_helper(scope, fn_lib, target, dot_rhs, level);
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
if let Some(src) = src {
|
match src.map(|s| s.typ) {
|
||||||
match src.typ {
|
None => (),
|
||||||
ScopeEntryType::Constant => {
|
|
||||||
|
Some(ScopeEntryType::Constant) => {
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant(
|
return Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
src.name.to_string(),
|
src.unwrap().name.to_string(),
|
||||||
idx_lhs.position(),
|
idx_lhs.position(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ScopeEntryType::Normal => {
|
|
||||||
|
Some(ScopeEntryType::Normal) => {
|
||||||
Self::update_indexed_var_in_scope(
|
Self::update_indexed_var_in_scope(
|
||||||
idx_src_type,
|
idx_src_type,
|
||||||
scope,
|
scope,
|
||||||
src,
|
src.unwrap(),
|
||||||
index,
|
index,
|
||||||
(val, dot_rhs.position()),
|
(val, dot_rhs.position()),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
@ -1106,16 +1109,16 @@ impl Engine<'_> {
|
|||||||
match dot_lhs {
|
match dot_lhs {
|
||||||
// id.???
|
// id.???
|
||||||
Expr::Variable(id, pos) => {
|
Expr::Variable(id, pos) => {
|
||||||
let (entry, mut target) = Self::search_scope(scope, id, *pos)?;
|
let (src, mut target) = Self::search_scope(scope, id, *pos)?;
|
||||||
|
|
||||||
match entry.typ {
|
match src.typ {
|
||||||
ScopeEntryType::Constant => Err(EvalAltResult::ErrorAssignmentToConstant(
|
ScopeEntryType::Constant => Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
id.to_string(),
|
id.to_string(),
|
||||||
op_pos,
|
op_pos,
|
||||||
)),
|
)),
|
||||||
_ => {
|
_ => {
|
||||||
// Avoid referencing scope which is used below as mut
|
// Avoid referencing scope which is used below as mut
|
||||||
let entry = ScopeSource { name: id, ..entry };
|
let entry = ScopeSource { name: id, ..src };
|
||||||
let this_ptr = target.as_mut();
|
let this_ptr = target.as_mut();
|
||||||
let value = self
|
let value = self
|
||||||
.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
||||||
@ -1139,25 +1142,26 @@ impl Engine<'_> {
|
|||||||
self.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
self.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
if let Some(src) = src {
|
match src.map(|x| x.typ) {
|
||||||
match src.typ {
|
None => (),
|
||||||
ScopeEntryType::Constant => {
|
|
||||||
|
Some(ScopeEntryType::Constant) => {
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant(
|
return Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
src.name.to_string(),
|
src.unwrap().name.to_string(),
|
||||||
lhs.position(),
|
lhs.position(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ScopeEntryType::Normal => {
|
|
||||||
|
Some(ScopeEntryType::Normal) => {
|
||||||
Self::update_indexed_var_in_scope(
|
Self::update_indexed_var_in_scope(
|
||||||
idx_src_type,
|
idx_src_type,
|
||||||
scope,
|
scope,
|
||||||
src,
|
src.unwrap(),
|
||||||
index,
|
index,
|
||||||
(target, val_pos),
|
(target, val_pos),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
@ -1260,29 +1264,36 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
match lhs.as_ref() {
|
match lhs.as_ref() {
|
||||||
// name = rhs
|
// name = rhs
|
||||||
Expr::Variable(name, pos) => match scope
|
Expr::Variable(name, pos) => match scope.get(name) {
|
||||||
.get(name)
|
None => {
|
||||||
.ok_or_else(|| {
|
return Err(EvalAltResult::ErrorVariableNotFound(
|
||||||
EvalAltResult::ErrorVariableNotFound(name.clone().into_owned(), *pos)
|
name.clone().into_owned(),
|
||||||
})?
|
*pos,
|
||||||
.0
|
))
|
||||||
{
|
}
|
||||||
|
|
||||||
|
Some((
|
||||||
entry
|
entry
|
||||||
@
|
@
|
||||||
ScopeSource {
|
ScopeSource {
|
||||||
typ: ScopeEntryType::Normal,
|
typ: ScopeEntryType::Normal,
|
||||||
..
|
..
|
||||||
} => {
|
},
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
// Avoid referencing scope which is used below as mut
|
// Avoid referencing scope which is used below as mut
|
||||||
let entry = ScopeSource { name, ..entry };
|
let entry = ScopeSource { name, ..entry };
|
||||||
*scope.get_mut(entry) = rhs_val.clone();
|
*scope.get_mut(entry) = rhs_val.clone();
|
||||||
Ok(rhs_val)
|
Ok(rhs_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some((
|
||||||
ScopeSource {
|
ScopeSource {
|
||||||
typ: ScopeEntryType::Constant,
|
typ: ScopeEntryType::Constant,
|
||||||
..
|
..
|
||||||
} => Err(EvalAltResult::ErrorAssignmentToConstant(
|
},
|
||||||
|
_,
|
||||||
|
)) => Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
*op_pos,
|
*op_pos,
|
||||||
)),
|
)),
|
||||||
@ -1294,27 +1305,26 @@ impl Engine<'_> {
|
|||||||
let (idx_src_type, src, index, _) =
|
let (idx_src_type, src, index, _) =
|
||||||
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
|
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
|
||||||
|
|
||||||
if let Some(src) = src {
|
match src.map(|x| x.typ) {
|
||||||
match src.typ {
|
None => Err(EvalAltResult::ErrorAssignmentToUnknownLHS(
|
||||||
ScopeEntryType::Constant => {
|
idx_lhs.position(),
|
||||||
|
)),
|
||||||
|
|
||||||
|
Some(ScopeEntryType::Constant) => {
|
||||||
Err(EvalAltResult::ErrorAssignmentToConstant(
|
Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
src.name.to_string(),
|
src.unwrap().name.to_string(),
|
||||||
idx_lhs.position(),
|
idx_lhs.position(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
ScopeEntryType::Normal => Ok(Self::update_indexed_var_in_scope(
|
|
||||||
|
Some(ScopeEntryType::Normal) => Ok(Self::update_indexed_var_in_scope(
|
||||||
idx_src_type,
|
idx_src_type,
|
||||||
scope,
|
scope,
|
||||||
src,
|
src.unwrap(),
|
||||||
index,
|
index,
|
||||||
(rhs_val, rhs.position()),
|
(rhs_val, rhs.position()),
|
||||||
)?),
|
)?),
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Err(EvalAltResult::ErrorAssignmentToUnknownLHS(
|
|
||||||
idx_lhs.position(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dot_lhs.dot_rhs = rhs
|
// dot_lhs.dot_rhs = rhs
|
||||||
|
@ -24,6 +24,7 @@ fn test_string() -> Result<(), EvalAltResult> {
|
|||||||
assert_eq!(engine.eval::<String>(r#""foo" + 123"#)?, "foo123");
|
assert_eq!(engine.eval::<String>(r#""foo" + 123"#)?, "foo123");
|
||||||
|
|
||||||
#[cfg(not(feature = "no_stdlib"))]
|
#[cfg(not(feature = "no_stdlib"))]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
assert_eq!(engine.eval::<String>("(42).to_string()")?, "42");
|
assert_eq!(engine.eval::<String>("(42).to_string()")?, "42");
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
39
tests/time.rs
Normal file
39
tests/time.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#![cfg(not(feature = "no_stdlib"))]
|
||||||
|
|
||||||
|
use rhai::{Engine, EvalAltResult, INT};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use rhai::FLOAT;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_timestamp() -> Result<(), EvalAltResult> {
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<String>("type_of(timestamp())")?, "timestamp");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
assert!(
|
||||||
|
engine.eval::<FLOAT>(
|
||||||
|
r#"
|
||||||
|
let time = timestamp();
|
||||||
|
let x = 10_000;
|
||||||
|
while x > 0 { x -= 1; }
|
||||||
|
elapsed(time)
|
||||||
|
"#
|
||||||
|
)? < 10.0
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
assert!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
r#"
|
||||||
|
let time = timestamp();
|
||||||
|
let x = 10_000;
|
||||||
|
while x > 0 { x -= 1; }
|
||||||
|
elapsed(time)
|
||||||
|
"#
|
||||||
|
)? < 10
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user