use std::{
ffi::{CStr, CString},
mem::MaybeUninit,
os::raw::{c_char, c_int, c_void},
ptr,
time::Duration,
};
use crate::{
addr::SocketAddr,
error::{Error, Result},
util::validate_ptr,
};
pub trait OptOps: super::Opt
{
fn get<T: HasOpts>(s: &T) -> Result<Self::OptType>;
fn set<T: HasOpts>(s: &T, val: Self::OptType) -> Result<()>;
}
pub trait HasOpts: Sized
{
type Handle;
const GETOPT_BOOL: unsafe extern "C" fn(Self::Handle, *const c_char, *mut bool) -> c_int;
const GETOPT_INT: unsafe extern "C" fn(Self::Handle, *const c_char, *mut c_int) -> c_int;
const GETOPT_MS: unsafe extern "C" fn(
Self::Handle,
*const c_char,
*mut nng_sys::nng_duration,
) -> c_int;
const GETOPT_SIZE: unsafe extern "C" fn(Self::Handle, *const c_char, *mut usize) -> c_int;
const GETOPT_SOCKADDR: unsafe extern "C" fn(
Self::Handle,
*const c_char,
*mut nng_sys::nng_sockaddr,
) -> c_int;
const GETOPT_STRING: unsafe extern "C" fn(
Self::Handle,
*const c_char,
*mut *mut c_char,
) -> c_int;
const GETOPT_UINT64: unsafe extern "C" fn(Self::Handle, *const c_char, *mut u64) -> c_int;
const SETOPT: unsafe extern "C" fn(Self::Handle, *const c_char, *const c_void, usize) -> c_int;
const SETOPT_BOOL: unsafe extern "C" fn(Self::Handle, *const c_char, bool) -> c_int;
const SETOPT_INT: unsafe extern "C" fn(Self::Handle, *const c_char, c_int) -> c_int;
const SETOPT_MS: unsafe extern "C" fn(
Self::Handle,
*const c_char,
nng_sys::nng_duration,
) -> c_int;
const SETOPT_PTR: unsafe extern "C" fn(Self::Handle, *const c_char, *mut c_void) -> c_int;
const SETOPT_SIZE: unsafe extern "C" fn(Self::Handle, *const c_char, usize) -> c_int;
const SETOPT_STRING: unsafe extern "C" fn(Self::Handle, *const c_char, *const c_char) -> c_int;
fn handle(&self) -> Self::Handle;
fn getopt_bool(&self, opt: *const c_char) -> Result<bool>
{
let mut raw = false;
let rv = unsafe { (Self::GETOPT_BOOL)(self.handle(), opt, &mut raw as _) };
rv2res!(rv, raw)
}
fn getopt_int(&self, opt: *const c_char) -> Result<i32>
{
let mut res = 0;
let rv = unsafe { (Self::GETOPT_INT)(self.handle(), opt, &mut res as _) };
rv2res!(rv, res)
}
fn getopt_ms(&self, opt: *const c_char) -> Result<Option<Duration>>
{
let mut dur: nng_sys::nng_duration = 0;
let rv = unsafe { (Self::GETOPT_MS)(self.handle(), opt, &mut dur as _) };
rv2res!(rv, crate::util::nng_to_duration(dur))
}
fn getopt_size(&self, opt: *const c_char) -> Result<usize>
{
let mut sz = 0;
let rv = unsafe { (Self::GETOPT_SIZE)(self.handle(), opt, &mut sz as _) };
rv2res!(rv, sz)
}
fn getopt_sockaddr(&self, opt: *const c_char) -> Result<SocketAddr>
{
unsafe {
let mut addr: MaybeUninit<nng_sys::nng_sockaddr> = MaybeUninit::uninit();
let rv = (Self::GETOPT_SOCKADDR)(self.handle(), opt, addr.as_mut_ptr());
rv2res!(rv, addr.assume_init().into())
}
}
fn getopt_string(&self, opt: *const c_char) -> Result<String>
{
unsafe {
let mut ptr: *mut c_char = ptr::null_mut();
let rv = (Self::GETOPT_STRING)(self.handle(), opt, &mut ptr as *mut _);
let ptr = validate_ptr(rv, ptr)?;
let name = CStr::from_ptr(ptr.as_ptr()).to_string_lossy().into_owned();
nng_sys::nng_strfree(ptr.as_ptr());
Ok(name)
}
}
fn getopt_uint64(&self, opt: *const c_char) -> Result<u64>
{
let mut res = 0;
let rv = unsafe { (Self::GETOPT_UINT64)(self.handle(), opt, &mut res as _) };
rv2res!(rv, res)
}
fn setopt(&self, opt: *const c_char, val: &[u8]) -> Result<()>
{
let rv = unsafe { (Self::SETOPT)(self.handle(), opt, val.as_ptr() as _, val.len()) };
rv2res!(rv)
}
fn setopt_bool(&self, opt: *const c_char, val: bool) -> Result<()>
{
let rv = unsafe { (Self::SETOPT_BOOL)(self.handle(), opt, val) };
rv2res!(rv)
}
fn setopt_int(&self, opt: *const c_char, val: i32) -> Result<()>
{
let rv = unsafe { (Self::SETOPT_INT)(self.handle(), opt, val) };
rv2res!(rv)
}
fn setopt_ms(&self, opt: *const c_char, dur: Option<Duration>) -> Result<()>
{
let ms = crate::util::duration_to_nng(dur);
let rv = unsafe { (Self::SETOPT_MS)(self.handle(), opt, ms) };
rv2res!(rv)
}
unsafe fn setopt_ptr(&self, opt: *const c_char, val: *mut c_void) -> Result<()>
{
let rv = (Self::SETOPT_PTR)(self.handle(), opt, val);
rv2res!(rv)
}
fn setopt_size(&self, opt: *const c_char, val: usize) -> Result<()>
{
let rv = unsafe { (Self::SETOPT_SIZE)(self.handle(), opt, val) };
rv2res!(rv)
}
fn setopt_string(&self, opt: *const c_char, val: &str) -> Result<()>
{
let cval = CString::new(val).map_err(|_| Error::InvalidInput)?;
let rv = unsafe { (Self::SETOPT_STRING)(self.handle(), opt, cval.as_ptr()) };
rv2res!(rv)
}
}