use std::panic::catch_unwind;
use std::ptr;
use super::types::{SciComplexVector, SciMatrix, SciResult, SciVector};
#[no_mangle]
pub unsafe extern "C" fn sci_vector_new(len: usize, out: *mut SciVector) -> SciResult {
if out.is_null() {
return SciResult::err("sci_vector_new: out pointer is null");
}
let result = catch_unwind(|| {
let v = vec![0.0f64; len];
SciVector::from_vec(v)
});
match result {
Ok(sv) => {
unsafe { ptr::write(out, sv) };
SciResult::ok()
}
Err(e) => SciResult::from_panic(e),
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_vector_from_data(
src: *const f64,
len: usize,
out: *mut SciVector,
) -> SciResult {
if out.is_null() {
return SciResult::err("sci_vector_from_data: out pointer is null");
}
if src.is_null() && len > 0 {
return SciResult::err("sci_vector_from_data: src is null but len > 0");
}
let result = catch_unwind(std::panic::AssertUnwindSafe(|| {
let slice = if len == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(src, len) }
};
SciVector::from_vec(slice.to_vec())
}));
match result {
Ok(sv) => {
unsafe { ptr::write(out, sv) };
SciResult::ok()
}
Err(e) => SciResult::from_panic(e),
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_vector_free(vec: *mut SciVector) {
if vec.is_null() {
return;
}
let sv = unsafe { ptr::read(vec) };
if !sv.data.is_null() && sv.len > 0 {
let _ = unsafe { Vec::from_raw_parts(sv.data, sv.len, sv.len) };
}
unsafe {
(*vec).data = ptr::null_mut();
(*vec).len = 0;
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_matrix_new(
rows: usize,
cols: usize,
out: *mut SciMatrix,
) -> SciResult {
if out.is_null() {
return SciResult::err("sci_matrix_new: out pointer is null");
}
let result = catch_unwind(|| {
let total = rows
.checked_mul(cols)
.ok_or_else(|| format!("sci_matrix_new: rows*cols overflow ({} x {})", rows, cols))?;
let v = vec![0.0f64; total];
SciMatrix::from_vec(v, rows, cols)
.ok_or_else(|| "sci_matrix_new: internal dimension mismatch".to_string())
});
match result {
Ok(Ok(sm)) => {
unsafe { ptr::write(out, sm) };
SciResult::ok()
}
Ok(Err(msg)) => SciResult::err(&msg),
Err(e) => SciResult::from_panic(e),
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_matrix_from_data(
src: *const f64,
rows: usize,
cols: usize,
out: *mut SciMatrix,
) -> SciResult {
if out.is_null() {
return SciResult::err("sci_matrix_from_data: out pointer is null");
}
let total = match rows.checked_mul(cols) {
Some(n) => n,
None => {
return SciResult::err("sci_matrix_from_data: rows*cols overflow");
}
};
if src.is_null() && total > 0 {
return SciResult::err("sci_matrix_from_data: src is null but size > 0");
}
let result = catch_unwind(std::panic::AssertUnwindSafe(|| {
let slice = if total == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(src, total) }
};
SciMatrix::from_vec(slice.to_vec(), rows, cols)
.ok_or_else(|| "sci_matrix_from_data: internal dimension mismatch".to_string())
}));
match result {
Ok(Ok(sm)) => {
unsafe { ptr::write(out, sm) };
SciResult::ok()
}
Ok(Err(msg)) => SciResult::err(&msg),
Err(e) => SciResult::from_panic(e),
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_matrix_free(mat: *mut SciMatrix) {
if mat.is_null() {
return;
}
let sm = unsafe { ptr::read(mat) };
let total = sm.rows.saturating_mul(sm.cols);
if !sm.data.is_null() && total > 0 {
let _ = unsafe { Vec::from_raw_parts(sm.data, total, total) };
}
unsafe {
(*mat).data = ptr::null_mut();
(*mat).rows = 0;
(*mat).cols = 0;
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_complex_vector_free(cv: *mut SciComplexVector) {
if cv.is_null() {
return;
}
let c = unsafe { ptr::read(cv) };
if !c.real.is_null() && c.len > 0 {
let _ = unsafe { Vec::from_raw_parts(c.real, c.len, c.len) };
}
if !c.imag.is_null() && c.len > 0 {
let _ = unsafe { Vec::from_raw_parts(c.imag, c.len, c.len) };
}
unsafe {
(*cv).real = ptr::null_mut();
(*cv).imag = ptr::null_mut();
(*cv).len = 0;
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_svd_result_free(svd: *mut super::types::SciSvdResult) {
if svd.is_null() {
return;
}
unsafe {
sci_matrix_free(&mut (*svd).u);
sci_vector_free(&mut (*svd).s);
sci_matrix_free(&mut (*svd).vt);
}
}
#[no_mangle]
pub unsafe extern "C" fn sci_eig_result_free(eig: *mut super::types::SciEigResult) {
if eig.is_null() {
return;
}
unsafe {
sci_complex_vector_free(&mut (*eig).eigenvalues);
sci_matrix_free(&mut (*eig).eigenvectors);
}
}