aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-php-shim
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe-php-shim')
-rw-r--r--crates/shirabe-php-shim/src/var.rs21
1 files changed, 21 insertions, 0 deletions
diff --git a/crates/shirabe-php-shim/src/var.rs b/crates/shirabe-php-shim/src/var.rs
index 513c3e88..dd0592f8 100644
--- a/crates/shirabe-php-shim/src/var.rs
+++ b/crates/shirabe-php-shim/src/var.rs
@@ -185,6 +185,27 @@ pub fn is_numeric_to_int(value: &PhpMixed) -> i64 {
}
}
+/// Approximates PHP's `<=>` for two strings: if both are numeric strings, compare numerically
+/// (as PHP does), otherwise fall back to a byte-wise comparison.
+///
+/// TODO: this only covers the string/string case of PHP's loose comparison. PHP's `<=>` has many
+/// more special-cased rules across other operand type combinations (bool, array, null, object,
+/// numeric-string-vs-non-numeric-string, ...). Extend this if a new caller needs those.
+pub fn loosely_compare(a: &str, b: &str) -> std::cmp::Ordering {
+ if is_numeric_string(a) && is_numeric_string(b) {
+ match (a.trim().parse::<i64>(), b.trim().parse::<i64>()) {
+ (Ok(na), Ok(nb)) => na.cmp(&nb),
+ _ => {
+ let na: f64 = a.trim().parse().unwrap_or(0.0);
+ let nb: f64 = b.trim().parse().unwrap_or(0.0);
+ na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal)
+ }
+ }
+ } else {
+ a.cmp(b)
+ }
+}
+
pub fn instance_of<T>(_value: &PhpMixed) -> bool {
// TODO(phase-d): PHP `instanceof` needs the runtime class of the value, which PhpMixed::Object
// does not carry.