rust_hdf5/format/messages/
continuation.rs1use crate::format::bytes::read_le_uint as read_uint;
8use crate::format::{FormatContext, FormatError, FormatResult};
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct ContinuationMessage {
13 pub offset: u64,
15 pub length: u64,
17}
18
19impl ContinuationMessage {
20 pub fn new(offset: u64, length: u64) -> Self {
21 Self { offset, length }
22 }
23
24 pub fn encode(&self, ctx: &FormatContext) -> Vec<u8> {
27 let sa = ctx.sizeof_addr as usize;
28 let ss = ctx.sizeof_size as usize;
29 let mut buf = Vec::with_capacity(sa + ss);
30 buf.extend_from_slice(&self.offset.to_le_bytes()[..sa]);
31 buf.extend_from_slice(&self.length.to_le_bytes()[..ss]);
32 buf
33 }
34
35 pub fn decode(buf: &[u8], ctx: &FormatContext) -> FormatResult<(Self, usize)> {
38 let sa = ctx.sizeof_addr as usize;
39 let ss = ctx.sizeof_size as usize;
40 let needed = sa + ss;
41 if buf.len() < needed {
42 return Err(FormatError::BufferTooShort {
43 needed,
44 available: buf.len(),
45 });
46 }
47
48 let offset = read_uint(&buf[0..], sa);
49 let length = read_uint(&buf[sa..], ss);
50
51 Ok((Self { offset, length }, needed))
52 }
53}
54
55#[cfg(test)]
58mod tests {
59 use super::*;
60
61 fn ctx8() -> FormatContext {
62 FormatContext {
63 sizeof_addr: 8,
64 sizeof_size: 8,
65 }
66 }
67
68 fn ctx4() -> FormatContext {
69 FormatContext {
70 sizeof_addr: 4,
71 sizeof_size: 4,
72 }
73 }
74
75 #[test]
76 fn roundtrip_ctx8() {
77 let msg = ContinuationMessage::new(0x1000, 256);
78 let encoded = msg.encode(&ctx8());
79 assert_eq!(encoded.len(), 16);
80 let (decoded, consumed) = ContinuationMessage::decode(&encoded, &ctx8()).unwrap();
81 assert_eq!(consumed, 16);
82 assert_eq!(decoded, msg);
83 }
84
85 #[test]
86 fn roundtrip_ctx4() {
87 let msg = ContinuationMessage::new(0x800, 128);
88 let encoded = msg.encode(&ctx4());
89 assert_eq!(encoded.len(), 8);
90 let (decoded, consumed) = ContinuationMessage::decode(&encoded, &ctx4()).unwrap();
91 assert_eq!(consumed, 8);
92 assert_eq!(decoded, msg);
93 }
94
95 #[test]
96 fn roundtrip_zero() {
97 let msg = ContinuationMessage::new(0, 0);
98 let encoded = msg.encode(&ctx8());
99 let (decoded, _) = ContinuationMessage::decode(&encoded, &ctx8()).unwrap();
100 assert_eq!(decoded, msg);
101 }
102
103 #[test]
104 fn roundtrip_large_values() {
105 let msg = ContinuationMessage::new(0xDEAD_BEEF_CAFE_0000, 0x0000_FFFF_0000_1234);
106 let encoded = msg.encode(&ctx8());
107 let (decoded, _) = ContinuationMessage::decode(&encoded, &ctx8()).unwrap();
108 assert_eq!(decoded, msg);
109 }
110
111 #[test]
112 fn decode_buffer_too_short() {
113 let buf = [0u8; 4];
114 let err = ContinuationMessage::decode(&buf, &ctx8()).unwrap_err();
115 match err {
116 FormatError::BufferTooShort {
117 needed: 16,
118 available: 4,
119 } => {}
120 other => panic!("unexpected error: {:?}", other),
121 }
122 }
123
124 #[test]
125 fn decode_buffer_too_short_ctx4() {
126 let buf = [0u8; 6];
127 let err = ContinuationMessage::decode(&buf, &ctx4()).unwrap_err();
128 match err {
129 FormatError::BufferTooShort {
130 needed: 8,
131 available: 6,
132 } => {}
133 other => panic!("unexpected error: {:?}", other),
134 }
135 }
136
137 #[test]
138 fn encode_size() {
139 let msg = ContinuationMessage::new(1, 2);
140 assert_eq!(msg.encode(&ctx8()).len(), 16);
141 assert_eq!(msg.encode(&ctx4()).len(), 8);
142 }
143}