nng_c/
options.rs

1//! Options
2
3use crate::sys;
4use crate::socket::Socket;
5use crate::error::{error, ErrorCode};
6
7use core::{fmt, time};
8use core::convert::TryInto;
9
10///Property interface
11pub trait Property<T>: Sized {
12    ///Gets instance of self from the `target
13    fn get(target: &T) -> Result<Self, ErrorCode>;
14}
15
16///Options interface
17pub trait Options<T> {
18    ///Applies options to the target, returning error if any happens
19    fn apply(&self, target: &T) -> Result<(), ErrorCode>;
20}
21
22impl<T> Options<T> for () {
23    #[inline(always)]
24    fn apply(&self, _: &T) -> Result<(), ErrorCode> {
25        Ok(())
26    }
27}
28
29macro_rules! set_bytes_option {
30    ($socket:expr, $name:expr, $bytes:expr) => {
31        unsafe {
32            let bytes = $bytes;
33            match sys::nng_socket_set($socket, $name.as_ptr() as _, bytes.as_ptr() as _, bytes.len()) {
34                0 => Ok(()),
35                code => Err(error(code)),
36            }
37        }
38    }
39}
40
41macro_rules! set_string_option {
42    ($socket:expr, $name:expr, $bytes:expr) => {
43        unsafe {
44            let bytes = $bytes;
45            match sys::nng_socket_set_string($socket, $name.as_ptr() as _, bytes.as_ptr() as _) {
46                0 => Ok(()),
47                code => Err(error(code)),
48            }
49        }
50    }
51}
52
53macro_rules! set_int_option {
54    ($socket:expr, $name:expr, $num:expr) => {
55        unsafe {
56            match sys::nng_socket_set_int($socket, $name.as_ptr() as _, $num as _) {
57                0 => Ok(()),
58                code => Err(error(code)),
59            }
60        }
61    }
62}
63
64macro_rules! set_size_t_option {
65    ($socket:expr, $name:expr, $num:expr) => {
66        unsafe {
67            match sys::nng_socket_set_size($socket, $name.as_ptr() as _, $num as _) {
68                0 => Ok(()),
69                code => Err(error(code)),
70            }
71        }
72    }
73}
74
75macro_rules! set_duration_option {
76    ($socket:expr, $name:expr, $duration:expr) => {
77        match $duration.as_millis().try_into() {
78            Ok(duration) => unsafe {
79                match sys::nng_socket_set_ms($socket, $name.as_ptr() as _, duration) {
80                    0 => Ok(()),
81                    code => Err(error(code)),
82                }
83            },
84            Err(_) => Err(error(sys::nng_errno_enum::NNG_EINVAL)),
85        }
86    }
87}
88
89#[derive(Copy, Clone, Debug)]
90///Req protocol options
91pub struct Req {
92    ///Duration after which request is considered failed to be delivered
93    ///Therefore triggering re-sending
94    pub resend_time: Option<time::Duration>,
95    ///Granularity of the clock used to check for resending time
96    pub resend_tick: Option<time::Duration>,
97}
98
99impl Options<Socket> for Req {
100    #[inline]
101    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
102        if let Some(resend_time) = self.resend_time {
103            set_duration_option!(**target, sys::NNG_OPT_REQ_RESENDTIME, resend_time)?;
104        }
105
106        if let Some(resend_tick) = self.resend_tick {
107            set_duration_option!(**target, sys::NNG_OPT_REQ_RESENDTICK, resend_tick)?;
108        }
109
110        Ok(())
111    }
112}
113
114#[derive(Copy, Clone, Debug)]
115///Topic to subscribe to for sub protocol.
116pub struct Subscribe<'a>(pub &'a [u8]);
117
118impl Options<Socket> for Subscribe<'_> {
119    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
120        set_bytes_option!(**target, sys::NNG_OPT_SUB_SUBSCRIBE, self.0)
121    }
122}
123
124#[derive(Copy, Clone, Debug)]
125///Topic to unsubscribe from for sub protocol.
126pub struct Unsubscribe<'a>(pub &'a [u8]);
127
128impl Options<Socket> for Unsubscribe<'_> {
129    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
130        set_bytes_option!(**target, sys::NNG_OPT_SUB_UNSUBSCRIBE, self.0)
131    }
132}
133
134#[derive(Copy, Clone, Debug)]
135///Max number of hops message can make to reach peer
136///
137///Usually defaults to 8
138pub struct MaxTtl(pub u8);
139
140impl Options<Socket> for MaxTtl {
141    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
142        set_int_option!(**target, sys::NNG_OPT_MAXTTL, self.0)
143    }
144}
145
146#[derive(Copy, Clone, Debug)]
147///Reconnect options
148pub struct Reconnect {
149    ///This is the minimum amount of time to wait before attempting to establish a connection after a previous attempt has failed
150    pub min_time: Option<time::Duration>,
151    ///This is the maximum amount of time to wait before attempting to establish a connection after a previous attempt has failed
152    ///
153    ///This can be set to 0, to disable exponential back-off
154    pub max_time: Option<time::Duration>,
155}
156
157impl Options<Socket> for Reconnect {
158    #[inline]
159    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
160        if let Some(min_time) = self.min_time {
161            set_duration_option!(**target, sys::NNG_OPT_RECONNMINT, min_time)?;
162        }
163
164        if let Some(max_time) = self.max_time {
165            set_duration_option!(**target, sys::NNG_OPT_RECONNMAXT, max_time)?;
166        }
167
168        Ok(())
169    }
170}
171
172#[derive(Copy, Clone, Debug)]
173///Sets internal receive buffer to this amount of messages
174///
175///Allowed values are from 0 to 8192.
176pub struct RecvBuf(pub u16);
177
178impl Options<Socket> for RecvBuf {
179    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
180        set_int_option!(**target, sys::NNG_OPT_RECVBUF, self.0)
181    }
182}
183
184#[derive(Copy, Clone, Debug)]
185///Limits size of message that socket can receive
186///
187///This specifically limits byte size of message, rejecting any attempt sending receiving of size beyond the limit.
188pub struct RecvMaxSize(pub usize);
189
190impl Options<Socket> for RecvMaxSize {
191    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
192        set_size_t_option!(**target, sys::NNG_OPT_RECVMAXSZ, self.0)
193    }
194}
195
196#[derive(Copy, Clone, Debug)]
197///Sets timeout on message receive.
198///
199///If no message is available within specified time, then it shall error out with timed_out error
200pub struct RecvTimeout(pub time::Duration);
201
202impl Options<Socket> for RecvTimeout {
203    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
204        set_duration_option!(**target, sys::NNG_OPT_RECVTIMEO, self.0)
205    }
206}
207
208#[derive(Copy, Clone, Debug)]
209///Sets internal send buffer to this amount of messages
210///
211///Allowed values are from 0 to 8192.
212pub struct SendBuf(pub u16);
213
214impl Options<Socket> for SendBuf {
215    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
216        set_int_option!(**target, sys::NNG_OPT_SENDBUF, self.0)
217    }
218}
219
220#[derive(Copy, Clone, Debug)]
221///Sets timeout on message send.
222///
223///If message cannot be sent within specified time, then it shall error out with timed_out error
224pub struct SendTimeout(pub time::Duration);
225
226impl Options<Socket> for SendTimeout {
227    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
228        set_duration_option!(**target, sys::NNG_OPT_SENDTIMEO, self.0)
229    }
230}
231
232#[derive(Copy, Clone, Eq)]
233///Socket name, limited to 63 characters.
234///
235///This is purely informative property without any functional use by nng itself
236pub struct SocketName(pub(crate) [u8; 64]);
237
238impl SocketName {
239    ///Creates new name, returning `Some` if input fits 63 characters limit
240    pub fn new(name: &str) -> Option<Self> {
241        let mut buf = [0; 64];
242        if name.len() < buf.len() {
243            buf[..name.len()].copy_from_slice(name.as_bytes());
244            Some(Self(buf))
245        } else {
246            None
247        }
248    }
249
250    ///Access raw bytes
251    pub fn as_bytes(&self) -> &[u8] {
252        if let Some(idx) = self.0.iter().position(|byt| *byt == 0) {
253            &self.0[..idx]
254        } else {
255            &self.0
256        }
257    }
258
259    ///Returns string, if raw bytes are valid unicode
260    pub fn as_str(&self) -> Option<&str> {
261        core::str::from_utf8(self.as_bytes()).ok()
262    }
263}
264
265impl Options<Socket> for SocketName {
266    fn apply(&self, target: &Socket) -> Result<(), ErrorCode> {
267        set_string_option!(**target, sys::NNG_OPT_SOCKNAME, self.0)
268    }
269}
270
271impl Property<Socket> for SocketName {
272    fn get(target: &Socket) -> Result<Self, ErrorCode> {
273        let mut buf = [0; 64];
274        let result = unsafe {
275            sys::nng_socket_get(**target, sys::NNG_OPT_SOCKNAME.as_ptr() as _, buf.as_mut_ptr() as _, &mut buf.len())
276        };
277
278        match result {
279            0 => Ok(Self(buf)),
280            code => Err(error(code))
281        }
282    }
283}
284
285impl PartialEq for SocketName {
286    #[inline]
287    fn eq(&self, other: &Self) -> bool {
288        self.as_bytes() == other.as_bytes()
289    }
290}
291
292impl PartialEq<PeerName> for SocketName {
293    #[inline]
294    fn eq(&self, other: &PeerName) -> bool {
295        self.as_bytes() == other.0.as_bytes()
296    }
297}
298
299impl PartialEq<str> for SocketName {
300    #[inline]
301    fn eq(&self, other: &str) -> bool {
302        self.as_bytes() == other.as_bytes()
303    }
304}
305
306impl PartialEq<&str> for SocketName {
307    #[inline]
308    fn eq(&self, other: &&str) -> bool {
309        self.as_bytes() == other.as_bytes()
310    }
311}
312
313impl PartialEq<SocketName> for str {
314    #[inline]
315    fn eq(&self, other: &SocketName) -> bool {
316        self.as_bytes() == other.as_bytes()
317    }
318}
319
320impl PartialEq<SocketName> for &str {
321    #[inline]
322    fn eq(&self, other: &SocketName) -> bool {
323        self.as_bytes() == other.as_bytes()
324    }
325}
326
327impl fmt::Debug for SocketName {
328    #[inline]
329    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
330        let mut fmt = fmt.debug_tuple("SocketName");
331        match self.as_str() {
332            Some(name) => fmt.field(&name).finish(),
333            None => fmt.field(&self.0).finish(),
334        }
335    }
336}
337
338impl fmt::Display for SocketName {
339    #[inline]
340    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
341        match self.as_str() {
342            Some(name) => fmt.write_str(name),
343            None => fmt.write_str("<non-utf-8>"),
344        }
345    }
346}
347
348#[derive(Copy, Clone, Eq)]
349#[repr(transparent)]
350///Peer name, limited to 63 characters.
351///
352///This tells protocol of the peer
353pub struct PeerName(pub(crate) SocketName);
354
355impl Property<Socket> for PeerName {
356    fn get(target: &Socket) -> Result<Self, ErrorCode> {
357        let mut buf = [0; 64];
358        let result = unsafe {
359            sys::nng_socket_get(**target, sys::NNG_OPT_PEERNAME.as_ptr() as _, buf.as_mut_ptr() as _, &mut buf.len())
360        };
361
362        match result {
363            0 => Ok(Self(SocketName(buf))),
364            code => Err(error(code))
365        }
366    }
367}
368
369impl PartialEq<SocketName> for PeerName {
370    #[inline]
371    fn eq(&self, other: &SocketName) -> bool {
372        self.0.as_bytes() == other.as_bytes()
373    }
374}
375
376impl PartialEq for PeerName {
377    #[inline]
378    fn eq(&self, other: &Self) -> bool {
379        self.0.as_bytes() == other.0.as_bytes()
380    }
381}
382
383impl PartialEq<str> for PeerName {
384    #[inline]
385    fn eq(&self, other: &str) -> bool {
386        self.0.as_bytes() == other.as_bytes()
387    }
388}
389
390impl PartialEq<&str> for PeerName {
391    #[inline]
392    fn eq(&self, other: &&str) -> bool {
393        self.0.as_bytes() == other.as_bytes()
394    }
395}
396
397impl PartialEq<PeerName> for str {
398    #[inline]
399    fn eq(&self, other: &PeerName) -> bool {
400        self.as_bytes() == other.0.as_bytes()
401    }
402}
403
404impl PartialEq<PeerName> for &str {
405    #[inline]
406    fn eq(&self, other: &PeerName) -> bool {
407        self.as_bytes() == other.0.as_bytes()
408    }
409}
410
411impl fmt::Debug for PeerName {
412    #[inline]
413    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
414        let mut fmt = fmt.debug_tuple("PeerName");
415        match self.0.as_str() {
416            Some(name) => fmt.field(&name).finish(),
417            None => fmt.field(&self.0).finish(),
418        }
419    }
420}
421
422impl fmt::Display for PeerName {
423    #[inline]
424    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
425        match self.0.as_str() {
426            Some(name) => fmt.write_str(name),
427            None => fmt.write_str("<non-utf-8>"),
428        }
429    }
430}