use std::{
ptr,
slice,
};
use libc::{
c_void,
size_t,
};
use crate::PublicKey;
#[repr(C)]
pub struct Signers {
signers: *const Signer,
signers_size: size_t,
free: Option<unsafe extern "C" fn(signers: *const Signer, signers_size: size_t)>,
}
impl Signers {
pub(super) fn as_slice(&self) -> &[Signer] {
if self.signers.is_null() {
&[]
} else {
unsafe { slice::from_raw_parts(self.signers, self.signers_size) }
}
}
}
impl Drop for Signers {
fn drop(&mut self) {
if let Some(free) = self.free {
unsafe { free(self.signers, self.signers_size) }
}
}
}
#[repr(C)]
pub struct Signer {
public_key: *const PublicKey,
context: *mut c_void,
sign_func: Option<
unsafe extern "C" fn(
context: *mut c_void,
message: *const u8,
message_size: size_t,
signature: *mut *const u8,
) -> size_t,
>,
free_signature_func: Option<
unsafe extern "C" fn(context: *mut c_void, signature: *mut u8, signature_size: size_t),
>,
free_context_func: Option<unsafe extern "C" fn(context: *mut c_void)>,
}
impl Signer {
pub(super) fn to_csigner(&self) -> CSigner {
let public_key = *unsafe { self.public_key.as_ref() }.unwrap();
let sign_func = self.sign_func.unwrap();
let free_signature_func = self.free_signature_func.unwrap();
CSigner {
public_key,
context: self.context,
sign_func,
free_signature_func,
free_context_func: self.free_context_func,
}
}
}
pub(super) type SignFn = unsafe extern "C" fn(
context: *mut c_void,
message: *const u8,
message_size: size_t,
signature: *mut *const u8,
) -> size_t;
pub(super) type FreeSignatureFn =
unsafe extern "C" fn(context: *mut c_void, signature: *mut u8, signature_size: size_t);
pub(crate) struct CSigner {
public_key: PublicKey,
context: *mut c_void,
sign_func: SignFn,
free_signature_func: FreeSignatureFn,
free_context_func: Option<unsafe extern "C" fn(context: *mut c_void)>,
}
impl CSigner {
pub(crate) fn public_key(&self) -> PublicKey {
self.public_key
}
pub(crate) fn sign(&self, message: &[u8]) -> (PublicKey, Vec<u8>) {
let message_size = message.len();
let message = message.as_ptr();
let mut signature = ptr::null();
let signature_size = unsafe {
(self.sign_func)(self.context, message, message_size, ptr::addr_of_mut!(signature))
};
assert!(!signature.is_null());
let signature_out = unsafe { slice::from_raw_parts(signature, signature_size) }.to_vec();
unsafe {
(self.free_signature_func)(self.context, signature.cast_mut(), signature_size);
}
(self.public_key, signature_out)
}
}
impl Drop for CSigner {
fn drop(&mut self) {
if let Some(free_context) = self.free_context_func {
unsafe { free_context(self.context) }
}
}
}
unsafe impl Send for CSigner {}
unsafe impl Sync for CSigner {}