use std::{ffi::CStr, mem};
use crate::{
binding::{fixnum, symbol},
rubysys::numeric::{
self, INTEGER_PACK_2COMP, INTEGER_PACK_LSWORD_FIRST, INTEGER_PACK_NATIVE_BYTE_ORDER,
},
types::{c_int, c_long, c_void, Value},
};
const PACK_FLAGS: c_int = INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER;
pub fn i128_to_integer(number: i128) -> Value {
unsafe {
numeric::rb_integer_unpack(
&number as *const i128 as *const c_void,
1,
mem::size_of::<i128>(),
0,
PACK_FLAGS | INTEGER_PACK_2COMP,
)
}
}
pub fn u128_to_integer(number: u128) -> Value {
unsafe {
numeric::rb_integer_unpack(
&number as *const u128 as *const c_void,
1,
mem::size_of::<u128>(),
0,
PACK_FLAGS,
)
}
}
pub fn integer_to_i128(integer: Value) -> Option<i128> {
let mut number: i128 = 0;
let sign = unsafe {
numeric::rb_integer_pack(
integer,
&mut number as *mut i128 as *mut c_void,
1,
mem::size_of::<i128>(),
0,
PACK_FLAGS | INTEGER_PACK_2COMP,
)
};
match sign {
0 => Some(0),
1 if number > 0 => Some(number),
-1 if number < 0 => Some(number),
_ => None,
}
}
pub fn integer_to_u128(integer: Value) -> Option<u128> {
let mut number: u128 = 0;
let sign = unsafe {
numeric::rb_integer_pack(
integer,
&mut number as *mut u128 as *mut c_void,
1,
mem::size_of::<u128>(),
0,
PACK_FLAGS,
)
};
match sign {
0 | 1 => Some(number),
_ => None,
}
}
pub fn cstr_to_integer(string: &CStr, base: u32) -> Value {
unsafe { numeric::rb_cstr_to_inum(string.as_ptr(), base as c_int, 1) }
}
pub fn integer_to_s(integer: Value, base: u32) -> Value {
unsafe { numeric::rb_big2str(integer, base as c_int) }
}
pub fn f64_to_integer(number: f64) -> Value {
unsafe { numeric::rb_dbl2big(number) }
}
pub fn float_rationalize(float: Value) -> Value {
unsafe { numeric::rb_flt_rationalize(float) }
}
pub fn rational_new(numerator: Value, denominator: Value) -> Value {
unsafe { numeric::rb_rational_new(numerator, denominator) }
}
pub fn rational_numerator(rational: Value) -> Value {
unsafe { numeric::rb_rational_num(rational) }
}
pub fn rational_denominator(rational: Value) -> Value {
unsafe { numeric::rb_rational_den(rational) }
}
pub fn to_rational(object: Value) -> Value {
unsafe { numeric::rb_Rational(object, fixnum::i64_to_num(1)) }
}
pub fn complex_new(real: Value, imaginary: Value) -> Value {
unsafe { numeric::rb_complex_new(real, imaginary) }
}
pub fn complex_polar(abs: Value, arg: Value) -> Value {
unsafe { numeric::rb_complex_new_polar(abs, arg) }
}
pub fn to_complex(object: Value) -> Value {
unsafe { numeric::rb_Complex(object, fixnum::i64_to_num(0)) }
}
pub fn complex_real(complex: Value) -> Value {
unsafe { numeric::rb_complex_real(complex) }
}
pub fn complex_imaginary(complex: Value) -> Value {
unsafe { numeric::rb_complex_imag(complex) }
}
pub fn complex_abs(complex: Value) -> Value {
unsafe { numeric::rb_complex_abs(complex) }
}
pub fn complex_arg(complex: Value) -> Value {
unsafe { numeric::rb_complex_arg(complex) }
}
pub fn coerce_bin(x: Value, y: Value, operator: &str) -> Value {
unsafe { numeric::rb_num_coerce_bin(x, y, symbol::internal_id(operator)) }
}
pub fn coerce_cmp(x: Value, y: Value, operator: &str) -> Value {
unsafe { numeric::rb_num_coerce_cmp(x, y, symbol::internal_id(operator)) }
}
pub fn coerce_relop(x: Value, y: Value, operator: &str) -> Value {
unsafe { numeric::rb_num_coerce_relop(x, y, symbol::internal_id(operator)) }
}
pub fn complex_from_parts(real: Value, imaginary: Value) -> Value {
unsafe { numeric::rb_Complex(real, imaginary) }
}
pub fn int_positive_pow(x: c_long, y: libc::c_ulong) -> Value {
unsafe { numeric::rb_int_positive_pow(x, y) }
}