#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct PosixMessageQueueFileDescriptor(mqd_t);
impl Drop for PosixMessageQueueFileDescriptor
{
#[inline(always)]
fn drop(&mut self)
{
self.0.close()
}
}
impl AsRawFd for PosixMessageQueueFileDescriptor
{
#[inline(always)]
fn as_raw_fd(&self) -> RawFd
{
self.0
}
}
impl IntoRawFd for PosixMessageQueueFileDescriptor
{
#[inline(always)]
fn into_raw_fd(self) -> RawFd
{
self.0
}
}
impl FromRawFd for PosixMessageQueueFileDescriptor
{
#[inline(always)]
unsafe fn from_raw_fd(fd: RawFd) -> Self
{
Self(fd)
}
}
impl FileDescriptor for PosixMessageQueueFileDescriptor
{
}
impl PosixMessageQueueFileDescriptor
{
#[inline(always)]
pub(crate) fn new(name: &CStr, send_or_receive: PosixMessageQueueCreateSendOrReceive, open_or_create: &OpenOrCreatePosixMessageQueue) -> Result<(Self, PosixMessageQueueConstraints), CreationError>
{
match open_or_create.invoke_mq_open(send_or_receive, name)
{
Err(error) => Err(error),
Ok(this) =>
{
let attributes = this.queue_attributes();
Ok
(
(
this,
PosixMessageQueueConstraints
{
maximum_number_of_enqueued_messages: attributes.maximum_number_of_enqueued_messages(),
maximum_message_size_in_bytes: attributes.maximum_message_size_in_bytes(),
}
)
)
}
}
}
pub(crate) fn send(&self, message_buffer: &[u8], message_priority: PosixMessagePriority) -> Result<(), StructWriteError>
{
let result = unsafe { mq_timedsend(self.0, message_buffer.as_ptr() as *const _ as *const _, message_buffer.len(), message_priority.into(), null()) };
if likely!(result == 0)
{
Ok(())
}
else if likely!(result == -1)
{
use self::StructWriteError::*;
Err
(
match errno().0
{
EAGAIN => WouldBlock,
EINTR => Interrupted,
EMSGSIZE => panic!("`msg_len` was greater than the `mq_msgsize` attribute of the message queue"),
EBADF => panic!("The descriptor specified in `mqdes` was invalid or not opened for reading"),
EINVAL => panic!("The call would have blocked, and `abs_timeout` was invalid, either because `tv_sec` was less than zero, or because `tv_nsec` was less than zero or greater than 1000 million"),
ETIMEDOUT => panic!("The call timed out before a message could be transferred"),
_ => unreachable_code(format_args!("")),
}
)
}
else
{
unreachable_code(format_args!(""));
}
}
pub(crate) fn receive(&self, message_buffer: &mut [u8]) -> Result<(usize, PosixMessagePriority), StructReadError>
{
let mut priority = unsafe_uninitialized();
let result = unsafe { mq_timedreceive(self.0, message_buffer.as_mut_ptr() as *mut _ as *mut _, message_buffer.len(), &mut priority, null()) } ;
if likely!(result >= 0)
{
Ok((result as usize, PosixMessagePriority(priority as u16)))
}
else if likely!(result == -1)
{
use self::StructReadError::*;
Err
(
match errno().0
{
EAGAIN => WouldBlock,
EINTR => Interrupted,
EMSGSIZE => panic!("`msg_len` was less than the `mq_msgsize` attribute of the message queue"),
EBADF => panic!("The descriptor specified in `mqdes` was invalid or not opened for reading"),
EINVAL => panic!("The call would have blocked, and `abs_timeout` was invalid, either because `tv_sec` was less than zero, or because `tv_nsec` was less than zero or greater than 1000 million"),
ETIMEDOUT => panic!("The call timed out before a message could be transferred"),
_ => unreachable_code(format_args!("")),
}
)
}
else
{
unreachable_code(format_args!(""));
}
}
#[inline(always)]
pub(crate) fn queue_depth(&self) -> usize
{
self.queue_attributes().queue_depth()
}
#[inline(always)]
pub(crate) fn queue_attributes(&self) -> mq_attr
{
let mut attributes = unsafe_zeroed();
let result = unsafe { mq_getattr(self.as_raw_fd(), &mut attributes) };
if likely!(result == 0)
{
attributes
}
else if likely!(result == -1)
{
match errno().0
{
EBADF => panic!("The message queue descriptor specified in `mqdes` is invalid"),
EINVAL => panic!("`newattr.mq_flags` contained set bits other than `O_NONBLOCK`"),
_ => unreachable_code(format_args!("")),
}
}
else
{
unreachable_code(format_args!(""))
}
}
pub(crate) fn guard_name(name: &CStr)
{
if cfg!(debug_assertions)
{
let bytes = name.to_bytes();
let length = bytes.len();
debug_assert!(length > 1, "name must be 2 bytes or more long (excluding the trailing NUL)");
debug_assert!(length < 256, "name must be 255 bytes or less long (excluding the trailing NUL)");
debug_assert_eq!(bytes[0], b'/', "name must start with a slash");
for byte in name.to_bytes()[ 1 .. ].iter()
{
debug_assert_ne!(byte, &b'/', "name contains more than one slash");
}
}
}
}