1use super::Registry;
2use super::FunctionMeta;
3
4pub mod bitand;
5pub mod bitor;
6pub mod bitxor;
7pub mod bitlshift;
8pub mod bitrshift;
9pub mod delta;
10pub mod gestep;
11pub mod complex;
12
13pub mod bin2dec;
14pub mod bin2hex;
15pub mod bin2oct;
16pub mod dec2bin;
17pub mod dec2hex;
18pub mod dec2oct;
19pub mod hex2bin;
20pub mod hex2dec;
21pub mod hex2oct;
22pub mod oct2bin;
23pub mod oct2dec;
24pub mod oct2hex;
25
26pub(crate) fn parse_bin(s: &str) -> Option<i64> {
30 if s.is_empty() {
31 return Some(0);
32 }
33 if s.len() > 10 {
34 return None;
35 }
36 for c in s.chars() {
37 if c != '0' && c != '1' {
38 return None;
39 }
40 }
41 let bits = u64::from_str_radix(s, 2).ok()?;
42 if bits & 0b10_0000_0000 != 0 {
44 Some(bits as i64 - 1024)
46 } else {
47 Some(bits as i64)
48 }
49}
50
51pub(crate) fn parse_oct(s: &str) -> Option<i64> {
55 if s.is_empty() {
56 return Some(0);
57 }
58 if s.len() > 10 {
59 return None;
60 }
61 for c in s.chars() {
62 if !('0'..='7').contains(&c) {
63 return None;
64 }
65 }
66 let bits = u64::from_str_radix(s, 8).ok()?;
67 if bits & 0x2000_0000 != 0 {
69 Some(bits as i64 - 0x4000_0000) } else {
71 Some(bits as i64)
72 }
73}
74
75pub(crate) fn parse_hex(s: &str) -> Option<i64> {
79 if s.is_empty() {
80 return Some(0);
81 }
82 if s.len() > 10 {
83 return None;
84 }
85 for c in s.chars() {
86 if !c.is_ascii_hexdigit() {
87 return None;
88 }
89 }
90 let bits = u64::from_str_radix(s, 16).ok()?;
91 if bits & 0x80_0000_0000 != 0 {
93 Some(bits as i64 - 0x100_0000_0000i64) } else {
95 Some(bits as i64)
96 }
97}
98
99pub(crate) fn format_bin(n: i64, places: Option<usize>) -> Result<String, ()> {
102 let bits: u64 = if n < 0 {
103 (n + 1024) as u64
105 } else {
106 n as u64
107 };
108 let s = format!("{:b}", bits);
109 apply_places(s, places, 10)
110}
111
112pub(crate) fn format_oct(n: i64, places: Option<usize>) -> Result<String, ()> {
115 let bits: u64 = if n < 0 {
116 (n + 0x4000_0000) as u64
118 } else {
119 n as u64
120 };
121 let s = format!("{:o}", bits);
122 apply_places(s, places, 10)
123}
124
125pub(crate) fn format_hex(n: i64, places: Option<usize>) -> Result<String, ()> {
128 let bits: u64 = if n < 0 {
129 (n + 0x100_0000_0000i64) as u64
131 } else {
132 n as u64
133 };
134 let s = format!("{:X}", bits);
135 apply_places(s, places, 10)
136}
137
138fn apply_places(s: String, places: Option<usize>, max_len: usize) -> Result<String, ()> {
139 match places {
140 None => Ok(s),
141 Some(p) => {
142 if p == 0 || s.len() > p || p > max_len {
143 Err(())
144 } else {
145 Ok(format!("{:0>width$}", s, width = p))
146 }
147 }
148 }
149}
150
151pub(crate) fn get_places(args: &[crate::types::Value]) -> Result<Option<usize>, crate::types::Value> {
154 use crate::eval::coercion::to_number;
155 use crate::types::{ErrorKind, Value};
156 if args.len() < 2 {
157 return Ok(None);
158 }
159 let n = to_number(args[1].clone())?;
160 let p = n.trunc() as i64;
161 if p <= 0 {
162 return Err(Value::Error(ErrorKind::Num));
163 }
164 Ok(Some(p as usize))
165}
166
167pub fn register_engineering(registry: &mut Registry) {
168 registry.register_eager("BITAND", bitand::bitand_fn, FunctionMeta { category: "engineering", signature: "BITAND(number1, number2)", description: "Bitwise AND of two integers" });
169 registry.register_eager("BITOR", bitor::bitor_fn, FunctionMeta { category: "engineering", signature: "BITOR(number1, number2)", description: "Bitwise OR of two integers" });
170 registry.register_eager("BITXOR", bitxor::bitxor_fn, FunctionMeta { category: "engineering", signature: "BITXOR(number1, number2)", description: "Bitwise XOR of two integers" });
171 registry.register_eager("BITLSHIFT", bitlshift::bitlshift_fn, FunctionMeta { category: "engineering", signature: "BITLSHIFT(number, shift_amount)", description: "Left-shift an integer by a number of bits" });
172 registry.register_eager("BITRSHIFT", bitrshift::bitrshift_fn, FunctionMeta { category: "engineering", signature: "BITRSHIFT(number, shift_amount)", description: "Right-shift an integer by a number of bits" });
173 registry.register_eager("DELTA", delta::delta_fn, FunctionMeta { category: "engineering", signature: "DELTA(number1, [number2])", description: "Test whether two values are equal" });
174 registry.register_eager("GESTEP", gestep::gestep_fn, FunctionMeta { category: "engineering", signature: "GESTEP(number, [step])", description: "Test whether a number is greater than or equal to a step value" });
175 registry.register_eager("BIN2DEC", bin2dec::bin2dec_fn, FunctionMeta { category: "engineering", signature: "BIN2DEC(number)", description: "Convert binary to decimal" });
176 registry.register_eager("BIN2HEX", bin2hex::bin2hex_fn, FunctionMeta { category: "engineering", signature: "BIN2HEX(number, [places])", description: "Convert binary to hexadecimal" });
177 registry.register_eager("BIN2OCT", bin2oct::bin2oct_fn, FunctionMeta { category: "engineering", signature: "BIN2OCT(number, [places])", description: "Convert binary to octal" });
178 registry.register_eager("DEC2BIN", dec2bin::dec2bin_fn, FunctionMeta { category: "engineering", signature: "DEC2BIN(number, [places])", description: "Convert decimal to binary" });
179 registry.register_eager("DEC2HEX", dec2hex::dec2hex_fn, FunctionMeta { category: "engineering", signature: "DEC2HEX(number, [places])", description: "Convert decimal to hexadecimal" });
180 registry.register_eager("DEC2OCT", dec2oct::dec2oct_fn, FunctionMeta { category: "engineering", signature: "DEC2OCT(number, [places])", description: "Convert decimal to octal" });
181 registry.register_eager("HEX2BIN", hex2bin::hex2bin_fn, FunctionMeta { category: "engineering", signature: "HEX2BIN(number, [places])", description: "Convert hexadecimal to binary" });
182 registry.register_eager("HEX2DEC", hex2dec::hex2dec_fn, FunctionMeta { category: "engineering", signature: "HEX2DEC(number)", description: "Convert hexadecimal to decimal" });
183 registry.register_eager("HEX2OCT", hex2oct::hex2oct_fn, FunctionMeta { category: "engineering", signature: "HEX2OCT(number, [places])", description: "Convert hexadecimal to octal" });
184 registry.register_eager("OCT2BIN", oct2bin::oct2bin_fn, FunctionMeta { category: "engineering", signature: "OCT2BIN(number, [places])", description: "Convert octal to binary" });
185 registry.register_eager("OCT2DEC", oct2dec::oct2dec_fn, FunctionMeta { category: "engineering", signature: "OCT2DEC(number)", description: "Convert octal to decimal" });
186 registry.register_eager("OCT2HEX", oct2hex::oct2hex_fn, FunctionMeta { category: "engineering", signature: "OCT2HEX(number, [places])", description: "Convert octal to hexadecimal" });
187
188 registry.register_eager("COMPLEX", complex::complex_fn, FunctionMeta { category: "engineering", signature: "COMPLEX(real, imaginary, [suffix])", description: "Create a complex number string" });
190 registry.register_eager("IMREAL", complex::imreal_fn, FunctionMeta { category: "engineering", signature: "IMREAL(complex)", description: "Real part of a complex number" });
191 registry.register_eager("IMAGINARY", complex::imaginary_fn, FunctionMeta { category: "engineering", signature: "IMAGINARY(complex)", description: "Imaginary part of a complex number" });
192 registry.register_eager("IMABS", complex::imabs_fn, FunctionMeta { category: "engineering", signature: "IMABS(complex)", description: "Absolute value of a complex number" });
193 registry.register_eager("IMPRODUCT", complex::improduct_fn, FunctionMeta { category: "engineering", signature: "IMPRODUCT(complex1, ...)", description: "Product of complex numbers" });
194 registry.register_eager("IMSUB", complex::imsub_fn, FunctionMeta { category: "engineering", signature: "IMSUB(complex1, complex2)", description: "Subtract complex numbers" });
195 registry.register_eager("IMSUM", complex::imsum_fn, FunctionMeta { category: "engineering", signature: "IMSUM(complex1, ...)", description: "Sum of complex numbers" });
196 registry.register_eager("IMDIV", complex::imdiv_fn, FunctionMeta { category: "engineering", signature: "IMDIV(complex1, complex2)", description: "Divide complex numbers" });
197 registry.register_eager("IMCONJUGATE", complex::imconjugate_fn, FunctionMeta { category: "engineering", signature: "IMCONJUGATE(complex)", description: "Complex conjugate" });
198 registry.register_eager("IMARGUMENT", complex::imargument_fn, FunctionMeta { category: "engineering", signature: "IMARGUMENT(complex)", description: "Argument (angle) of a complex number" });
199 registry.register_eager("IMLN", complex::imln_fn, FunctionMeta { category: "engineering", signature: "IMLN(complex)", description: "Natural log of a complex number" });
200 registry.register_eager("IMLOG10", complex::imlog10_fn, FunctionMeta { category: "engineering", signature: "IMLOG10(complex)", description: "Base-10 log of a complex number" });
201 registry.register_eager("IMLOG2", complex::imlog2_fn, FunctionMeta { category: "engineering", signature: "IMLOG2(complex)", description: "Base-2 log of a complex number" });
202 registry.register_eager("IMLOG", complex::imlog_fn, FunctionMeta { category: "engineering", signature: "IMLOG(complex, base)", description: "Logarithm of a complex number to a given base" });
203 registry.register_eager("IMEXP", complex::imexp_fn, FunctionMeta { category: "engineering", signature: "IMEXP(complex)", description: "e raised to a complex power" });
204 registry.register_eager("IMPOWER", complex::impower_fn, FunctionMeta { category: "engineering", signature: "IMPOWER(complex, number)", description: "Complex number raised to a power" });
205 registry.register_eager("IMSQRT", complex::imsqrt_fn, FunctionMeta { category: "engineering", signature: "IMSQRT(complex)", description: "Square root of a complex number" });
206 registry.register_eager("IMSIN", complex::imsin_fn, FunctionMeta { category: "engineering", signature: "IMSIN(complex)", description: "Sine of a complex number" });
207 registry.register_eager("IMCOS", complex::imcos_fn, FunctionMeta { category: "engineering", signature: "IMCOS(complex)", description: "Cosine of a complex number" });
208 registry.register_eager("IMTAN", complex::imtan_fn, FunctionMeta { category: "engineering", signature: "IMTAN(complex)", description: "Tangent of a complex number" });
209 registry.register_eager("IMCOT", complex::imcot_fn, FunctionMeta { category: "engineering", signature: "IMCOT(complex)", description: "Cotangent of a complex number" });
210 registry.register_eager("IMCSC", complex::imcsc_fn, FunctionMeta { category: "engineering", signature: "IMCSC(complex)", description: "Cosecant of a complex number" });
211 registry.register_eager("IMSEC", complex::imsec_fn, FunctionMeta { category: "engineering", signature: "IMSEC(complex)", description: "Secant of a complex number" });
212 registry.register_eager("IMSINH", complex::imsinh_fn, FunctionMeta { category: "engineering", signature: "IMSINH(complex)", description: "Hyperbolic sine of a complex number" });
213 registry.register_eager("IMCOSH", complex::imcosh_fn, FunctionMeta { category: "engineering", signature: "IMCOSH(complex)", description: "Hyperbolic cosine of a complex number" });
214 registry.register_eager("IMTANH", complex::imtanh_fn, FunctionMeta { category: "engineering", signature: "IMTANH(complex)", description: "Hyperbolic tangent of a complex number" });
215 registry.register_eager("IMCOTH", complex::imcoth_fn, FunctionMeta { category: "engineering", signature: "IMCOTH(complex)", description: "Hyperbolic cotangent of a complex number" });
216 registry.register_eager("IMCSCH", complex::imcsch_fn, FunctionMeta { category: "engineering", signature: "IMCSCH(complex)", description: "Hyperbolic cosecant of a complex number" });
217 registry.register_eager("IMSECH", complex::imsech_fn, FunctionMeta { category: "engineering", signature: "IMSECH(complex)", description: "Hyperbolic secant of a complex number" });
218
219 registry.register_eager("ERF", erf::erf_fn, FunctionMeta { category: "engineering", signature: "ERF(lower_limit, [upper_limit])", description: "Error function" });
221 registry.register_eager("ERF.PRECISE", erf::erf_precise_fn, FunctionMeta { category: "engineering", signature: "ERF.PRECISE(x)", description: "Error function (precise)" });
222 registry.register_eager("ERFC", erf::erfc_fn, FunctionMeta { category: "engineering", signature: "ERFC(x)", description: "Complementary error function" });
223 registry.register_eager("ERFC.PRECISE", erf::erfc_precise_fn, FunctionMeta { category: "engineering", signature: "ERFC.PRECISE(x)", description: "Complementary error function (precise)" });
224}
225
226pub mod erf;