use std::ffi::c_char;
use std::os::raw::c_void;
use crate::core::{FfiResult, IntoAnyMeasurementFfiResultExt, Measure};
use crate::domains::{AtomDomain, MapDomain};
use crate::error::Fallible;
use crate::ffi::any::{AnyDomain, AnyMeasurement, AnyMetric, Downcast};
use crate::ffi::util::{Type, TypeContents, as_ref};
use crate::measurements::nature::Nature;
use crate::measurements::{MakeNoiseThreshold, make_gaussian_threshold};
use crate::measures::{Approximate, ZeroConcentratedDivergence};
use crate::metrics::{AbsoluteDistance, L02InfDistance};
use crate::traits::{Hashable, Number};
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measurements__make_gaussian_threshold(
input_domain: *const AnyDomain,
input_metric: *const AnyMetric,
scale: f64,
threshold: *const c_void,
k: *const i32,
MO: *const c_char,
) -> FfiResult<*mut AnyMeasurement> {
fn monomorphize<MO: 'static + Measure, TK, TV, QI>(
input_domain: &AnyDomain,
input_metric: &AnyMetric,
scale: f64,
threshold: *const c_void,
k: Option<i32>,
) -> Fallible<AnyMeasurement>
where
TK: Hashable,
TV: Number + Nature,
QI: Number,
<TV as Nature>::RV<2>: MakeNoiseThreshold<
MapDomain<AtomDomain<TK>, AtomDomain<TV>>,
L02InfDistance<AbsoluteDistance<QI>>,
MO,
Threshold = TV,
>,
{
let input_domain = input_domain
.downcast_ref::<MapDomain<AtomDomain<TK>, AtomDomain<TV>>>()?
.clone();
let input_metric = input_metric
.downcast_ref::<L02InfDistance<AbsoluteDistance<QI>>>()?
.clone();
let threshold = *try_as_ref!(threshold as *const TV);
make_gaussian_threshold(input_domain, input_metric, scale, threshold, k).into_any()
}
let input_domain = try_as_ref!(input_domain);
let input_metric = try_as_ref!(input_metric);
let TypeContents::GENERIC { name, args } = &input_domain.carrier_type.contents else {
return err!(
FFI,
"Generic type {:?} not supported",
input_domain.type_.descriptor
)
.into();
};
if !name.starts_with("HashMap") || args.len() != 2 {
return err!(
FFI,
"Domain not supported: {:?}. Must be MapDomain<AtomDomain<TK>, AtomDomain<TV>>",
input_domain.carrier_type.descriptor
)
.into();
}
let MO = try_!(Type::try_from(MO));
let TK = try_!(Type::of_id(&args[0]));
let TV = try_!(Type::of_id(&args[1]));
let QI = try_!(input_metric.type_.get_atom());
let k = as_ref(k as *const i32).map(Clone::clone);
dispatch!(monomorphize, [
(MO, [Approximate<ZeroConcentratedDivergence>]),
(TK, @hashable),
(TV, @numbers),
(QI, @numbers)
], (input_domain, input_metric, scale, threshold, k))
.into()
}