#![allow(unsafe_code)]
#![allow(unreachable_pub)]
use core::ffi::{c_char, c_int};
use core::ptr;
use core::str::FromStr;
use std::panic::{AssertUnwindSafe, catch_unwind};
use alloc::boxed::Box;
use alloc::string::ToString;
use std::ffi::{CStr, CString};
use crate::int::{Int, Sign};
pub struct PurempInt(Int);
#[inline]
fn to_handle(i: Int) -> *mut PurempInt {
Box::into_raw(Box::new(PurempInt(i)))
}
#[unsafe(no_mangle)]
pub extern "C" fn puremp_version() -> *const c_char {
concat!(env!("CARGO_PKG_VERSION"), "\0").as_ptr() as *const c_char
}
#[unsafe(no_mangle)]
pub extern "C" fn puremp_int_from_i64(v: i64) -> *mut PurempInt {
to_handle(Int::from_i64(v))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_from_str(s: *const c_char) -> *mut PurempInt {
if s.is_null() {
return ptr::null_mut();
}
let r = catch_unwind(AssertUnwindSafe(|| {
let cs = unsafe { CStr::from_ptr(s) };
let text = cs.to_str().ok()?;
Int::from_str(text).ok()
}));
match r {
Ok(Some(i)) => to_handle(i),
_ => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_free(h: *mut PurempInt) {
if !h.is_null() {
drop(unsafe { Box::from_raw(h) });
}
}
unsafe fn binop<F>(a: *const PurempInt, b: *const PurempInt, f: F) -> *mut PurempInt
where
F: Fn(&Int, &Int) -> Int,
{
if a.is_null() || b.is_null() {
return ptr::null_mut();
}
let r = catch_unwind(AssertUnwindSafe(|| {
let x = unsafe { &(*a).0 };
let y = unsafe { &(*b).0 };
to_handle(f(x, y))
}));
r.unwrap_or(ptr::null_mut())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_add(
a: *const PurempInt,
b: *const PurempInt,
) -> *mut PurempInt {
unsafe { binop(a, b, |x, y| x.add(y)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_sub(
a: *const PurempInt,
b: *const PurempInt,
) -> *mut PurempInt {
unsafe { binop(a, b, |x, y| x.sub(y)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_mul(
a: *const PurempInt,
b: *const PurempInt,
) -> *mut PurempInt {
unsafe { binop(a, b, |x, y| x.mul(y)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_pow(base: *const PurempInt, exp: u64) -> *mut PurempInt {
if base.is_null() {
return ptr::null_mut();
}
let r = catch_unwind(AssertUnwindSafe(|| {
let x = unsafe { &(*base).0 };
to_handle(x.pow(exp))
}));
r.unwrap_or(ptr::null_mut())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_neg(a: *const PurempInt) -> *mut PurempInt {
if a.is_null() {
return ptr::null_mut();
}
let r = catch_unwind(AssertUnwindSafe(|| {
let x = unsafe { &(*a).0 };
to_handle(x.neg())
}));
r.unwrap_or(ptr::null_mut())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_cmp(a: *const PurempInt, b: *const PurempInt) -> c_int {
if a.is_null() || b.is_null() {
return -2;
}
let r = catch_unwind(AssertUnwindSafe(|| {
let x = unsafe { &(*a).0 };
let y = unsafe { &(*b).0 };
match x.cmp(y) {
core::cmp::Ordering::Less => -1,
core::cmp::Ordering::Equal => 0,
core::cmp::Ordering::Greater => 1,
}
}));
r.unwrap_or(-2)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_sign(a: *const PurempInt) -> c_int {
if a.is_null() {
return -2;
}
let r = catch_unwind(AssertUnwindSafe(|| match unsafe { &(*a).0 }.sign() {
Sign::Negative => -1,
Sign::Zero => 0,
Sign::Positive => 1,
}));
r.unwrap_or(-2)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_int_to_string(a: *const PurempInt) -> *mut c_char {
if a.is_null() {
return ptr::null_mut();
}
let r = catch_unwind(AssertUnwindSafe(|| {
let x = unsafe { &(*a).0 };
CString::new(x.to_string()).ok()
}));
match r {
Ok(Some(c)) => c.into_raw(),
_ => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn puremp_string_free(s: *mut c_char) {
if !s.is_null() {
drop(unsafe { CString::from_raw(s) });
}
}