use thiserror::Error;
use crate::codec::{Decode, DecodeError, Encode, EncodeError, decode_payload, encode_payload};
use crate::frame::RawMessage;
pub trait Payload {
const OPCODE: u8;
}
pub trait Request: Payload + Encode {
type Response: Payload + Decode;
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum MessageSetError {
#[error("unknown opcode 0x{0:02x}")]
UnknownOpcode(u8),
#[error("malformed payload for opcode 0x{opcode:02x}")]
Malformed {
opcode: u8,
#[source]
source: DecodeError,
},
}
pub trait MessageSet: Sized {
fn opcode(&self) -> u8;
fn encode(self) -> Result<RawMessage, EncodeError>;
fn decode(message: &RawMessage) -> Result<Self, MessageSetError>;
}
pub fn encode_message<M>(message: &M) -> Result<RawMessage, EncodeError>
where
M: Payload + Encode,
{
Ok(RawMessage::new(M::OPCODE, encode_payload(message)?))
}
pub fn decode_message<M>(message: &RawMessage) -> Result<M, MessageSetError>
where
M: Payload + Decode,
{
if message.message_type != M::OPCODE {
return Err(MessageSetError::UnknownOpcode(message.message_type));
}
decode_payload(&message.payload).map_err(|source| MessageSetError::Malformed {
opcode: message.message_type,
source,
})
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum NoExtension {}
impl MessageSet for NoExtension {
fn opcode(&self) -> u8 {
match *self {}
}
fn encode(self) -> Result<RawMessage, EncodeError> {
match self {}
}
fn decode(message: &RawMessage) -> Result<Self, MessageSetError> {
Err(MessageSetError::UnknownOpcode(message.message_type))
}
}
impl MessageSet for RawMessage {
fn opcode(&self) -> u8 {
self.message_type
}
fn encode(self) -> Result<RawMessage, EncodeError> {
Ok(self)
}
fn decode(message: &RawMessage) -> Result<Self, MessageSetError> {
Ok(message.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_extension_never_decodes() {
let message = RawMessage::new(0x80, vec![]);
let error = NoExtension::decode(&message).unwrap_err();
assert!(matches!(error, MessageSetError::UnknownOpcode(0x80)));
}
#[test]
fn raw_message_passes_through() {
let message = RawMessage::new(0xab, vec![9, 8, 7]);
let decoded = RawMessage::decode(&message).unwrap();
assert_eq!(decoded, message);
assert_eq!(decoded.opcode(), 0xab);
let encoded = decoded.encode().unwrap();
assert_eq!(encoded, message);
}
}