use core::mem::size_of;
use core::num::NonZeroU32;
use crate::buf::{Aligned, AlignedBuf};
use crate::error::{Error, ErrorKind, Result};
use crate::proto;
use crate::{Body, Endianness, Message, MessageKind, ObjectPath, Serial, Signature};
pub(crate) struct MessageRef {
pub(crate) serial: Serial,
pub(crate) message_type: proto::MessageType,
pub(crate) flags: proto::Flags,
pub(crate) headers: usize,
}
pub struct RecvBuf {
buf: AlignedBuf,
endianness: Endianness,
last_message: Option<MessageRef>,
}
impl RecvBuf {
pub fn new() -> Self {
Self {
buf: AlignedBuf::new(),
endianness: Endianness::NATIVE,
last_message: None,
}
}
#[inline]
pub(crate) fn buf(&self) -> &AlignedBuf {
&self.buf
}
#[inline]
pub(crate) fn buf_mut(&mut self) -> &mut AlignedBuf {
&mut self.buf
}
#[inline]
pub(crate) fn set_last_message(&mut self, message_ref: MessageRef) {
self.last_message = Some(message_ref);
}
pub(crate) fn set_endianness(&mut self, endianness: Endianness) {
self.endianness = endianness;
}
pub fn clear(&mut self) {
self.buf.clear();
self.last_message = None;
}
pub fn has_message(&self) -> bool {
self.last_message.is_some()
}
pub fn last_message(&self) -> Result<Message<'_>> {
let Some(message_ref) = &self.last_message else {
return Err(Error::new(ErrorKind::MissingMessage));
};
last_message(message_ref, self.buf.as_aligned(), self.endianness)
}
}
fn last_message<'a>(
message_ref: &MessageRef,
mut buf: Aligned<'a>,
endianness: Endianness,
) -> Result<Message<'a>> {
let MessageRef {
serial,
message_type,
flags,
headers,
} = *message_ref;
buf.advance(size_of::<proto::Header>() + size_of::<u32>())?;
let mut path = None;
let mut interface = None;
let mut member = None;
let mut error_name = None;
let mut reply_serial = None;
let mut destination = None;
let mut signature = Signature::empty();
let mut sender = None;
let mut buf = Body::from_raw_parts(buf, endianness, Signature::empty());
let mut st = buf.read_until(headers);
while !st.is_empty() {
st.align::<u64>()?;
let variant = st.load::<proto::Variant>()?;
let sig = st.read::<Signature>()?;
match (variant, sig.as_bytes()) {
(proto::Variant::PATH, b"o") => {
path = Some(st.read::<ObjectPath>()?);
}
(proto::Variant::INTERFACE, b"s") => {
interface = Some(st.read::<str>()?);
}
(proto::Variant::MEMBER, b"s") => {
member = Some(st.read::<str>()?);
}
(proto::Variant::ERROR_NAME, b"s") => {
error_name = Some(st.read::<str>()?);
}
(proto::Variant::REPLY_SERIAL, b"u") => {
let number = st.load::<u32>()?;
let number =
Serial::new(NonZeroU32::new(number).ok_or(ErrorKind::ZeroReplySerial)?);
reply_serial = Some(number);
}
(proto::Variant::DESTINATION, b"s") => {
destination = Some(st.read::<str>()?);
}
(proto::Variant::SIGNATURE, b"g") => {
signature = st.read::<Signature>()?;
}
(proto::Variant::SENDER, b"s") => {
sender = Some(st.read::<str>()?);
}
(_, _) => {
crate::signature::skip(sig, &mut st)?;
}
}
}
buf.align::<u64>()?;
let kind = match message_type {
proto::MessageType::METHOD_CALL => {
let Some(path) = path else {
return Err(Error::new(ErrorKind::MissingPath));
};
let Some(member) = member else {
return Err(Error::new(ErrorKind::MissingMember));
};
MessageKind::MethodCall { path, member }
}
proto::MessageType::METHOD_RETURN => {
let Some(reply_serial) = reply_serial else {
return Err(Error::new(ErrorKind::MissingReplySerial));
};
MessageKind::MethodReturn { reply_serial }
}
proto::MessageType::ERROR => {
let Some(error_name) = error_name else {
return Err(Error::new(ErrorKind::MissingErrorName));
};
let Some(reply_serial) = reply_serial else {
return Err(Error::new(ErrorKind::MissingReplySerial));
};
MessageKind::Error {
error_name,
reply_serial,
}
}
proto::MessageType::SIGNAL => {
let Some(path) = path else {
return Err(Error::new(ErrorKind::MissingPath));
};
let Some(member) = member else {
return Err(Error::new(ErrorKind::MissingMember));
};
MessageKind::Signal { path, member }
}
_ => return Err(Error::new(ErrorKind::InvalidProtocol)),
};
Ok(Message {
kind,
serial,
flags,
interface,
destination,
sender,
body: buf.with_signature(signature),
})
}
impl Default for RecvBuf {
#[inline]
fn default() -> Self {
Self::new()
}
}