use std::ffi::c_void;
use anyhow::Result;
use async_trait::async_trait;
use drasi_lib::identity::{CredentialContext, Credentials, IdentityProvider};
use super::identity::IdentityProviderVtable;
pub struct FfiIdentityProviderProxy {
vtable: IdentityProviderVtable,
}
unsafe impl Send for FfiIdentityProviderProxy {}
unsafe impl Sync for FfiIdentityProviderProxy {}
impl FfiIdentityProviderProxy {
pub unsafe fn new(vtable: *const IdentityProviderVtable) -> Self {
assert!(
!vtable.is_null(),
"FfiIdentityProviderProxy::new: vtable pointer is null"
);
let vtable = &*vtable;
Self {
vtable: IdentityProviderVtable {
state: vtable.state,
get_credentials_fn: vtable.get_credentials_fn,
clone_fn: vtable.clone_fn,
drop_fn: vtable.drop_fn,
},
}
}
}
#[async_trait]
impl IdentityProvider for FfiIdentityProviderProxy {
async fn get_credentials(&self, context: &CredentialContext) -> Result<Credentials> {
let context_json =
serde_json::to_string(&context.properties).unwrap_or_else(|_| "{}".to_string());
let result = (self.vtable.get_credentials_fn)(
self.vtable.state,
context_json.as_ptr(),
context_json.len(),
);
unsafe { result.into_result() }
}
fn clone_box(&self) -> Box<dyn IdentityProvider> {
let cloned_state = (self.vtable.clone_fn)(self.vtable.state);
Box::new(FfiIdentityProviderProxy {
vtable: IdentityProviderVtable {
state: cloned_state,
get_credentials_fn: self.vtable.get_credentials_fn,
clone_fn: self.vtable.clone_fn,
drop_fn: self.vtable.drop_fn,
},
})
}
}
impl Drop for FfiIdentityProviderProxy {
fn drop(&mut self) {
debug_assert!(
!self.vtable.state.is_null(),
"FfiIdentityProviderProxy::drop: state is null; clone_fn may have panicked"
);
(self.vtable.drop_fn)(self.vtable.state);
}
}