use std::{
cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
ffi::CString,
hash::{Hash, Hasher},
num::NonZeroU32,
};
use crate::{
error::{Error, Result},
socket::Socket,
};
#[derive(Clone, Copy, Debug)]
pub struct Dialer
{
handle: nng_sys::nng_dialer,
}
impl Dialer
{
pub fn new(socket: &Socket, url: &str, nonblocking: bool) -> Result<Self>
{
let addr = CString::new(url).map_err(|_| Error::AddressInvalid)?;
let mut handle = nng_sys::nng_dialer::NNG_DIALER_INITIALIZER;
let flags = if nonblocking { nng_sys::NNG_FLAG_NONBLOCK } else { 0 };
let rv = unsafe {
nng_sys::nng_dial(socket.handle(), addr.as_ptr(), &mut handle as *mut _, flags as i32)
};
rv2res!(rv, Dialer { handle })
}
#[allow(clippy::missing_panics_doc)]
pub fn close(self)
{
let rv = unsafe { nng_sys::nng_dialer_close(self.handle) };
assert!(
rv == 0 || rv == nng_sys::NNG_ECLOSED as i32,
"Unexpected error code while closing dialer ({})",
rv
);
}
pub(crate) fn from_nng_sys(handle: nng_sys::nng_dialer) -> Self
{
assert!(unsafe { nng_sys::nng_dialer_id(handle) > 0 }, "Dialer handle is not initialized");
Dialer { handle }
}
}
#[cfg(feature = "ffi-module")]
impl Dialer
{
pub fn nng_dialer(self) -> nng_sys::nng_dialer { self.handle }
}
impl PartialEq for Dialer
{
fn eq(&self, other: &Dialer) -> bool
{
unsafe { nng_sys::nng_dialer_id(self.handle) == nng_sys::nng_dialer_id(other.handle) }
}
}
impl Eq for Dialer {}
impl PartialOrd for Dialer
{
fn partial_cmp(&self, other: &Dialer) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl Ord for Dialer
{
fn cmp(&self, other: &Dialer) -> Ordering
{
unsafe {
let us = nng_sys::nng_dialer_id(self.handle);
let them = nng_sys::nng_dialer_id(other.handle);
us.cmp(&them)
}
}
}
impl Hash for Dialer
{
fn hash<H: Hasher>(&self, state: &mut H)
{
let id = unsafe { nng_sys::nng_dialer_id(self.handle) };
id.hash(state);
}
}
#[rustfmt::skip]
expose_options!{
Dialer :: handle -> nng_sys::nng_dialer;
GETOPT_BOOL = nng_sys::nng_dialer_get_bool;
GETOPT_INT = nng_sys::nng_dialer_get_int;
GETOPT_MS = nng_sys::nng_dialer_get_ms;
GETOPT_SIZE = nng_sys::nng_dialer_get_size;
GETOPT_SOCKADDR = nng_sys::nng_dialer_get_addr;
GETOPT_STRING = nng_sys::nng_dialer_get_string;
GETOPT_UINT64 = nng_sys::nng_dialer_get_uint64;
SETOPT = nng_sys::nng_dialer_set;
SETOPT_BOOL = nng_sys::nng_dialer_set_bool;
SETOPT_INT = nng_sys::nng_dialer_set_int;
SETOPT_MS = nng_sys::nng_dialer_set_ms;
SETOPT_PTR = nng_sys::nng_dialer_set_ptr;
SETOPT_SIZE = nng_sys::nng_dialer_set_size;
SETOPT_STRING = nng_sys::nng_dialer_set_string;
Gets -> [LocalAddr, Raw, ReconnectMinTime,
ReconnectMaxTime, RecvBufferSize,
RecvMaxSize, RecvTimeout,
SendBufferSize, SendTimeout,
SocketName, MaxTtl, Url,
protocol::reqrep::ResendTime,
protocol::survey::SurveyTime,
transport::tcp::NoDelay,
transport::tcp::KeepAlive,
transport::websocket::Protocol];
Sets -> [];
}
#[derive(Debug)]
pub struct DialerBuilder
{
handle: nng_sys::nng_dialer,
}
impl DialerBuilder
{
pub fn new(socket: &Socket, url: &str) -> Result<Self>
{
let addr = CString::new(url).map_err(|_| Error::AddressInvalid)?;
let mut handle = nng_sys::nng_dialer::NNG_DIALER_INITIALIZER;
let rv = unsafe {
nng_sys::nng_dialer_create(&mut handle as *mut _, socket.handle(), addr.as_ptr())
};
rv2res!(rv, DialerBuilder { handle })
}
pub fn start(self, nonblocking: bool) -> std::result::Result<Dialer, (Self, Error)>
{
let flags = if nonblocking { nng_sys::NNG_FLAG_NONBLOCK } else { 0 };
let rv = unsafe { nng_sys::nng_dialer_start(self.handle, flags as i32) };
if let Some(e) = NonZeroU32::new(rv as u32) {
Err((self, Error::from(e)))
}
else {
let handle = Dialer { handle: self.handle };
std::mem::forget(self);
Ok(handle)
}
}
}
#[cfg(feature = "ffi-module")]
impl DialerBuilder
{
pub fn nng_dialer(&self) -> nng_sys::nng_dialer { self.handle }
}
#[rustfmt::skip]
expose_options!{
DialerBuilder :: handle -> nng_sys::nng_dialer;
GETOPT_BOOL = nng_sys::nng_dialer_get_bool;
GETOPT_INT = nng_sys::nng_dialer_get_int;
GETOPT_MS = nng_sys::nng_dialer_get_ms;
GETOPT_SIZE = nng_sys::nng_dialer_get_size;
GETOPT_SOCKADDR = nng_sys::nng_dialer_get_addr;
GETOPT_STRING = nng_sys::nng_dialer_get_string;
GETOPT_UINT64 = nng_sys::nng_dialer_get_uint64;
SETOPT = nng_sys::nng_dialer_set;
SETOPT_BOOL = nng_sys::nng_dialer_set_bool;
SETOPT_INT = nng_sys::nng_dialer_set_int;
SETOPT_MS = nng_sys::nng_dialer_set_ms;
SETOPT_PTR = nng_sys::nng_dialer_set_ptr;
SETOPT_SIZE = nng_sys::nng_dialer_set_size;
SETOPT_STRING = nng_sys::nng_dialer_set_string;
Gets -> [LocalAddr, Raw, ReconnectMinTime,
ReconnectMaxTime, RecvBufferSize,
RecvMaxSize, RecvTimeout,
SendBufferSize, SendTimeout,
SocketName, MaxTtl, Url,
protocol::reqrep::ResendTime,
protocol::survey::SurveyTime,
transport::tcp::NoDelay,
transport::tcp::KeepAlive,
transport::websocket::Protocol];
Sets -> [ReconnectMinTime, ReconnectMaxTime,
RecvMaxSize, transport::tcp::NoDelay,
transport::tcp::KeepAlive,
transport::tls::CaFile,
transport::tls::CertKeyFile,
transport::websocket::RequestHeaders,
transport::websocket::Protocol];
}
impl Drop for DialerBuilder
{
fn drop(&mut self)
{
let rv = unsafe { nng_sys::nng_dialer_close(self.handle) };
assert!(
rv == 0 || rv == nng_sys::NNG_ECLOSED as i32,
"Unexpected error code while closing dialer ({})",
rv
);
}
}