mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 17:05:36 +01:00
Merge 'Fix math functions compatibility issues' from Levy A.
Adds `round`, `hex`, `unhex`, `abs`, `lower`, `upper`, `sign` and `log` (with base) to the expression fuzzer. Rounding with the precision argument still has some incompatibilities. Closes #3160
This commit is contained in:
11
core/util.rs
11
core/util.rs
@@ -103,17 +103,6 @@ impl<I: ?Sized + IO> IOExt for I {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RoundToPrecision {
|
||||
fn round_to_precision(self, precision: i32) -> f64;
|
||||
}
|
||||
|
||||
impl RoundToPrecision for f64 {
|
||||
fn round_to_precision(self, precision: i32) -> f64 {
|
||||
let factor = 10f64.powi(precision);
|
||||
(self * factor).round() / factor
|
||||
}
|
||||
}
|
||||
|
||||
// https://sqlite.org/lang_keywords.html
|
||||
const QUOTE_PAIRS: &[(char, char)] = &[
|
||||
('"', '"'),
|
||||
|
||||
@@ -56,7 +56,7 @@ use crate::{
|
||||
},
|
||||
util::{
|
||||
cast_real_to_integer, cast_text_to_integer, cast_text_to_numeric, cast_text_to_real,
|
||||
checked_cast_text_to_numeric, parse_schema_rows, RoundToPrecision,
|
||||
checked_cast_text_to_numeric, parse_schema_rows,
|
||||
},
|
||||
vdbe::{
|
||||
builder::CursorType,
|
||||
@@ -4599,7 +4599,11 @@ pub fn op_function(
|
||||
}
|
||||
ScalarFunc::Unhex => {
|
||||
let reg_value = &state.registers[*start_reg];
|
||||
let ignored_chars = state.registers.get(*start_reg + 1);
|
||||
let ignored_chars = if func.arg_count == 2 {
|
||||
state.registers.get(*start_reg + 1)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let result = reg_value
|
||||
.get_value()
|
||||
.exec_unhex(ignored_chars.map(|x| x.get_value()));
|
||||
@@ -7908,10 +7912,8 @@ mod cmath {
|
||||
|
||||
impl Value {
|
||||
pub fn exec_lower(&self) -> Option<Self> {
|
||||
match self {
|
||||
Value::Text(t) => Some(Value::build_text(t.as_str().to_lowercase())),
|
||||
t => Some(t.to_owned()),
|
||||
}
|
||||
self.cast_text()
|
||||
.map(|s| Value::build_text(s.to_ascii_lowercase()))
|
||||
}
|
||||
|
||||
pub fn exec_length(&self) -> Self {
|
||||
@@ -7940,49 +7942,20 @@ impl Value {
|
||||
}
|
||||
|
||||
pub fn exec_upper(&self) -> Option<Self> {
|
||||
match self {
|
||||
Value::Text(t) => Some(Value::build_text(t.as_str().to_uppercase())),
|
||||
t => Some(t.to_owned()),
|
||||
}
|
||||
self.cast_text()
|
||||
.map(|s| Value::build_text(s.to_ascii_uppercase()))
|
||||
}
|
||||
|
||||
pub fn exec_sign(&self) -> Option<Value> {
|
||||
let num = match self {
|
||||
Value::Integer(i) => *i as f64,
|
||||
Value::Float(f) => *f,
|
||||
Value::Text(s) => {
|
||||
if let Ok(i) = s.as_str().parse::<i64>() {
|
||||
i as f64
|
||||
} else if let Ok(f) = s.as_str().parse::<f64>() {
|
||||
f
|
||||
} else {
|
||||
return Some(Value::Null);
|
||||
}
|
||||
}
|
||||
Value::Blob(b) => match std::str::from_utf8(b) {
|
||||
Ok(s) => {
|
||||
if let Ok(i) = s.parse::<i64>() {
|
||||
i as f64
|
||||
} else if let Ok(f) = s.parse::<f64>() {
|
||||
f
|
||||
} else {
|
||||
return Some(Value::Null);
|
||||
}
|
||||
}
|
||||
Err(_) => return Some(Value::Null),
|
||||
},
|
||||
_ => return Some(Value::Null),
|
||||
};
|
||||
let v = Numeric::from_value_strict(self).try_into_f64()?;
|
||||
|
||||
let sign = if num > 0.0 {
|
||||
Some(Value::Integer(if v > 0.0 {
|
||||
1
|
||||
} else if num < 0.0 {
|
||||
} else if v < 0.0 {
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Some(Value::Integer(sign))
|
||||
}))
|
||||
}
|
||||
|
||||
/// Generates the Soundex code for a given word
|
||||
@@ -8077,25 +8050,24 @@ impl Value {
|
||||
}
|
||||
|
||||
pub fn exec_abs(&self) -> Result<Self> {
|
||||
match self {
|
||||
Value::Integer(x) => {
|
||||
match i64::checked_abs(*x) {
|
||||
Some(y) => Ok(Value::Integer(y)),
|
||||
// Special case: if we do the abs of "-9223372036854775808", it causes overflow.
|
||||
// return IntegerOverflow error
|
||||
None => Err(LimboError::IntegerOverflow),
|
||||
}
|
||||
Ok(match self {
|
||||
Value::Null => Value::Null,
|
||||
Value::Integer(v) => {
|
||||
Value::Integer(v.checked_abs().ok_or(LimboError::IntegerOverflow)?)
|
||||
}
|
||||
Value::Float(x) => {
|
||||
if x < &0.0 {
|
||||
Ok(Value::Float(-x))
|
||||
} else {
|
||||
Ok(Value::Float(*x))
|
||||
}
|
||||
Value::Float(non_nan) => Value::Float(non_nan.abs()),
|
||||
_ => {
|
||||
let s = match self {
|
||||
Value::Text(text) => text.to_string(),
|
||||
Value::Blob(blob) => String::from_utf8_lossy(blob).to_string(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
crate::numeric::str_to_f64(s)
|
||||
.map(|v| Value::Float(f64::from(v).abs()))
|
||||
.unwrap_or(Value::Float(0.0))
|
||||
}
|
||||
Value::Null => Ok(Value::Null),
|
||||
_ => Ok(Value::Float(0.0)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn exec_random() -> Self {
|
||||
@@ -8238,7 +8210,7 @@ impl Value {
|
||||
Value::build_text(hex::encode_upper(text))
|
||||
}
|
||||
Value::Blob(blob_bytes) => Value::build_text(hex::encode_upper(blob_bytes)),
|
||||
_ => Value::Null,
|
||||
Value::Null => Value::build_text(""),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8246,9 +8218,12 @@ impl Value {
|
||||
match self {
|
||||
Value::Null => Value::Null,
|
||||
_ => match ignored_chars {
|
||||
None => match hex::decode(self.to_string()) {
|
||||
Ok(bytes) => Value::Blob(bytes),
|
||||
Err(_) => Value::Null,
|
||||
None => match self
|
||||
.cast_text()
|
||||
.map(|s| hex::decode(&s[0..s.find('\0').unwrap_or(s.len())]))
|
||||
{
|
||||
Some(Ok(bytes)) => Value::Blob(bytes),
|
||||
_ => Value::Null,
|
||||
},
|
||||
Some(ignore) => match ignore {
|
||||
Value::Text(_) => {
|
||||
@@ -8260,7 +8235,7 @@ impl Value {
|
||||
.to_string();
|
||||
match hex::decode(trimmed) {
|
||||
Ok(bytes) => Value::Blob(bytes),
|
||||
Err(_) => Value::Null,
|
||||
_ => Value::Null,
|
||||
}
|
||||
}
|
||||
_ => Value::Null,
|
||||
@@ -8283,36 +8258,33 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn _to_float(&self) -> f64 {
|
||||
match self {
|
||||
Value::Text(x) => match cast_text_to_numeric(x.as_str()) {
|
||||
Value::Integer(i) => i as f64,
|
||||
Value::Float(f) => f,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Value::Integer(x) => *x as f64,
|
||||
Value::Float(x) => *x,
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exec_round(&self, precision: Option<&Value>) -> Value {
|
||||
let reg = self._to_float();
|
||||
let round = |reg: f64, f: f64| {
|
||||
let precision = if f < 1.0 { 0.0 } else { f };
|
||||
Value::Float(reg.round_to_precision(precision as i32))
|
||||
let Some(f) = Numeric::from(self).try_into_f64() else {
|
||||
return Value::Null;
|
||||
};
|
||||
match precision {
|
||||
Some(Value::Text(x)) => match cast_text_to_numeric(x.as_str()) {
|
||||
Value::Integer(i) => round(reg, i as f64),
|
||||
Value::Float(f) => round(reg, f),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Some(Value::Integer(i)) => round(reg, *i as f64),
|
||||
Some(Value::Float(f)) => round(reg, *f),
|
||||
None => round(reg, 0.0),
|
||||
_ => Value::Null,
|
||||
|
||||
let precision = match precision.map(|v| Numeric::from(v).try_into_f64()) {
|
||||
None => 0.0,
|
||||
Some(Some(v)) => v,
|
||||
Some(None) => return Value::Null,
|
||||
};
|
||||
|
||||
if !(-4503599627370496.0..=4503599627370496.0).contains(&f) {
|
||||
return Value::Float(f);
|
||||
}
|
||||
|
||||
let precision = if precision < 1.0 { 0.0 } else { precision };
|
||||
let precision = precision.clamp(0.0, 30.0) as usize;
|
||||
|
||||
if precision == 0 {
|
||||
return Value::Float(((f + if f < 0.0 { -0.5 } else { 0.5 }) as i64) as f64);
|
||||
}
|
||||
|
||||
let f: f64 = crate::numeric::str_to_f64(format!("{f:.precision$}"))
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
Value::Float(f)
|
||||
}
|
||||
|
||||
// Implements TRIM pattern matching.
|
||||
@@ -8576,6 +8548,11 @@ impl Value {
|
||||
|
||||
let log_x = libm::log(f);
|
||||
let log_base = libm::log(base);
|
||||
|
||||
if log_base <= 0.0 {
|
||||
return Value::Null;
|
||||
}
|
||||
|
||||
let result = log_x / log_base;
|
||||
Value::Float(result)
|
||||
}
|
||||
@@ -10008,8 +9985,8 @@ mod tests {
|
||||
assert_eq!(input_str.exec_upper().unwrap(), expected_str);
|
||||
|
||||
let input_int = Value::Integer(10);
|
||||
assert_eq!(input_int.exec_upper().unwrap(), input_int);
|
||||
assert_eq!(Value::Null.exec_upper().unwrap(), Value::Null)
|
||||
assert_eq!(input_int.exec_upper().unwrap(), Value::build_text("10"));
|
||||
assert_eq!(Value::Null.exec_upper(), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -10019,8 +9996,8 @@ mod tests {
|
||||
assert_eq!(input_str.exec_lower().unwrap(), expected_str);
|
||||
|
||||
let input_int = Value::Integer(10);
|
||||
assert_eq!(input_int.exec_lower().unwrap(), input_int);
|
||||
assert_eq!(Value::Null.exec_lower().unwrap(), Value::Null)
|
||||
assert_eq!(input_int.exec_lower().unwrap(), Value::build_text("10"));
|
||||
assert_eq!(Value::Null.exec_lower(), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -10487,7 +10464,7 @@ mod tests {
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::build_text("abc");
|
||||
let expected = Some(Value::Null);
|
||||
let expected = None;
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::build_text("42");
|
||||
@@ -10503,23 +10480,23 @@ mod tests {
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::Blob(b"abc".to_vec());
|
||||
let expected = Some(Value::Null);
|
||||
let expected = None;
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::Blob(b"42".to_vec());
|
||||
let expected = Some(Value::Integer(1));
|
||||
let expected = None;
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::Blob(b"-42".to_vec());
|
||||
let expected = Some(Value::Integer(-1));
|
||||
let expected = None;
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::Blob(b"0".to_vec());
|
||||
let expected = Some(Value::Integer(0));
|
||||
let expected = None;
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
|
||||
let input = Value::Null;
|
||||
let expected = Some(Value::Null);
|
||||
let expected = None;
|
||||
assert_eq!(input.exec_sign(), expected);
|
||||
}
|
||||
|
||||
|
||||
109
fuzz/Cargo.lock
generated
109
fuzz/Cargo.lock
generated
@@ -56,12 +56,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@@ -88,9 +82,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
version = "2.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
@@ -153,11 +147,10 @@ checksum = "18758054972164c3264f7c8386f5fc6da6114cb46b619fd365d4e3b2dc3ae487"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.40"
|
||||
version = "0.4.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
@@ -231,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
@@ -266,12 +259,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
@@ -569,16 +556,6 @@ dependencies = [
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
@@ -893,8 +870,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -904,7 +891,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -916,6 +913,15 @@ dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.10"
|
||||
@@ -1121,18 +1127,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1182,7 +1188,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "turso_core"
|
||||
version = "0.2.0-pre.1"
|
||||
version = "0.2.0-pre.3"
|
||||
dependencies = [
|
||||
"aegis",
|
||||
"aes",
|
||||
@@ -1205,7 +1211,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"paste",
|
||||
"polling",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"rustix 1.0.7",
|
||||
@@ -1218,14 +1224,14 @@ dependencies = [
|
||||
"turso_ext",
|
||||
"turso_macros",
|
||||
"turso_parser",
|
||||
"turso_sqlite3_parser",
|
||||
"twox-hash",
|
||||
"uncased",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "turso_ext"
|
||||
version = "0.2.0-pre.1"
|
||||
version = "0.2.0-pre.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"getrandom 0.3.1",
|
||||
@@ -1234,7 +1240,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "turso_macros"
|
||||
version = "0.2.0-pre.1"
|
||||
version = "0.2.0-pre.3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1243,7 +1249,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "turso_parser"
|
||||
version = "0.2.0-pre.1"
|
||||
version = "0.2.0-pre.3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"miette",
|
||||
@@ -1254,19 +1260,12 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "turso_sqlite3_parser"
|
||||
version = "0.2.0-pre.1"
|
||||
name = "twox-hash"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"fallible-iterator",
|
||||
"indexmap",
|
||||
"log",
|
||||
"memchr",
|
||||
"miette",
|
||||
"smallvec",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1434,9 +1433,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
||||
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
||||
@@ -118,6 +118,14 @@ impl rusqlite::types::FromSql for Value {
|
||||
|
||||
str_enum! {
|
||||
enum UnaryFunc {
|
||||
Round => "round",
|
||||
Hex => "hex",
|
||||
Unhex => "unhex",
|
||||
Abs => "abs",
|
||||
Lower => "lower",
|
||||
Upper => "upper",
|
||||
Sign => "sign",
|
||||
|
||||
Ceil => "ceil",
|
||||
Floor => "floor",
|
||||
Trunc => "trunc",
|
||||
@@ -149,9 +157,11 @@ str_enum! {
|
||||
|
||||
str_enum! {
|
||||
enum BinaryFunc {
|
||||
Round => "round",
|
||||
Power => "pow",
|
||||
Mod => "mod",
|
||||
Atan2 => "atan2",
|
||||
Log => "log",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user