use std::ffi::c_char;
use crate::ffi::{
any::{AnyObject, CallbackFn, Downcast, wrap_func},
util::{ExtrinsicObject, c_bool},
};
use opendp_derive::bootstrap;
use crate::{
core::{FfiResult, Measure},
error::Fallible,
ffi::{
any::AnyMeasure,
util::{self, into_c_char_p, to_str},
},
measures::{Approximate, MaxDivergence, ZeroConcentratedDivergence},
};
use super::{PrivacyProfile, RenyiDivergence, SmoothedMaxDivergence};
#[bootstrap(
name = "_measure_free",
arguments(this(do_not_convert = true)),
returns(c_type = "FfiResult<void *>")
)]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures___measure_free(this: *mut AnyMeasure) -> FfiResult<*mut ()> {
util::into_owned(this).map(|_| ()).into()
}
#[bootstrap(
name = "_measure_equal",
returns(c_type = "FfiResult<bool *>", hint = "bool")
)]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures___measure_equal(
left: *mut AnyMeasure,
right: *const AnyMeasure,
) -> FfiResult<*mut c_bool> {
let status = try_as_ref!(left) == try_as_ref!(right);
FfiResult::Ok(util::into_raw(util::from_bool(status)))
}
#[bootstrap(
name = "measure_debug",
arguments(this(rust_type = b"null")),
returns(c_type = "FfiResult<char *>")
)]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__measure_debug(this: *mut AnyMeasure) -> FfiResult<*mut c_char> {
let this = try_as_ref!(this);
FfiResult::Ok(try_!(into_c_char_p(format!("{:?}", this))))
}
#[bootstrap(
name = "measure_type",
arguments(this(rust_type = b"null")),
returns(c_type = "FfiResult<char *>")
)]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__measure_type(this: *mut AnyMeasure) -> FfiResult<*mut c_char> {
let this = try_as_ref!(this);
FfiResult::Ok(try_!(into_c_char_p(this.type_.descriptor.to_string())))
}
#[bootstrap(
name = "measure_distance_type",
arguments(this(rust_type = b"null")),
returns(c_type = "FfiResult<char *>")
)]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__measure_distance_type(
this: *mut AnyMeasure,
) -> FfiResult<*mut c_char> {
let this = try_as_ref!(this);
FfiResult::Ok(try_!(into_c_char_p(
this.distance_type.descriptor.to_string()
)))
}
#[bootstrap(name = "max_divergence")]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__max_divergence() -> FfiResult<*mut AnyMeasure> {
Ok(AnyMeasure::new(MaxDivergence)).into()
}
#[bootstrap(name = "smoothed_max_divergence")]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__smoothed_max_divergence() -> FfiResult<*mut AnyMeasure> {
Ok(AnyMeasure::new(SmoothedMaxDivergence)).into()
}
#[bootstrap(name = "fixed_smoothed_max_divergence")]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__fixed_smoothed_max_divergence() -> FfiResult<*mut AnyMeasure> {
Ok(AnyMeasure::new(Approximate(MaxDivergence))).into()
}
#[bootstrap(
rust_path = "measures/struct.Approximate",
generics(M(suppress)),
arguments(measure(c_type = "AnyMeasure *", rust_type = b"null")),
returns(c_type = "FfiResult<AnyMeasure *>", hint = "ApproximateDivergence")
)]
fn approximate<M: Measure>(measure: M) -> Approximate<M> {
Approximate(measure)
}
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__approximate(
measure: *const AnyMeasure,
) -> FfiResult<*mut AnyMeasure> {
fn monomorphize<MO: 'static + Measure>(measure: &AnyMeasure) -> Fallible<AnyMeasure> {
let measure = measure.downcast_ref::<MO>()?.clone();
Ok(AnyMeasure::new(approximate(measure)))
}
let measure = try_as_ref!(measure);
let MO = measure.type_.clone();
dispatch!(
monomorphize,
[(
MO,
[
MaxDivergence,
SmoothedMaxDivergence,
ZeroConcentratedDivergence,
ExtrinsicDivergence
]
)],
(measure)
)
.into()
}
#[bootstrap(name = "_approximate_divergence_get_inner_measure")]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures___approximate_divergence_get_inner_measure(
privacy_measure: *const AnyMeasure,
) -> FfiResult<*mut AnyMeasure> {
let privacy_measure = try_as_ref!(privacy_measure);
let M = privacy_measure.type_.clone();
let T = try_!(M.get_atom());
fn monomorphize<M: 'static + Measure>(privacy_measure: &AnyMeasure) -> Fallible<AnyMeasure> {
let privacy_measure = privacy_measure.downcast_ref::<Approximate<M>>()?.clone();
Ok(AnyMeasure::new(privacy_measure.0.clone()))
}
dispatch!(
monomorphize,
[(
T,
[
MaxDivergence,
SmoothedMaxDivergence,
ZeroConcentratedDivergence,
ExtrinsicDivergence
]
)],
(privacy_measure)
)
.into()
}
#[bootstrap(name = "zero_concentrated_divergence")]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__zero_concentrated_divergence() -> FfiResult<*mut AnyMeasure> {
Ok(AnyMeasure::new(ZeroConcentratedDivergence)).into()
}
#[bootstrap(name = "renyi_divergence")]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__renyi_divergence() -> FfiResult<*mut AnyMeasure> {
Ok(AnyMeasure::new(RenyiDivergence)).into()
}
#[derive(Clone, Default)]
pub struct ExtrinsicDivergence {
pub descriptor: String,
}
impl std::fmt::Debug for ExtrinsicDivergence {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "UserDivergence({:?})", self.descriptor)
}
}
impl PartialEq for ExtrinsicDivergence {
fn eq(&self, other: &Self) -> bool {
self.descriptor == other.descriptor
}
}
impl Measure for ExtrinsicDivergence {
type Distance = ExtrinsicObject;
}
#[bootstrap(
name = "user_divergence",
features("honest-but-curious"),
arguments(descriptor(rust_type = "String"))
)]
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__user_divergence(
descriptor: *mut c_char,
) -> FfiResult<*mut AnyMeasure> {
let descriptor = try_!(to_str(descriptor)).to_string();
Ok(AnyMeasure::new(ExtrinsicDivergence { descriptor })).into()
}
#[bootstrap(
name = "new_privacy_profile",
features("contrib", "honest-but-curious"),
arguments(curve(rust_type = "f64")),
returns(rust_type = "PrivacyProfile")
)]
#[allow(dead_code)]
fn new_privacy_profile(curve: *const CallbackFn) -> Fallible<AnyObject> {
let _ = curve;
panic!("this signature only exists for code generation")
}
#[unsafe(no_mangle)]
pub extern "C" fn opendp_measures__new_privacy_profile(
curve: *const CallbackFn,
) -> FfiResult<*mut AnyObject> {
let curve = wrap_func(try_as_ref!(curve).clone());
FfiResult::Ok(AnyObject::new_raw(PrivacyProfile::new(
move |epsilon: f64| curve(&AnyObject::new(epsilon))?.downcast::<f64>(),
)))
}