extern crate alloc;
use alloc::vec::Vec;
use crate::common_types::{ReplyHeader, RequestHeader};
use crate::error::{RpcError, RpcResult};
#[must_use]
pub fn encode_request_frame(header: &RequestHeader, user_payload: &[u8]) -> Vec<u8> {
let mut out = header.to_cdr_le();
out.extend_from_slice(user_payload);
out
}
pub fn decode_request_frame(bytes: &[u8]) -> RpcResult<(RequestHeader, &[u8])> {
let header = RequestHeader::from_cdr_le(bytes)?;
let consumed = encoded_request_header_len(&header);
if consumed > bytes.len() {
return Err(RpcError::codec("request frame truncated"));
}
Ok((header, &bytes[consumed..]))
}
#[must_use]
pub fn encode_reply_frame(header: &ReplyHeader, user_payload: &[u8]) -> Vec<u8> {
let mut out = header.to_cdr_le();
out.extend_from_slice(user_payload);
out
}
pub fn decode_reply_frame(bytes: &[u8]) -> RpcResult<(ReplyHeader, &[u8])> {
let header = ReplyHeader::from_cdr_le(bytes)?;
let consumed = encoded_reply_header_len();
if consumed > bytes.len() {
return Err(RpcError::codec("reply frame truncated"));
}
Ok((header, &bytes[consumed..]))
}
fn encoded_request_header_len(header: &RequestHeader) -> usize {
header.to_cdr_le().len()
}
fn encoded_reply_header_len() -> usize {
28
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use crate::common_types::{RemoteExceptionCode, SampleIdentity};
fn id() -> SampleIdentity {
SampleIdentity::new([0x42; 16], 7)
}
#[test]
fn request_frame_roundtrip_empty_payload() {
let h = RequestHeader::new(id(), "");
let frame = encode_request_frame(&h, &[]);
let (back, payload) = decode_request_frame(&frame).unwrap();
assert_eq!(back, h);
assert!(payload.is_empty());
}
#[test]
fn request_frame_roundtrip_with_payload() {
let h = RequestHeader::new(id(), "calc-A");
let frame = encode_request_frame(&h, &[1, 2, 3, 4]);
let (back, payload) = decode_request_frame(&frame).unwrap();
assert_eq!(back, h);
assert_eq!(payload, &[1, 2, 3, 4]);
}
#[test]
fn reply_frame_roundtrip() {
let h = ReplyHeader::new(id(), RemoteExceptionCode::Ok);
let frame = encode_reply_frame(&h, &[9, 8, 7]);
let (back, payload) = decode_reply_frame(&frame).unwrap();
assert_eq!(back, h);
assert_eq!(payload, &[9, 8, 7]);
}
#[test]
fn reply_frame_carries_exception_code() {
let h = ReplyHeader::new(id(), RemoteExceptionCode::InvalidArgument);
let frame = encode_reply_frame(&h, &[]);
let (back, _) = decode_reply_frame(&frame).unwrap();
assert_eq!(back.remote_ex, RemoteExceptionCode::InvalidArgument);
}
#[test]
fn decode_request_frame_truncated_header_is_error() {
let bytes = [0u8; 8];
assert!(decode_request_frame(&bytes).is_err());
}
#[test]
fn decode_reply_frame_truncated_is_error() {
let bytes = [0u8; 4];
assert!(decode_reply_frame(&bytes).is_err());
}
#[test]
fn reply_header_consumed_28_bytes() {
let h = ReplyHeader::new(SampleIdentity::UNKNOWN, RemoteExceptionCode::Ok);
let bytes = h.to_cdr_le();
assert_eq!(bytes.len(), 28);
}
}