use crate::copp::InterpolationMode;
use crate::copp::copp2::stable::basic::{a_to_b_topp2, s_to_t_topp2, t_to_s_topp2};
use crate::copp::copp3::stable::basic::{s_to_t_topp3, t_to_s_topp3};
use crate::copp::copp3::stable::topp3_lp::force_positive_a;
use crate::diag::CoppError;
use crate::ffi::c::core::status::panic_to_status;
use crate::ffi::c::{CoppSliceF64, CoppSliceMutF64, CoppStatus, CoppVecF64};
use std::panic::{AssertUnwindSafe, catch_unwind};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_a_to_b_2nd(
s: CoppSliceF64,
a: CoppSliceF64,
out_b: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
let out_b = match CoppVecF64::out_ptr(out_b) {
Ok(out_b) => out_b,
Err(status) => return status,
};
unsafe {
CoppVecF64::write_empty_to(out_b);
}
match catch_unwind(AssertUnwindSafe(|| {
let s = unsafe { s.as_slice()? };
let a = unsafe { a.as_slice()? };
let b = a_to_b_topp2(s, a).map_err(interpolation_status)?;
unsafe {
CoppVecF64::write_vec_to(out_b, b);
}
Ok(CoppStatus::Ok)
})) {
Ok(Ok(status)) | Ok(Err(status)) => status.into_ffi_status(),
Err(payload) => panic_to_status(payload).into_ffi_status(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_s_to_t_2nd(
s: CoppSliceF64,
a: CoppSliceF64,
t0: f64,
out_t_final: *mut f64,
out_t_s: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
if out_t_final.is_null() || out_t_s.is_null() {
return CoppStatus::NullPointer.into_ffi_status();
}
let out_t_s = match CoppVecF64::out_ptr(out_t_s) {
Ok(out_t_s) => out_t_s,
Err(status) => return status,
};
unsafe {
CoppVecF64::write_empty_to(out_t_s);
}
match catch_unwind(AssertUnwindSafe(|| {
let s = unsafe { s.as_slice()? };
let a = unsafe { a.as_slice()? };
let (t_final, t_s) = s_to_t_topp2(s, a, t0).map_err(interpolation_status)?;
unsafe {
out_t_final.write(t_final);
}
unsafe {
CoppVecF64::write_vec_to(out_t_s, t_s);
}
Ok(CoppStatus::Ok)
})) {
Ok(Ok(status)) | Ok(Err(status)) => status.into_ffi_status(),
Err(payload) => panic_to_status(payload).into_ffi_status(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_t_to_s_uniform_2nd(
s: CoppSliceF64,
a: CoppSliceF64,
t_s: CoppSliceF64,
t0: f64,
dt: f64,
include_final: bool,
out_s_t: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
topp2_t_to_s_common(s, a, t_s, out_s_t, |s, a, t_s| {
t_to_s_topp2(
s,
a,
t_s,
InterpolationMode::UniformTimeGrid(t0, dt, include_final),
)
.map_err(interpolation_status)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_t_to_s_non_uniform_2nd(
s: CoppSliceF64,
a: CoppSliceF64,
t_s: CoppSliceF64,
t_sample: CoppSliceF64,
out_s_t: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
topp2_t_to_s_common(s, a, t_s, out_s_t, |s, a, t_s| {
let t_sample = unsafe { t_sample.as_slice()? };
t_to_s_topp2(s, a, t_s, InterpolationMode::NonUniformTimeGrid(t_sample))
.map_err(interpolation_status)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_s_to_t_3rd(
s: CoppSliceF64,
a: CoppSliceF64,
b: CoppSliceF64,
num_stationary_start: usize,
num_stationary_end: usize,
t0: f64,
out_t_final: *mut f64,
out_t_s: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
if out_t_final.is_null() || out_t_s.is_null() {
return CoppStatus::NullPointer.into_ffi_status();
}
let out_t_s = match CoppVecF64::out_ptr(out_t_s) {
Ok(out_t_s) => out_t_s,
Err(status) => return status,
};
unsafe {
CoppVecF64::write_empty_to(out_t_s);
}
match catch_unwind(AssertUnwindSafe(|| {
let s = unsafe { s.as_slice()? };
let a = unsafe { a.as_slice()? };
let b = unsafe { b.as_slice()? };
let (t_final, t_s) =
s_to_t_topp3(s, (a, b, (num_stationary_start, num_stationary_end)), t0)
.map_err(interpolation_status)?;
unsafe {
out_t_final.write(t_final);
}
unsafe {
CoppVecF64::write_vec_to(out_t_s, t_s);
}
Ok(CoppStatus::Ok)
})) {
Ok(Ok(status)) | Ok(Err(status)) => status.into_ffi_status(),
Err(payload) => panic_to_status(payload).into_ffi_status(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_t_to_s_uniform_3rd(
s: CoppSliceF64,
a: CoppSliceF64,
b: CoppSliceF64,
num_stationary_start: usize,
num_stationary_end: usize,
t_s: CoppSliceF64,
t0: f64,
dt: f64,
include_final: bool,
out_s_t: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
topp3_t_to_s_common(
s,
a,
b,
(num_stationary_start, num_stationary_end),
t_s,
out_s_t,
|s, a, b, num_stationary, t_s| {
t_to_s_topp3(
s,
(a, b, num_stationary),
t_s,
InterpolationMode::UniformTimeGrid(t0, dt, include_final),
)
.map_err(interpolation_status)
},
)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_t_to_s_non_uniform_3rd(
s: CoppSliceF64,
a: CoppSliceF64,
b: CoppSliceF64,
num_stationary_start: usize,
num_stationary_end: usize,
t_s: CoppSliceF64,
t_sample: CoppSliceF64,
out_s_t: *mut CoppVecF64,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
topp3_t_to_s_common(
s,
a,
b,
(num_stationary_start, num_stationary_end),
t_s,
out_s_t,
|s, a, b, num_stationary, t_s| {
let t_sample = unsafe { t_sample.as_slice()? };
t_to_s_topp3(
s,
(a, b, num_stationary),
t_s,
InterpolationMode::NonUniformTimeGrid(t_sample),
)
.map_err(interpolation_status)
},
)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn copp_force_positive_a_3rd(
s: CoppSliceF64,
a: CoppSliceMutF64,
b: CoppSliceMutF64,
num_stationary_start: usize,
num_stationary_end: usize,
a_min: f64,
out_succeed: *mut bool,
) -> CoppStatus {
crate::ffi::c::core::status::clear_last_error();
if out_succeed.is_null() {
return CoppStatus::NullPointer.into_ffi_status();
}
unsafe {
out_succeed.write(false);
}
match catch_unwind(AssertUnwindSafe(|| {
let s = unsafe { s.as_slice()? };
let a = unsafe { a.as_mut_slice()? };
let b = unsafe { b.as_mut_slice()? };
let succeed =
force_positive_a((a, b, (num_stationary_start, num_stationary_end)), s, a_min)
.map_err(interpolation_status)?;
unsafe {
out_succeed.write(succeed);
}
Ok(CoppStatus::Ok)
})) {
Ok(Ok(status)) | Ok(Err(status)) => status.into_ffi_status(),
Err(payload) => panic_to_status(payload).into_ffi_status(),
}
}
fn topp2_t_to_s_common(
s: CoppSliceF64,
a: CoppSliceF64,
t_s: CoppSliceF64,
out_s_t: *mut CoppVecF64,
interpolate: impl FnOnce(&[f64], &[f64], &[f64]) -> Result<Vec<f64>, CoppStatus>,
) -> CoppStatus {
let out_s_t = match CoppVecF64::out_ptr(out_s_t) {
Ok(out_s_t) => out_s_t,
Err(status) => return status,
};
unsafe {
CoppVecF64::write_empty_to(out_s_t);
}
match catch_unwind(AssertUnwindSafe(|| {
let s = unsafe { s.as_slice()? };
let a = unsafe { a.as_slice()? };
let t_s = unsafe { t_s.as_slice()? };
let s_t = interpolate(s, a, t_s)?;
unsafe {
CoppVecF64::write_vec_to(out_s_t, s_t);
}
Ok(CoppStatus::Ok)
})) {
Ok(Ok(status)) | Ok(Err(status)) => status.into_ffi_status(),
Err(payload) => panic_to_status(payload).into_ffi_status(),
}
}
fn topp3_t_to_s_common(
s: CoppSliceF64,
a: CoppSliceF64,
b: CoppSliceF64,
num_stationary: (usize, usize),
t_s: CoppSliceF64,
out_s_t: *mut CoppVecF64,
interpolate: impl FnOnce(
&[f64],
&[f64],
&[f64],
(usize, usize),
&[f64],
) -> Result<Vec<f64>, CoppStatus>,
) -> CoppStatus {
let out_s_t = match CoppVecF64::out_ptr(out_s_t) {
Ok(out_s_t) => out_s_t,
Err(status) => return status,
};
unsafe {
CoppVecF64::write_empty_to(out_s_t);
}
let (num_stationary_start, num_stationary_end) = num_stationary;
match catch_unwind(AssertUnwindSafe(|| {
let s = unsafe { s.as_slice()? };
let a = unsafe { a.as_slice()? };
let b = unsafe { b.as_slice()? };
let t_s = unsafe { t_s.as_slice()? };
let s_t = interpolate(s, a, b, (num_stationary_start, num_stationary_end), t_s)?;
unsafe {
CoppVecF64::write_vec_to(out_s_t, s_t);
}
Ok(CoppStatus::Ok)
})) {
Ok(Ok(status)) | Ok(Err(status)) => status.into_ffi_status(),
Err(payload) => panic_to_status(payload).into_ffi_status(),
}
}
fn interpolation_status(error: CoppError) -> CoppStatus {
match error {
CoppError::InvalidInput(_, _) => CoppStatus::InvalidArgument,
error => CoppStatus::from(&error),
}
}