Add Dynamic::clone_cast.
This commit is contained in:
parent
ec7b906f71
commit
b14d18934a
@ -56,6 +56,7 @@ Enhancements
|
|||||||
* Replaced all `HashMap` usage with `BTreeMap` for better performance because collections in Rhai are tiny.
|
* Replaced all `HashMap` usage with `BTreeMap` for better performance because collections in Rhai are tiny.
|
||||||
* `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any clonable type.
|
* `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any clonable type.
|
||||||
* `#[rhai_fn(return_raw)]` can now return `Result<T, Box<EvalAltResult>>` where `T` is any clonable type instead of `Result<Dynamic, Box<EvalAltResult>>`.
|
* `#[rhai_fn(return_raw)]` can now return `Result<T, Box<EvalAltResult>>` where `T` is any clonable type instead of `Result<Dynamic, Box<EvalAltResult>>`.
|
||||||
|
* `Dynamic::clone_cast` is added to simplify casting from a `&Dynamic`.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.14
|
Version 0.19.14
|
||||||
|
@ -1131,6 +1131,37 @@ impl Dynamic {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/// Clone the [`Dynamic`] value and convert it into a specific type.
|
||||||
|
///
|
||||||
|
/// Casting to a [`Dynamic`] just returns as is, but if it contains a shared value,
|
||||||
|
/// it is cloned into a [`Dynamic`] with a normal value.
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if types mismatched.
|
||||||
|
///
|
||||||
|
/// # Panics or Deadlocks
|
||||||
|
///
|
||||||
|
/// Panics if the cast fails (e.g. the type of the actual value is not the
|
||||||
|
/// same as the specified type).
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// These normally shouldn't occur since most operations in Rhai is single-threaded.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Dynamic;
|
||||||
|
///
|
||||||
|
/// let x = Dynamic::from(42_u32);
|
||||||
|
/// let y = &x;
|
||||||
|
///
|
||||||
|
/// assert_eq!(y.clone_cast::<u32>(), 42);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clone_cast<T: Variant + Clone>(&self) -> T {
|
||||||
|
self.read_lock::<T>().unwrap().clone()
|
||||||
|
}
|
||||||
/// Flatten the [`Dynamic`] and clone it.
|
/// Flatten the [`Dynamic`] and clone it.
|
||||||
///
|
///
|
||||||
/// If the [`Dynamic`] is not a shared value, it returns a cloned copy.
|
/// If the [`Dynamic`] is not a shared value, it returns a cloned copy.
|
||||||
|
@ -768,7 +768,7 @@ impl Module {
|
|||||||
/// // Get the second parameter by 'consuming' it
|
/// // Get the second parameter by 'consuming' it
|
||||||
/// let double = std::mem::take(args[1]).cast::<bool>();
|
/// let double = std::mem::take(args[1]).cast::<bool>();
|
||||||
/// // Since it is a primary type, it can also be cheaply copied
|
/// // Since it is a primary type, it can also be cheaply copied
|
||||||
/// let double = args[1].clone().cast::<bool>();
|
/// let double = args[1].clone_cast::<bool>();
|
||||||
/// // Get a mutable reference to the first argument.
|
/// // Get a mutable reference to the first argument.
|
||||||
/// let mut x = args[0].write_lock::<i64>().unwrap();
|
/// let mut x = args[0].write_lock::<i64>().unwrap();
|
||||||
///
|
///
|
||||||
|
@ -183,7 +183,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i8>()
|
.downclone_cast::<i8>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i16>()
|
.downclone_cast::<i16>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +205,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i32>()
|
.downclone_cast::<i32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i64>()
|
.downclone_cast::<i64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i128>()
|
.downclone_cast::<i128>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u8>()
|
.downclone_cast::<u8>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u16>()
|
.downclone_cast::<u16>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,7 +259,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u32>()
|
.downclone_cast::<u32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u64>()
|
.downclone_cast::<u64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,7 +279,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u128>()
|
.downclone_cast::<u128>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return self
|
return self
|
||||||
.value
|
.value
|
||||||
.downcast_ref::<f32>()
|
.downclone_cast::<f32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
@ -298,7 +298,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
.value
|
.value
|
||||||
.downcast_ref::<rust_decimal::Decimal>()
|
.downclone_cast::<rust_decimal::Decimal>()
|
||||||
.and_then(|&x| x.to_f32())
|
.and_then(|&x| x.to_f32())
|
||||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
||||||
}
|
}
|
||||||
@ -312,7 +312,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return self
|
return self
|
||||||
.value
|
.value
|
||||||
.downcast_ref::<f64>()
|
.downclone_cast::<f64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
@ -322,7 +322,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
.value
|
.value
|
||||||
.downcast_ref::<rust_decimal::Decimal>()
|
.downclone_cast::<rust_decimal::Decimal>()
|
||||||
.and_then(|&x| x.to_f64())
|
.and_then(|&x| x.to_f64())
|
||||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
||||||
}
|
}
|
||||||
@ -334,12 +334,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<char>()
|
.downclone_cast::<char>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_char(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_char(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value.downcast_ref::<ImmutableString>().map_or_else(
|
self.value.downclone_cast::<ImmutableString>().map_or_else(
|
||||||
|| self.type_error(),
|
|| self.type_error(),
|
||||||
|x| visitor.visit_borrowed_str(x.as_str()),
|
|x| visitor.visit_borrowed_str(x.as_str()),
|
||||||
)
|
)
|
||||||
@ -366,7 +366,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<()>()
|
.downclone_cast::<()>()
|
||||||
.map_or_else(|| self.type_error(), |_| visitor.visit_unit())
|
.map_or_else(|| self.type_error(), |_| visitor.visit_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +388,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return self.value.downcast_ref::<Array>().map_or_else(
|
return self.value.downclone_cast::<Array>().map_or_else(
|
||||||
|| self.type_error(),
|
|| self.type_error(),
|
||||||
|arr| _visitor.visit_seq(IterateArray::new(arr.iter())),
|
|arr| _visitor.visit_seq(IterateArray::new(arr.iter())),
|
||||||
);
|
);
|
||||||
@ -416,7 +416,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return self.value.downcast_ref::<Map>().map_or_else(
|
return self.value.downclone_cast::<Map>().map_or_else(
|
||||||
|| self.type_error(),
|
|| self.type_error(),
|
||||||
|map| {
|
|map| {
|
||||||
_visitor.visit_map(IterateMap::new(
|
_visitor.visit_map(IterateMap::new(
|
||||||
@ -449,7 +449,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
visitor.visit_enum(s.as_str().into_deserializer())
|
visitor.visit_enum(s.as_str().into_deserializer())
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
if let Some(map) = self.value.downcast_ref::<Map>() {
|
if let Some(map) = self.value.downclone_cast::<Map>() {
|
||||||
let mut iter = map.iter();
|
let mut iter = map.iter();
|
||||||
let first = iter.next();
|
let first = iter.next();
|
||||||
let second = iter.next();
|
let second = iter.next();
|
||||||
|
@ -59,6 +59,11 @@ fn test_arrays() -> Result<(), Box<EvalAltResult>> {
|
|||||||
5
|
5
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut a = Array::new();
|
||||||
|
a.push((42 as INT).into());
|
||||||
|
|
||||||
|
assert_eq!(a[0].clone_cast::<INT>(), 42);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ fn test_closures_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
// Make closure
|
// Make closure
|
||||||
let f = move |p1: TestStruct, p2: TestStruct| -> Result<(), Box<EvalAltResult>> {
|
let f = move |p1: TestStruct, p2: TestStruct| -> Result<(), Box<EvalAltResult>> {
|
||||||
let action_ptr = res["action"].clone().cast::<FnPtr>();
|
let action_ptr = res["action"].clone_cast::<FnPtr>();
|
||||||
let name = action_ptr.fn_name();
|
let name = action_ptr.fn_name();
|
||||||
engine.call_fn(&mut Scope::new(), &ast, name, (p1, p2))
|
engine.call_fn(&mut Scope::new(), &ast, name, (p1, p2))
|
||||||
};
|
};
|
||||||
|
@ -94,9 +94,9 @@ fn test_map_assign() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let x = engine.eval::<Map>(r#"let x = #{a: 1, b: true, "c$": "hello"}; x"#)?;
|
let x = engine.eval::<Map>(r#"let x = #{a: 1, b: true, "c$": "hello"}; x"#)?;
|
||||||
|
|
||||||
assert_eq!(x["a"].clone().cast::<INT>(), 1);
|
assert_eq!(x["a"].clone_cast::<INT>(), 1);
|
||||||
assert_eq!(x["b"].clone().cast::<bool>(), true);
|
assert_eq!(x["b"].clone_cast::<bool>(), true);
|
||||||
assert_eq!(x["c$"].clone().cast::<String>(), "hello");
|
assert_eq!(x["c$"].clone_cast::<String>(), "hello");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -107,9 +107,9 @@ fn test_map_return() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let x = engine.eval::<Map>(r#"#{a: 1, b: true, "c$": "hello"}"#)?;
|
let x = engine.eval::<Map>(r#"#{a: 1, b: true, "c$": "hello"}"#)?;
|
||||||
|
|
||||||
assert_eq!(x["a"].clone().cast::<INT>(), 1);
|
assert_eq!(x["a"].clone_cast::<INT>(), 1);
|
||||||
assert_eq!(x["b"].clone().cast::<bool>(), true);
|
assert_eq!(x["b"].clone_cast::<bool>(), true);
|
||||||
assert_eq!(x["c$"].clone().cast::<String>(), "hello");
|
assert_eq!(x["c$"].clone_cast::<String>(), "hello");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -152,11 +152,11 @@ fn test_map_json() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(!map.contains_key("x"));
|
assert!(!map.contains_key("x"));
|
||||||
|
|
||||||
assert_eq!(map["a"].clone().cast::<INT>(), 1);
|
assert_eq!(map["a"].clone_cast::<INT>(), 1);
|
||||||
assert_eq!(map["b"].clone().cast::<bool>(), true);
|
assert_eq!(map["b"].clone_cast::<bool>(), true);
|
||||||
assert_eq!(map["c"].clone().cast::<INT>(), 42);
|
assert_eq!(map["c"].clone_cast::<INT>(), 42);
|
||||||
assert_eq!(map["$d e f!"].clone().cast::<String>(), "hello");
|
assert_eq!(map["$d e f!"].clone_cast::<String>(), "hello");
|
||||||
assert_eq!(map["z"].clone().cast::<()>(), ());
|
assert_eq!(map["z"].clone_cast::<()>(), ());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user