zmq/
message.rs

1use libc::size_t;
2
3use std::ffi;
4use std::fmt;
5use std::ops::{Deref, DerefMut};
6use std::os::raw::c_void;
7use std::{ptr, slice, str};
8
9use super::errno_to_error;
10
11/// Holds a 0MQ message.
12///
13/// A message is a single frame, either received or created locally and then
14/// sent over the wire. Multipart messages are transmitted as multiple
15/// `Message`s.
16///
17/// In rust-zmq, you aren't required to create message objects if you use the
18/// convenience APIs provided (e.g. `Socket::recv_bytes()` or
19/// `Socket::send()`). However, using message objects can make multiple
20/// operations in a loop more efficient, since allocated memory can be reused.
21pub struct Message {
22    msg: zmq_sys::zmq_msg_t,
23}
24
25impl Drop for Message {
26    fn drop(&mut self) {
27        unsafe {
28            let rc = zmq_sys::zmq_msg_close(&mut self.msg);
29            assert_eq!(rc, 0);
30        }
31    }
32}
33
34impl fmt::Debug for Message {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        write!(f, "{:?}", self.deref())
37    }
38}
39
40unsafe extern "C" fn drop_msg_data_box(data: *mut c_void, hint: *mut c_void) {
41    let _ = Box::from_raw(slice::from_raw_parts_mut(data as *mut u8, hint as usize));
42}
43
44impl Message {
45    unsafe fn alloc<F>(f: F) -> Message
46    where
47        F: FnOnce(&mut zmq_sys::zmq_msg_t) -> i32,
48    {
49        let mut msg = zmq_sys::zmq_msg_t::default();
50        let rc = f(&mut msg);
51        if rc == -1 {
52            panic!("{}", errno_to_error())
53        }
54        Message { msg }
55    }
56
57    /// Create an empty `Message`.
58    pub fn new() -> Message {
59        unsafe { Self::alloc(|msg| zmq_sys::zmq_msg_init(msg)) }
60    }
61
62    /// Create a `Message` preallocated with `len` uninitialized bytes.
63    ///
64    /// Since it is very easy to introduce undefined behavior using this
65    /// function, its use is not recommended, and it will be removed in a future
66    /// release. If there is a use-case that cannot be handled efficiently by
67    /// the safe message constructors, please file an issue.
68    ///
69    /// # Safety
70    ///
71    /// The returned message contains uninitialized memory, and hence the
72    /// `Deref` and `DerefMut` traits must not be used until the memory has been
73    /// initialized. Since there is no proper API to do so, this function is
74    /// basically not usable safely, unless you happen to invoke C code that
75    /// takes a raw message pointer and initializes its contents.
76    #[deprecated(
77        since = "0.9.1",
78        note = "This method has an unintuitive name, and should not be needed."
79    )]
80    pub unsafe fn with_capacity_unallocated(len: usize) -> Message {
81        Self::alloc(|msg| zmq_sys::zmq_msg_init_size(msg, len as size_t))
82    }
83
84    unsafe fn with_size_uninit(len: usize) -> Message {
85        Self::alloc(|msg| zmq_sys::zmq_msg_init_size(msg, len as size_t))
86    }
87
88    /// Create a `Message` with space for `len` bytes that are initialized to 0.
89    pub fn with_size(len: usize) -> Message {
90        unsafe {
91            let mut msg = Message::with_size_uninit(len);
92            ptr::write_bytes(msg.as_mut_ptr(), 0, len);
93            msg
94        }
95    }
96
97    /// Create a `Message` with space for `len` bytes that are initialized to 0.
98    #[deprecated(
99        since = "0.9.1",
100        note = "This method has a name which does not match its semantics. Use `with_size` instead"
101    )]
102    pub fn with_capacity(len: usize) -> Message {
103        Self::with_size(len)
104    }
105
106    /// Create a `Message` from a `&[u8]`. This will copy `data` into the message.
107    ///
108    /// This is equivalent to using the `From<&[u8]>` trait.
109    #[deprecated(since = "0.9.1", note = "Use the `From` trait instead.")]
110    pub fn from_slice(data: &[u8]) -> Message {
111        Self::from(data)
112    }
113
114    /// Return the message content as a string slice if it is valid UTF-8.
115    pub fn as_str(&self) -> Option<&str> {
116        str::from_utf8(self).ok()
117    }
118
119    /// Return the `ZMQ_MORE` flag, which indicates if more parts of a multipart
120    /// message will follow.
121    pub fn get_more(&self) -> bool {
122        let rc = unsafe { zmq_sys::zmq_msg_more(&self.msg) };
123        rc != 0
124    }
125
126    /// Query a message metadata property.
127    ///
128    /// # Non-UTF8 values
129    ///
130    /// The `zmq_msg_gets` man page notes "The encoding of the property and
131    /// value shall be UTF8". However, this is not actually enforced. For API
132    /// compatibility reasons, this function will return `None` when
133    /// encountering a non-UTF8 value; so a missing and a non-UTF8 value cannot
134    /// currently be distinguished.
135    ///
136    /// This is considered a bug in the bindings, and will be fixed with the
137    /// next API-breaking release.
138    pub fn gets<'a>(&'a mut self, property: &str) -> Option<&'a str> {
139        let c_str = ffi::CString::new(property.as_bytes()).unwrap();
140
141        let value = unsafe { zmq_sys::zmq_msg_gets(&self.msg, c_str.as_ptr()) };
142
143        if value.is_null() {
144            None
145        } else {
146            str::from_utf8(unsafe { ffi::CStr::from_ptr(value) }.to_bytes()).ok()
147        }
148    }
149}
150
151impl Deref for Message {
152    type Target = [u8];
153
154    fn deref(&self) -> &[u8] {
155        // This is safe because we're constraining the slice to the lifetime of
156        // this message.
157        unsafe {
158            let ptr = &self.msg as *const _ as *mut _;
159            let data = zmq_sys::zmq_msg_data(ptr);
160            let len = zmq_sys::zmq_msg_size(ptr) as usize;
161            slice::from_raw_parts(data as *mut u8, len)
162        }
163    }
164}
165
166impl PartialEq for Message {
167    fn eq(&self, other: &Message) -> bool {
168        self[..] == other[..]
169    }
170}
171
172impl Eq for Message {}
173
174impl DerefMut for Message {
175    fn deref_mut(&mut self) -> &mut [u8] {
176        // This is safe because we're constraining the slice to the lifetime of
177        // this message.
178        unsafe {
179            let data = zmq_sys::zmq_msg_data(&mut self.msg);
180            let len = zmq_sys::zmq_msg_size(&self.msg) as usize;
181            slice::from_raw_parts_mut(data as *mut u8, len)
182        }
183    }
184}
185
186impl<'a> From<&'a [u8]> for Message {
187    /// Construct a message from a byte slice by copying the data.
188    fn from(data: &'a [u8]) -> Self {
189        unsafe {
190            let mut msg = Message::with_size_uninit(data.len());
191            ptr::copy_nonoverlapping(data.as_ptr(), msg.as_mut_ptr(), data.len());
192            msg
193        }
194    }
195}
196
197impl From<Vec<u8>> for Message {
198    /// Construct a message from a byte vector without copying the data.
199    fn from(msg: Vec<u8>) -> Self {
200        Message::from(msg.into_boxed_slice())
201    }
202}
203
204impl From<Box<[u8]>> for Message {
205    /// Construct a message from a boxed slice without copying the data.
206    fn from(data: Box<[u8]>) -> Self {
207        let len = data.len();
208        if len == 0 {
209            return Message::new();
210        }
211        let raw = Box::into_raw(data);
212        unsafe {
213            Self::alloc(|msg| {
214                zmq_sys::zmq_msg_init_data(
215                    msg,
216                    raw as *mut c_void,
217                    len,
218                    Some(drop_msg_data_box),
219                    len as *mut c_void,
220                )
221            })
222        }
223    }
224}
225
226impl<'a> From<&'a str> for Message {
227    /// Construct a message from a string slice by copying the UTF-8 data.
228    fn from(msg: &str) -> Self {
229        Message::from(msg.as_bytes())
230    }
231}
232
233impl<'a> From<&'a String> for Message {
234    /// Construct a message from a string slice by copying the UTF-8 data.
235    fn from(msg: &String) -> Self {
236        Message::from(msg.as_bytes())
237    }
238}
239
240impl<'a, T> From<&'a T> for Message
241where
242    T: Into<Message> + Clone,
243{
244    fn from(v: &'a T) -> Self {
245        v.clone().into()
246    }
247}
248
249/// Get the low-level C pointer.
250pub fn msg_ptr(msg: &mut Message) -> *mut zmq_sys::zmq_msg_t {
251    &mut msg.msg
252}