commit
0603b2b1cc
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.rhai linguist-language=JavaScript
|
@ -264,7 +264,7 @@ impl Module {
|
|||||||
// NB: sub-modules must have their new items for exporting generated in depth-first order
|
// NB: sub-modules must have their new items for exporting generated in depth-first order
|
||||||
// to avoid issues caused by re-parsing them
|
// to avoid issues caused by re-parsing them
|
||||||
let inner_modules = sub_modules
|
let inner_modules = sub_modules
|
||||||
.drain(..)
|
.into_iter()
|
||||||
.try_fold::<_, _, Result<_, syn::Error>>(Vec::new(), |mut acc, m| {
|
.try_fold::<_, _, Result<_, syn::Error>>(Vec::new(), |mut acc, m| {
|
||||||
acc.push(m.generate_inner()?);
|
acc.push(m.generate_inner()?);
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error[E0599]: the method `map` exists for type `bool`, but its trait bounds were not satisfied
|
error[E0599]: `bool` is not an iterator
|
||||||
--> ui_tests/export_fn_raw_return.rs:10:33
|
--> ui_tests/export_fn_raw_return.rs:10:33
|
||||||
|
|
|
|
||||||
10 | pub fn test_fn(input: Point) -> bool {
|
10 | pub fn test_fn(input: Point) -> bool {
|
||||||
| ^^^^ method cannot be called on `bool` due to unsatisfied trait bounds
|
| ^^^^ `bool` is not an iterator
|
||||||
|
|
|
|
||||||
= note: the following trait bounds were not satisfied:
|
= note: the following trait bounds were not satisfied:
|
||||||
`bool: std::iter::Iterator`
|
`bool: std::iter::Iterator`
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error[E0599]: the method `map` exists for type `bool`, but its trait bounds were not satisfied
|
error[E0599]: `bool` is not an iterator
|
||||||
--> ui_tests/export_mod_raw_return.rs:12:33
|
--> ui_tests/export_mod_raw_return.rs:12:33
|
||||||
|
|
|
|
||||||
12 | pub fn test_fn(input: Point) -> bool {
|
12 | pub fn test_fn(input: Point) -> bool {
|
||||||
| ^^^^ method cannot be called on `bool` due to unsatisfied trait bounds
|
| ^^^^ `bool` is not an iterator
|
||||||
|
|
|
|
||||||
= note: the following trait bounds were not satisfied:
|
= note: the following trait bounds were not satisfied:
|
||||||
`bool: std::iter::Iterator`
|
`bool: std::iter::Iterator`
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
|
error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
|
||||||
--> ui_tests/non_clonable.rs:11:23
|
--> ui_tests/non_clonable.rs:11:23
|
||||||
|
|
|
|
||||||
|
10 | #[export_fn]
|
||||||
|
| ------------ in this procedural macro expansion
|
||||||
11 | pub fn test_fn(input: NonClonable) -> bool {
|
11 | pub fn test_fn(input: NonClonable) -> bool {
|
||||||
| ^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
|
| ^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
|
||||||
|
|
|
|
||||||
@ -9,3 +11,4 @@ note: required by a bound in `rhai::Dynamic::cast`
|
|||||||
|
|
|
|
||||||
| pub fn cast<T: Any + Clone>(self) -> T {
|
| pub fn cast<T: Any + Clone>(self) -> T {
|
||||||
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
||||||
|
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
|
error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
|
||||||
--> ui_tests/non_clonable_second.rs:11:27
|
--> ui_tests/non_clonable_second.rs:11:27
|
||||||
|
|
|
|
||||||
|
10 | #[export_fn]
|
||||||
|
| ------------ in this procedural macro expansion
|
||||||
11 | pub fn test_fn(a: u32, b: NonClonable) -> bool {
|
11 | pub fn test_fn(a: u32, b: NonClonable) -> bool {
|
||||||
| ^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
|
| ^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
|
||||||
|
|
|
|
||||||
@ -9,3 +11,4 @@ note: required by a bound in `rhai::Dynamic::cast`
|
|||||||
|
|
|
|
||||||
| pub fn cast<T: Any + Clone>(self) -> T {
|
| pub fn cast<T: Any + Clone>(self) -> T {
|
||||||
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
||||||
|
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
@ -69,12 +69,8 @@ impl Engine {
|
|||||||
let typ = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
result.try_cast().ok_or_else(|| {
|
result.try_cast().ok_or_else(|| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = self.map_type_name(type_name::<T>()).into();
|
||||||
self.map_type_name(type_name::<T>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into()
|
||||||
typ.into(),
|
|
||||||
Position::NONE,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments and the
|
/// Call a script function defined in an [`AST`] with multiple [`Dynamic`] arguments and the
|
||||||
|
@ -195,12 +195,8 @@ impl Engine {
|
|||||||
let typ = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
result.try_cast::<T>().ok_or_else(|| {
|
result.try_cast::<T>().ok_or_else(|| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = self.map_type_name(type_name::<T>()).into();
|
||||||
self.map_type_name(type_name::<T>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into()
|
||||||
typ.into(),
|
|
||||||
Position::NONE,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Evaluate an [`AST`] with own scope.
|
/// Evaluate an [`AST`] with own scope.
|
||||||
|
@ -125,7 +125,7 @@ impl Engine {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn make_type_mismatch_err<T>(&self, typ: &str, pos: Position) -> RhaiError {
|
pub(crate) fn make_type_mismatch_err<T>(&self, typ: &str, pos: Position) -> RhaiError {
|
||||||
ERR::ErrorMismatchDataType(self.map_type_name(type_name::<T>()).into(), typ.into(), pos)
|
let t = self.map_type_name(type_name::<T>()).into();
|
||||||
.into()
|
ERR::ErrorMismatchDataType(t, typ.into(), pos).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
144
src/func/call.rs
144
src/func/call.rs
@ -37,6 +37,7 @@ struct ArgBackup<'a> {
|
|||||||
|
|
||||||
impl<'a> ArgBackup<'a> {
|
impl<'a> ArgBackup<'a> {
|
||||||
/// Create a new `ArgBackup`.
|
/// Create a new `ArgBackup`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
orig_mut: None,
|
orig_mut: None,
|
||||||
@ -60,8 +61,8 @@ impl<'a> ArgBackup<'a> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics when `args` is empty.
|
/// Panics when `args` is empty.
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn change_first_arg_to_copy(&mut self, args: &mut FnCallArgs<'a>) {
|
pub fn change_first_arg_to_copy(&mut self, args: &mut FnCallArgs<'a>) {
|
||||||
// Clone the original value.
|
// Clone the original value.
|
||||||
self.value_copy = args[0].clone();
|
self.value_copy = args[0].clone();
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ impl<'a> ArgBackup<'a> {
|
|||||||
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_
|
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_
|
||||||
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
|
pub fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
|
||||||
if let Some(p) = self.orig_mut.take() {
|
if let Some(p) = self.orig_mut.take() {
|
||||||
args[0] = p;
|
args[0] = p;
|
||||||
}
|
}
|
||||||
@ -94,7 +95,7 @@ impl<'a> ArgBackup<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ArgBackup<'_> {
|
impl Drop for ArgBackup<'_> {
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Panic if the shorter lifetime leaks.
|
// Panic if the shorter lifetime leaks.
|
||||||
assert!(
|
assert!(
|
||||||
@ -382,15 +383,12 @@ impl Engine {
|
|||||||
let mut _result = if let Some(FnResolutionCacheEntry { func, source }) = func {
|
let mut _result = if let Some(FnResolutionCacheEntry { func, source }) = func {
|
||||||
assert!(func.is_native());
|
assert!(func.is_native());
|
||||||
|
|
||||||
|
let mut backup = ArgBackup::new();
|
||||||
|
|
||||||
// Calling pure function but the first argument is a reference?
|
// Calling pure function but the first argument is a reference?
|
||||||
let mut backup: Option<ArgBackup> = None;
|
|
||||||
if is_ref_mut && func.is_pure() && !args.is_empty() {
|
if is_ref_mut && func.is_pure() && !args.is_empty() {
|
||||||
// Clone the first argument
|
// Clone the first argument
|
||||||
backup = Some(ArgBackup::new());
|
backup.change_first_arg_to_copy(args);
|
||||||
backup
|
|
||||||
.as_mut()
|
|
||||||
.expect("`Some`")
|
|
||||||
.change_first_arg_to_copy(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let source = match (source.as_str(), parent_source.as_str()) {
|
let source = match (source.as_str(), parent_source.as_str()) {
|
||||||
@ -420,9 +418,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
if let Some(bk) = backup {
|
backup.restore_first_arg(args);
|
||||||
bk.restore_first_arg(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
@ -470,11 +466,8 @@ impl Engine {
|
|||||||
KEYWORD_PRINT => {
|
KEYWORD_PRINT => {
|
||||||
if let Some(ref print) = self.print {
|
if let Some(ref print) = self.print {
|
||||||
let text = result.into_immutable_string().map_err(|typ| {
|
let text = result.into_immutable_string().map_err(|typ| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = self.map_type_name(type_name::<ImmutableString>()).into();
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), pos)
|
||||||
typ.into(),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
(print(&text).into(), false)
|
(print(&text).into(), false)
|
||||||
} else {
|
} else {
|
||||||
@ -484,11 +477,8 @@ impl Engine {
|
|||||||
KEYWORD_DEBUG => {
|
KEYWORD_DEBUG => {
|
||||||
if let Some(ref debug) = self.debug {
|
if let Some(ref debug) = self.debug {
|
||||||
let text = result.into_immutable_string().map_err(|typ| {
|
let text = result.into_immutable_string().map_err(|typ| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = self.map_type_name(type_name::<ImmutableString>()).into();
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), pos)
|
||||||
typ.into(),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
let source = match global.source.as_str() {
|
let source = match global.source.as_str() {
|
||||||
"" => None,
|
"" => None,
|
||||||
@ -511,15 +501,10 @@ impl Engine {
|
|||||||
crate::engine::FN_IDX_GET => {
|
crate::engine::FN_IDX_GET => {
|
||||||
assert!(args.len() == 2);
|
assert!(args.len() == 2);
|
||||||
|
|
||||||
Err(ERR::ErrorIndexingType(
|
let t0 = self.map_type_name(args[0].type_name());
|
||||||
format!(
|
let t1 = self.map_type_name(args[1].type_name());
|
||||||
"{} [{}]",
|
|
||||||
self.map_type_name(args[0].type_name()),
|
Err(ERR::ErrorIndexingType(format!("{} [{}]", t0, t1), pos).into())
|
||||||
self.map_type_name(args[1].type_name())
|
|
||||||
),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// index setter function not found?
|
// index setter function not found?
|
||||||
@ -527,16 +512,11 @@ impl Engine {
|
|||||||
crate::engine::FN_IDX_SET => {
|
crate::engine::FN_IDX_SET => {
|
||||||
assert!(args.len() == 3);
|
assert!(args.len() == 3);
|
||||||
|
|
||||||
Err(ERR::ErrorIndexingType(
|
let t0 = self.map_type_name(args[0].type_name());
|
||||||
format!(
|
let t1 = self.map_type_name(args[1].type_name());
|
||||||
"{} [{}] = {}",
|
let t2 = self.map_type_name(args[2].type_name());
|
||||||
self.map_type_name(args[0].type_name()),
|
|
||||||
self.map_type_name(args[1].type_name()),
|
Err(ERR::ErrorIndexingType(format!("{} [{}] = {}", t0, t1, t2), pos).into())
|
||||||
self.map_type_name(args[2].type_name())
|
|
||||||
),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter function not found?
|
// Getter function not found?
|
||||||
@ -544,11 +524,13 @@ impl Engine {
|
|||||||
_ if name.starts_with(crate::engine::FN_GET) => {
|
_ if name.starts_with(crate::engine::FN_GET) => {
|
||||||
assert!(args.len() == 1);
|
assert!(args.len() == 1);
|
||||||
|
|
||||||
|
let prop = &name[crate::engine::FN_GET.len()..];
|
||||||
|
let t0 = self.map_type_name(args[0].type_name());
|
||||||
|
|
||||||
Err(ERR::ErrorDotExpr(
|
Err(ERR::ErrorDotExpr(
|
||||||
format!(
|
format!(
|
||||||
"Unknown property '{}' - a getter is not registered for type '{}'",
|
"Unknown property '{}' - a getter is not registered for type '{}'",
|
||||||
&name[crate::engine::FN_GET.len()..],
|
prop, t0
|
||||||
self.map_type_name(args[0].type_name())
|
|
||||||
),
|
),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
@ -560,12 +542,14 @@ impl Engine {
|
|||||||
_ if name.starts_with(crate::engine::FN_SET) => {
|
_ if name.starts_with(crate::engine::FN_SET) => {
|
||||||
assert!(args.len() == 2);
|
assert!(args.len() == 2);
|
||||||
|
|
||||||
|
let prop = &name[crate::engine::FN_SET.len()..];
|
||||||
|
let t0 = self.map_type_name(args[0].type_name());
|
||||||
|
let t1 = self.map_type_name(args[1].type_name());
|
||||||
|
|
||||||
Err(ERR::ErrorDotExpr(
|
Err(ERR::ErrorDotExpr(
|
||||||
format!(
|
format!(
|
||||||
"No writable property '{}' - a setter is not registered for type '{}' to handle '{}'",
|
"No writable property '{}' - a setter is not registered for type '{}' to handle '{}'",
|
||||||
&name[crate::engine::FN_SET.len()..],
|
prop, t0, t1
|
||||||
self.map_type_name(args[0].type_name()),
|
|
||||||
self.map_type_name(args[1].type_name()),
|
|
||||||
),
|
),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
@ -612,8 +596,11 @@ impl Engine {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
fn no_method_err(name: &str, pos: Position) -> RhaiResultOf<(Dynamic, bool)> {
|
fn no_method_err(name: &str, pos: Position) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
let msg = format!("'{0}' should not be called this way. Try {0}(...);", name);
|
Err(ERR::ErrorRuntime(
|
||||||
Err(ERR::ErrorRuntime(msg.into(), pos).into())
|
(format!("'{0}' should not be called this way. Try {0}(...);", name)).into(),
|
||||||
|
pos,
|
||||||
|
)
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
@ -627,10 +614,8 @@ impl Engine {
|
|||||||
match fn_name {
|
match fn_name {
|
||||||
// Handle type_of()
|
// Handle type_of()
|
||||||
KEYWORD_TYPE_OF if args.len() == 1 => {
|
KEYWORD_TYPE_OF if args.len() == 1 => {
|
||||||
return Ok((
|
let typ = self.map_type_name(args[0].type_name()).to_string().into();
|
||||||
self.map_type_name(args[0].type_name()).to_string().into(),
|
return Ok((typ, false));
|
||||||
false,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle is_def_fn()
|
// Handle is_def_fn()
|
||||||
@ -711,7 +696,7 @@ impl Engine {
|
|||||||
// Method call of script function - map first argument to `this`
|
// Method call of script function - map first argument to `this`
|
||||||
let (first_arg, rest_args) = args.split_first_mut().unwrap();
|
let (first_arg, rest_args) = args.split_first_mut().unwrap();
|
||||||
|
|
||||||
let result = self.call_script_fn(
|
self.call_script_fn(
|
||||||
scope,
|
scope,
|
||||||
global,
|
global,
|
||||||
state,
|
state,
|
||||||
@ -722,19 +707,14 @@ impl Engine {
|
|||||||
true,
|
true,
|
||||||
pos,
|
pos,
|
||||||
level,
|
level,
|
||||||
);
|
)
|
||||||
|
|
||||||
result?
|
|
||||||
} else {
|
} else {
|
||||||
// Normal call of script function
|
// Normal call of script function
|
||||||
|
let mut backup = ArgBackup::new();
|
||||||
|
|
||||||
// The first argument is a reference?
|
// The first argument is a reference?
|
||||||
let mut backup: Option<ArgBackup> = None;
|
|
||||||
if is_ref_mut && !args.is_empty() {
|
if is_ref_mut && !args.is_empty() {
|
||||||
backup = Some(ArgBackup::new());
|
backup.change_first_arg_to_copy(args);
|
||||||
backup
|
|
||||||
.as_mut()
|
|
||||||
.expect("`Some`")
|
|
||||||
.change_first_arg_to_copy(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self.call_script_fn(
|
let result = self.call_script_fn(
|
||||||
@ -742,17 +722,15 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
if let Some(bk) = backup {
|
backup.restore_first_arg(args);
|
||||||
bk.restore_first_arg(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
result?
|
result
|
||||||
};
|
};
|
||||||
|
|
||||||
// Restore the original source
|
// Restore the original source
|
||||||
mem::swap(&mut global.source, &mut source);
|
mem::swap(&mut global.source, &mut source);
|
||||||
|
|
||||||
return Ok((result, false));
|
return Ok((result?, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native function call
|
// Native function call
|
||||||
@ -827,16 +805,12 @@ impl Engine {
|
|||||||
KEYWORD_FN_PTR_CALL => {
|
KEYWORD_FN_PTR_CALL => {
|
||||||
if !call_args.is_empty() {
|
if !call_args.is_empty() {
|
||||||
if !call_args[0].is::<FnPtr>() {
|
if !call_args[0].is::<FnPtr>() {
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
let typ = self.map_type_name(call_args[0].type_name());
|
||||||
self.map_type_name(call_args[0].type_name()),
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, *call_arg_pos));
|
||||||
*call_arg_pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
let typ = self.map_type_name(target.type_name());
|
||||||
self.map_type_name(target.type_name()),
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, pos));
|
||||||
pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FnPtr call on object
|
// FnPtr call on object
|
||||||
@ -866,10 +840,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
KEYWORD_FN_PTR_CURRY => {
|
KEYWORD_FN_PTR_CURRY => {
|
||||||
if !target.is::<FnPtr>() {
|
if !target.is::<FnPtr>() {
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
let typ = self.map_type_name(target.type_name());
|
||||||
self.map_type_name(target.type_name()),
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, pos));
|
||||||
pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
||||||
@ -1016,10 +988,8 @@ impl Engine {
|
|||||||
self.get_arg_value(scope, global, state, lib, this_ptr, arg, level)?;
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, level)?;
|
||||||
|
|
||||||
if !arg_value.is::<FnPtr>() {
|
if !arg_value.is::<FnPtr>() {
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
let typ = self.map_type_name(arg_value.type_name());
|
||||||
self.map_type_name(arg_value.type_name()),
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, arg_pos));
|
||||||
arg_pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let fn_ptr = arg_value.cast::<FnPtr>();
|
let fn_ptr = arg_value.cast::<FnPtr>();
|
||||||
@ -1066,10 +1036,8 @@ impl Engine {
|
|||||||
self.get_arg_value(scope, global, state, lib, this_ptr, first, level)?;
|
self.get_arg_value(scope, global, state, lib, this_ptr, first, level)?;
|
||||||
|
|
||||||
if !arg_value.is::<FnPtr>() {
|
if !arg_value.is::<FnPtr>() {
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(
|
let typ = self.map_type_name(arg_value.type_name());
|
||||||
self.map_type_name(arg_value.type_name()),
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, arg_pos));
|
||||||
arg_pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
let (name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
||||||
|
@ -277,12 +277,8 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
let typ = self.engine().map_type_name(result.type_name());
|
let typ = self.engine().map_type_name(result.type_name());
|
||||||
|
|
||||||
result.try_cast().ok_or_else(|| {
|
result.try_cast().ok_or_else(|| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = self.engine().map_type_name(type_name::<T>()).into();
|
||||||
self.engine().map_type_name(type_name::<T>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into()
|
||||||
typ.into(),
|
|
||||||
Position::NONE,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Call a function inside the call context.
|
/// Call a function inside the call context.
|
||||||
@ -348,7 +344,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume a [`Shared`] resource and return a mutable reference to the wrapped value.
|
/// Return a mutable reference to the wrapped value of a [`Shared`] resource.
|
||||||
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
|
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -357,6 +353,14 @@ pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
|
|||||||
Shared::make_mut(value)
|
Shared::make_mut(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a mutable reference to the wrapped value of a [`Shared`] resource.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn shared_get_mut<T: Clone>(value: &mut Shared<T>) -> Option<&mut T> {
|
||||||
|
Shared::get_mut(value)
|
||||||
|
}
|
||||||
|
|
||||||
/// Consume a [`Shared`] resource if is unique (i.e. not shared), or clone it otherwise.
|
/// Consume a [`Shared`] resource if is unique (i.e. not shared), or clone it otherwise.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -1085,7 +1085,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
match x.name.as_str() {
|
match x.name.as_str() {
|
||||||
KEYWORD_TYPE_OF if arg_values.len() == 1 => {
|
KEYWORD_TYPE_OF if arg_values.len() == 1 => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::from_dynamic(state.engine.map_type_name(arg_values[0].type_name()).into(), *pos);
|
let typ = state.engine.map_type_name(arg_values[0].type_name()).into();
|
||||||
|
*expr = Expr::from_dynamic(typ, *pos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
@ -193,7 +193,11 @@ mod string_functions {
|
|||||||
/// Clear the string, making it empty.
|
/// Clear the string, making it empty.
|
||||||
pub fn clear(string: &mut ImmutableString) {
|
pub fn clear(string: &mut ImmutableString) {
|
||||||
if !string.is_empty() {
|
if !string.is_empty() {
|
||||||
string.make_mut().clear();
|
if let Some(s) = string.get_mut() {
|
||||||
|
s.clear();
|
||||||
|
} else {
|
||||||
|
*string = ImmutableString::new();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Cut off the string at the specified number of characters.
|
/// Cut off the string at the specified number of characters.
|
||||||
@ -220,8 +224,8 @@ mod string_functions {
|
|||||||
let copy = string.make_mut();
|
let copy = string.make_mut();
|
||||||
copy.clear();
|
copy.clear();
|
||||||
copy.extend(chars.into_iter().take(len as usize));
|
copy.extend(chars.into_iter().take(len as usize));
|
||||||
} else if !string.is_empty() {
|
} else {
|
||||||
string.make_mut().clear();
|
clear(string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Remove whitespace characters from both ends of the string.
|
/// Remove whitespace characters from both ends of the string.
|
||||||
@ -231,13 +235,23 @@ mod string_functions {
|
|||||||
/// ```rhai
|
/// ```rhai
|
||||||
/// let text = " hello ";
|
/// let text = " hello ";
|
||||||
///
|
///
|
||||||
/// print(text.trim()); // prints "hello"
|
/// text.trim();
|
||||||
|
///
|
||||||
|
/// print(text); // prints "hello"
|
||||||
/// ```
|
/// ```
|
||||||
pub fn trim(string: &mut ImmutableString) {
|
pub fn trim(string: &mut ImmutableString) {
|
||||||
let trimmed = string.trim();
|
if let Some(s) = string.get_mut() {
|
||||||
|
let trimmed = s.trim();
|
||||||
|
|
||||||
if trimmed.len() < string.len() {
|
if trimmed != s {
|
||||||
*string = trimmed.to_string().into();
|
*s = trimmed.into();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let trimmed = string.trim();
|
||||||
|
|
||||||
|
if trimmed != string {
|
||||||
|
*string = trimmed.into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Remove the last character from the string and return it.
|
/// Remove the last character from the string and return it.
|
||||||
@ -313,7 +327,7 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(pure)]
|
#[rhai_fn(pure)]
|
||||||
pub fn to_upper(string: &mut ImmutableString) -> ImmutableString {
|
pub fn to_upper(string: &mut ImmutableString) -> ImmutableString {
|
||||||
if string.is_empty() || string.chars().all(char::is_uppercase) {
|
if string.chars().all(char::is_uppercase) {
|
||||||
string.clone()
|
string.clone()
|
||||||
} else {
|
} else {
|
||||||
string.to_uppercase().into()
|
string.to_uppercase().into()
|
||||||
@ -366,7 +380,7 @@ mod string_functions {
|
|||||||
/// print(text); // prints "hello, world!";
|
/// print(text); // prints "hello, world!";
|
||||||
/// ```
|
/// ```
|
||||||
pub fn make_lower(string: &mut ImmutableString) {
|
pub fn make_lower(string: &mut ImmutableString) {
|
||||||
if !string.is_empty() && string.chars().any(|ch| !ch.is_lowercase()) {
|
if string.chars().any(|ch| !ch.is_lowercase()) {
|
||||||
*string = string.to_lowercase().into();
|
*string = string.to_lowercase().into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,12 +162,8 @@ impl FnPtr {
|
|||||||
let typ = engine.map_type_name(result.type_name());
|
let typ = engine.map_type_name(result.type_name());
|
||||||
|
|
||||||
result.try_cast().ok_or_else(|| {
|
result.try_cast().ok_or_else(|| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = engine.map_type_name(type_name::<T>()).into();
|
||||||
engine.map_type_name(type_name::<T>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into()
|
||||||
typ.into(),
|
|
||||||
Position::NONE,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Call the function pointer with curried arguments (if any).
|
/// Call the function pointer with curried arguments (if any).
|
||||||
@ -190,12 +186,8 @@ impl FnPtr {
|
|||||||
let typ = context.engine().map_type_name(result.type_name());
|
let typ = context.engine().map_type_name(result.type_name());
|
||||||
|
|
||||||
result.try_cast().ok_or_else(|| {
|
result.try_cast().ok_or_else(|| {
|
||||||
ERR::ErrorMismatchOutputType(
|
let t = context.engine().map_type_name(type_name::<T>()).into();
|
||||||
context.engine().map_type_name(type_name::<T>()).into(),
|
ERR::ErrorMismatchOutputType(t, typ.into(), Position::NONE).into()
|
||||||
typ.into(),
|
|
||||||
Position::NONE,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// Call the function pointer with curried arguments (if any).
|
/// Call the function pointer with curried arguments (if any).
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! The `ImmutableString` type.
|
//! The `ImmutableString` type.
|
||||||
|
|
||||||
use crate::func::native::{shared_make_mut, shared_take};
|
use crate::func::native::{shared_get_mut, shared_make_mut, shared_take};
|
||||||
use crate::{Shared, SmartString};
|
use crate::{Shared, SmartString};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -580,6 +580,7 @@ impl ImmutableString {
|
|||||||
Self(SmartString::new_const().into())
|
Self(SmartString::new_const().into())
|
||||||
}
|
}
|
||||||
/// Consume the [`ImmutableString`] and convert it into a [`String`].
|
/// Consume the [`ImmutableString`] and convert it into a [`String`].
|
||||||
|
///
|
||||||
/// If there are other references to the same string, a cloned copy is returned.
|
/// If there are other references to the same string, a cloned copy is returned.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_owned(mut self) -> String {
|
pub fn into_owned(mut self) -> String {
|
||||||
@ -588,10 +589,17 @@ impl ImmutableString {
|
|||||||
}
|
}
|
||||||
/// Make sure that the [`ImmutableString`] is unique (i.e. no other outstanding references).
|
/// Make sure that the [`ImmutableString`] is unique (i.e. no other outstanding references).
|
||||||
/// Then return a mutable reference to the [`SmartString`].
|
/// Then return a mutable reference to the [`SmartString`].
|
||||||
|
///
|
||||||
|
/// If there are other references to the same string, a cloned copy is used.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn make_mut(&mut self) -> &mut SmartString {
|
pub(crate) fn make_mut(&mut self) -> &mut SmartString {
|
||||||
shared_make_mut(&mut self.0)
|
shared_make_mut(&mut self.0)
|
||||||
}
|
}
|
||||||
|
/// Return a mutable reference to the [`SmartString`] wrapped by the [`ImmutableString`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_mut(&mut self) -> Option<&mut SmartString> {
|
||||||
|
shared_get_mut(&mut self.0)
|
||||||
|
}
|
||||||
/// Returns `true` if the two [`ImmutableString`]'s point to the same allocation.
|
/// Returns `true` if the two [`ImmutableString`]'s point to the same allocation.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
Loading…
Reference in New Issue
Block a user