diff --git a/CHANGELOG.md b/CHANGELOG.md index f4efcd1e..59875fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Enhancements * Array methods now avoid cloning as much as possible (although most predicates will involve cloning anyway if passed a closure). * Array methods that take function pointers (e.g. closures) now optionally take the function name as a string. * Array adds the `dedup` method. +* Array adds a `sort` method with no parameters which sorts homogeneous arrays of built-in comparable types (e.g. `INT`). * Inlining is disabled for error-path functions because errors are exceptional and scripts usually fail completely when an error is encountered. * The `optimize` module is completely eliminated under `no_optimize`, which should yield smaller code size. diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 8d3ab3ac..51c1bcc0 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -809,7 +809,7 @@ mod array_functions { array: &mut Array, comparer: FnPtr, ) -> Result<(), Box> { - if array.is_empty() { + if array.len() <= 1 { return Ok(()); } @@ -829,6 +829,82 @@ mod array_functions { Ok(()) } + #[rhai_fn(name = "sort", return_raw)] + pub fn sort_with_builtin(array: &mut Array) -> Result<(), Box> { + if array.len() <= 1 { + return Ok(()); + } + + let type_id = array[0].type_id(); + + if array.iter().any(|a| a.type_id() != type_id) { + return Err(EvalAltResult::ErrorFunctionNotFound( + "sort() cannot be called with elements of different types".into(), + Position::NONE, + ) + .into()); + } + + if type_id == TypeId::of::() { + array.sort_by(|a, b| { + let a = a.as_int().expect("a is INT"); + let b = b.as_int().expect("b is INT"); + a.cmp(&b) + }); + return Ok(()); + } + if type_id == TypeId::of::() { + array.sort_by(|a, b| { + let a = a.as_char().expect("a is char"); + let b = b.as_char().expect("b is char"); + a.cmp(&b) + }); + return Ok(()); + } + #[cfg(not(feature = "no_float"))] + if type_id == TypeId::of::() { + array.sort_by(|a, b| { + let a = a.as_float().expect("a is FLOAT"); + let b = b.as_float().expect("b is FLOAT"); + a.partial_cmp(&b).unwrap_or(Ordering::Equal) + }); + return Ok(()); + } + if type_id == TypeId::of::() { + array.sort_by(|a, b| { + let a = a + .read_lock::() + .expect("a is ImmutableString"); + let b = b + .read_lock::() + .expect("b is ImmutableString"); + a.as_str().cmp(b.as_str()) + }); + return Ok(()); + } + #[cfg(feature = "decimal")] + if type_id == TypeId::of::() { + array.sort_by(|a, b| { + let a = a.as_decimal().expect("a is Decimal"); + let b = b.as_decimal().expect("b is Decimal"); + a.cmp(&b) + }); + return Ok(()); + } + if type_id == TypeId::of::() { + array.sort_by(|a, b| { + let a = a.as_bool().expect("a is bool"); + let b = b.as_bool().expect("b is bool"); + a.cmp(&b) + }); + return Ok(()); + } + if type_id == TypeId::of::<()>() { + return Ok(()); + } + + Ok(()) + } #[rhai_fn(return_raw, pure)] pub fn drain( ctx: NativeCallContext,