Simplify Dynamic::as_XXX calls.

This commit is contained in:
Stephen Chung 2022-11-09 20:18:11 +08:00
parent ce046422f0
commit a1d42b826a
5 changed files with 66 additions and 54 deletions

View File

@ -16,6 +16,7 @@ Bug fixes
* `import` statements inside `eval` no longer cause errors in subsequent code. * `import` statements inside `eval` no longer cause errors in subsequent code.
* Functions marked `global` in `import`ed modules with no alias names now work properly. * Functions marked `global` in `import`ed modules with no alias names now work properly.
* Incorrect loop optimizations that are too aggressive (e.g. unrolling a `do { ... } until true` with a `break` statement inside) and cause crashes are removed. * Incorrect loop optimizations that are too aggressive (e.g. unrolling a `do { ... } until true` with a `break` statement inside) and cause crashes are removed.
* `Dynamic::is` now works properly for shared values.
Breaking changes Breaking changes
---------------- ----------------

View File

@ -52,7 +52,6 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
lib: &[SharedModule], lib: &[SharedModule],
scope: &'s mut Scope, scope: &'s mut Scope,
this_ptr: &'s mut Dynamic, this_ptr: &'s mut Dynamic,
expr: &Expr, expr: &Expr,
@ -136,7 +135,6 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
lib: &[SharedModule], lib: &[SharedModule],
scope: &'s mut Scope, scope: &'s mut Scope,
this_ptr: &'s mut Dynamic, this_ptr: &'s mut Dynamic,
expr: &Expr, expr: &Expr,
@ -221,7 +219,6 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
lib: &[SharedModule], lib: &[SharedModule],
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, this_ptr: &mut Dynamic,
expr: &Expr, expr: &Expr,

View File

@ -6,7 +6,7 @@ use crate::ast::{
ASTFlags, BinaryExpr, Expr, Ident, OpAssignment, Stmt, SwitchCasesCollection, TryCatchBlock, ASTFlags, BinaryExpr, Expr, Ident, OpAssignment, Stmt, SwitchCasesCollection, TryCatchBlock,
}; };
use crate::func::{get_builtin_op_assignment_fn, get_hasher}; use crate::func::{get_builtin_op_assignment_fn, get_hasher};
use crate::types::dynamic::{AccessMode, Union}; use crate::types::dynamic::AccessMode;
use crate::types::RestoreOnDrop; use crate::types::RestoreOnDrop;
use crate::{ use crate::{
Dynamic, Engine, ImmutableString, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR, Dynamic, Engine, ImmutableString, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR,
@ -687,7 +687,7 @@ impl Engine {
.map(|_| Dynamic::UNIT) .map(|_| Dynamic::UNIT)
.map_err(|result_err| match *result_err { .map_err(|result_err| match *result_err {
// Re-throw exception // Re-throw exception
ERR::ErrorRuntime(Dynamic(Union::Unit(..)), pos) => { ERR::ErrorRuntime(v, pos) if v.is_unit() => {
err.set_position(pos); err.set_position(pos);
err err
} }

View File

@ -690,7 +690,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
PlusAssign => Some(|_ctx, args| { PlusAssign => Some(|_ctx, args| {
let (first, second) = args.split_first_mut().expect(BUILTIN); let (first, second) = args.split_first_mut().expect(BUILTIN);
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN); let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
let y = std::mem::take(second[0]).cast::<ImmutableString>(); let y = &*second[0].read_lock::<ImmutableString>().expect(BUILTIN);
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if !x.is_empty() && !y.is_empty() { if !x.is_empty() && !y.is_empty() {
@ -704,7 +704,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
MinusAssign => Some(|_, args| { MinusAssign => Some(|_, args| {
let (first, second) = args.split_first_mut().expect(BUILTIN); let (first, second) = args.split_first_mut().expect(BUILTIN);
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN); let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
let y = std::mem::take(second[0]).cast::<ImmutableString>(); let y = &*second[0].read_lock::<ImmutableString>().expect(BUILTIN);
Ok((*x -= y).into()) Ok((*x -= y).into())
}), }),
_ => None, _ => None,
@ -718,7 +718,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
return match op { return match op {
PlusAssign => Some(|_ctx, args| { PlusAssign => Some(|_ctx, args| {
let x = std::mem::take(args[1]).cast::<Array>(); let x = std::mem::take(args[1]).into_array().expect(BUILTIN);
if x.is_empty() { if x.is_empty() {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
@ -749,7 +749,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
return match op { return match op {
PlusAssign => Some(|_ctx, args| { PlusAssign => Some(|_ctx, args| {
let blob2 = std::mem::take(args[1]).cast::<Blob>(); let blob2 = std::mem::take(args[1]).into_blob().expect(BUILTIN);
let blob1 = &mut *args[0].write_lock::<Blob>().expect(BUILTIN); let blob1 = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -951,14 +951,14 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
return match op { return match op {
PlusAssign => Some(|_ctx, args| { PlusAssign => Some(|_ctx, args| {
let s = std::mem::take(args[1]).cast::<ImmutableString>(); let (first, second) = args.split_first_mut().expect(BUILTIN);
let blob = &mut *first.write_lock::<Blob>().expect(BUILTIN);
let s = &*second[0].read_lock::<ImmutableString>().expect(BUILTIN);
if s.is_empty() { if s.is_empty() {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
} }
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
_ctx.engine().raise_err_if_over_data_size_limit(( _ctx.engine().raise_err_if_over_data_size_limit((
blob.len() + s.len(), blob.len() + s.len(),
@ -966,7 +966,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
0, 0,
))?; ))?;
Ok(append_str(blob, &s).into()) Ok(append_str(blob, s).into())
}), }),
_ => None, _ => None,
}; };

View File

@ -260,10 +260,18 @@ impl Dynamic {
} }
/// Is the value held by this [`Dynamic`] a particular type? /// Is the value held by this [`Dynamic`] a particular type?
/// ///
/// If the [`Dynamic`] is a shared variant checking is performed on top of its internal value. /// # Panics or Deadlocks When Value is Shared
///
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
/// Otherwise, this call panics if the data is currently borrowed for write.
#[inline] #[inline]
#[must_use] #[must_use]
pub fn is<T: Any + Clone>(&self) -> bool { pub fn is<T: Any + Clone>(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
if self.is_shared() {
return TypeId::of::<T>() == self.type_id();
}
if TypeId::of::<T>() == TypeId::of::<()>() { if TypeId::of::<T>() == TypeId::of::<()>() {
return matches!(self.0, Union::Unit(..)); return matches!(self.0, Union::Unit(..));
} }
@ -1819,9 +1827,12 @@ impl Dynamic {
#[inline] #[inline]
pub fn as_unit(&self) -> Result<(), &'static str> { pub fn as_unit(&self) -> Result<(), &'static str> {
match self.0 { match self.0 {
Union::Unit(v, ..) => Ok(v), Union::Unit(..) => Ok(()),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
Union::Unit(..) => Ok(()),
_ => Err(cell.type_name()),
},
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1832,7 +1843,10 @@ impl Dynamic {
match self.0 { match self.0 {
Union::Int(n, ..) => Ok(n), Union::Int(n, ..) => Ok(n),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
Union::Int(n, ..) => Ok(n),
_ => Err(cell.type_name()),
},
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1846,7 +1860,10 @@ impl Dynamic {
match self.0 { match self.0 {
Union::Float(n, ..) => Ok(*n), Union::Float(n, ..) => Ok(*n),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
Union::Float(n, ..) => Ok(*n),
_ => Err(cell.type_name()),
},
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1860,7 +1877,10 @@ impl Dynamic {
match self.0 { match self.0 {
Union::Decimal(ref n, ..) => Ok(**n), Union::Decimal(ref n, ..) => Ok(**n),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
Union::Decimal(ref n, ..) => Ok(**n),
_ => Err(cell.type_name()),
},
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1871,7 +1891,10 @@ impl Dynamic {
match self.0 { match self.0 {
Union::Bool(b, ..) => Ok(b), Union::Bool(b, ..) => Ok(b),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
Union::Bool(b, ..) => Ok(b),
_ => Err(cell.type_name()),
},
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1880,9 +1903,12 @@ impl Dynamic {
#[inline] #[inline]
pub fn as_char(&self) -> Result<char, &'static str> { pub fn as_char(&self) -> Result<char, &'static str> {
match self.0 { match self.0 {
Union::Char(n, ..) => Ok(n), Union::Char(c, ..) => Ok(c),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
Union::Char(c, ..) => Ok(c),
_ => Err(cell.type_name()),
},
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1917,14 +1943,10 @@ impl Dynamic {
match self.0 { match self.0 {
Union::Str(s, ..) => Ok(s), Union::Str(s, ..) => Ok(s),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, ..) => { Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
let value = crate::func::locked_read(cell);
match value.0 {
Union::Str(ref s, ..) => Ok(s.clone()), Union::Str(ref s, ..) => Ok(s.clone()),
_ => Err((*value).type_name()), _ => Err(cell.type_name()),
} },
}
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1938,14 +1960,10 @@ impl Dynamic {
match self.0 { match self.0 {
Union::Array(a, ..) => Ok(*a), Union::Array(a, ..) => Ok(*a),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, ..) => { Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
let value = crate::func::locked_read(cell);
match value.0 {
Union::Array(ref a, ..) => Ok(a.as_ref().clone()), Union::Array(ref a, ..) => Ok(a.as_ref().clone()),
_ => Err((*value).type_name()), _ => Err(cell.type_name()),
} },
}
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }
@ -1973,12 +1991,12 @@ impl Dynamic {
v.try_cast::<T>().ok_or(typ) v.try_cast::<T>().ok_or(typ)
}) })
.collect(), .collect(),
Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => Ok(self.cast::<Vec<T>>()), Union::Blob(b, ..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
Ok(reify!(*b => Vec<T>))
}
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, ..) => { Union::Shared(ref cell, ..) => {
let value = crate::func::locked_read(cell); match crate::func::locked_read(cell).0 {
match value.0 {
Union::Array(ref a, ..) => { Union::Array(ref a, ..) => {
a.iter() a.iter()
.map(|v| { .map(|v| {
@ -1996,10 +2014,10 @@ impl Dynamic {
}) })
.collect() .collect()
} }
Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => { Union::Blob(ref b, ..) if TypeId::of::<T>() == TypeId::of::<u8>() => {
Ok((*value).clone().cast::<Vec<T>>()) Ok(reify!(b.clone() => Vec<T>))
} }
_ => Err((*value).type_name()), _ => Err(cell.type_name()),
} }
} }
_ => Err(self.type_name()), _ => Err(self.type_name()),
@ -2013,16 +2031,12 @@ impl Dynamic {
#[inline(always)] #[inline(always)]
pub fn into_blob(self) -> Result<crate::Blob, &'static str> { pub fn into_blob(self) -> Result<crate::Blob, &'static str> {
match self.0 { match self.0 {
Union::Blob(a, ..) => Ok(*a), Union::Blob(b, ..) => Ok(*b),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(ref cell, ..) => { Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
let value = crate::func::locked_read(cell); Union::Blob(ref b, ..) => Ok(b.as_ref().clone()),
_ => Err(cell.type_name()),
match value.0 { },
Union::Blob(ref a, ..) => Ok(a.as_ref().clone()),
_ => Err((*value).type_name()),
}
}
_ => Err(self.type_name()), _ => Err(self.type_name()),
} }
} }