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