use std::ptr;
use std::time::Duration;
use std::os::raw::{c_char, c_int, c_void};
use std::ffi::{CString, CStr};
use crate::error::{Result, ErrorKind};
use crate::addr::SocketAddr;
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 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_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::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: nng_sys::nng_sockaddr = std::mem::uninitialized();
let rv = (Self::GETOPT_SOCKADDR)(self.handle(), opt, &mut addr as _);
rv2res!(rv, addr.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 _);
validate_ptr!(rv, ptr);
let name = CStr::from_ptr(ptr).to_string_lossy().into_owned();
nng_sys::nng_strfree(ptr);
Ok(name)
}
}
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::duration_to_nng(dur);
let rv = unsafe {
(Self::SETOPT_MS)(self.handle(), opt, ms)
};
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(|_| ErrorKind::InvalidInput)?;
let rv = unsafe {
(Self::SETOPT_STRING)(self.handle(), opt, cval.as_ptr())
};
rv2res!(rv)
}
}