Skip to main content

rust_hdf5/format/messages/
fill_value.rs

1//! Fill value message (type 0x05) — specifies default fill value for unwritten elements.
2//!
3//! Binary layout (version 3):
4//!   Byte 0: version = 3
5//!   Byte 1: space allocation time (1=early, 2=late, 3=incremental)
6//!   Byte 2: fill value write time (0=on_alloc, 1=never, 2=if_set)
7//!   Byte 3: fill value defined (0=undefined, 1=default, 2=user-defined)
8//!   [if defined == 2]: u32 LE size + size bytes of fill data
9
10use crate::format::{FormatError, FormatResult};
11
12const VERSION: u8 = 3;
13
14/// Fill value message payload.
15#[derive(Debug, Clone, PartialEq)]
16pub struct FillValueMessage {
17    /// Space allocation time: 1=early, 2=late, 3=incremental.
18    pub alloc_time: u8,
19    /// Fill value write time: 0=on alloc, 1=never, 2=if set.
20    pub fill_write_time: u8,
21    /// Fill value defined: 0=undefined, 1=default (zeros), 2=user-defined.
22    pub fill_defined: u8,
23    /// User-defined fill value data.  Present only when `fill_defined == 2`.
24    pub fill_value: Option<Vec<u8>>,
25}
26
27impl Default for FillValueMessage {
28    fn default() -> Self {
29        Self {
30            alloc_time: 2,      // late
31            fill_write_time: 0, // on alloc
32            fill_defined: 1,    // default value (zeros)
33            fill_value: None,
34        }
35    }
36}
37
38impl FillValueMessage {
39    /// A user-defined fill value.
40    pub fn with_value(data: Vec<u8>) -> Self {
41        Self {
42            alloc_time: 2,
43            fill_write_time: 0,
44            fill_defined: 2,
45            fill_value: Some(data),
46        }
47    }
48
49    /// An undefined fill value (no fill is performed).
50    pub fn undefined() -> Self {
51        Self {
52            alloc_time: 2,
53            fill_write_time: 1, // never
54            fill_defined: 0,
55            fill_value: None,
56        }
57    }
58
59    // ------------------------------------------------------------------ encode
60
61    pub fn encode(&self) -> Vec<u8> {
62        let mut buf = Vec::with_capacity(8);
63        buf.push(VERSION);
64        buf.push(self.alloc_time);
65        buf.push(self.fill_write_time);
66        buf.push(self.fill_defined);
67
68        if self.fill_defined == 2 {
69            if let Some(ref data) = self.fill_value {
70                buf.extend_from_slice(&(data.len() as u32).to_le_bytes());
71                buf.extend_from_slice(data);
72            } else {
73                buf.extend_from_slice(&0u32.to_le_bytes());
74            }
75        }
76
77        buf
78    }
79
80    // ------------------------------------------------------------------ decode
81
82    pub fn decode(buf: &[u8]) -> FormatResult<(Self, usize)> {
83        if buf.len() < 4 {
84            return Err(FormatError::BufferTooShort {
85                needed: 4,
86                available: buf.len(),
87            });
88        }
89
90        let version = buf[0];
91        if version != VERSION {
92            return Err(FormatError::InvalidVersion(version));
93        }
94
95        let alloc_time = buf[1];
96        let fill_write_time = buf[2];
97        let fill_defined = buf[3];
98
99        let mut pos = 4;
100        let fill_value = if fill_defined == 2 {
101            if buf.len() < pos + 4 {
102                return Err(FormatError::BufferTooShort {
103                    needed: pos + 4,
104                    available: buf.len(),
105                });
106            }
107            let size =
108                u32::from_le_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]) as usize;
109            pos += 4;
110            if buf.len() < pos + size {
111                return Err(FormatError::BufferTooShort {
112                    needed: pos + size,
113                    available: buf.len(),
114                });
115            }
116            let data = buf[pos..pos + size].to_vec();
117            pos += size;
118            Some(data)
119        } else {
120            None
121        };
122
123        Ok((
124            Self {
125                alloc_time,
126                fill_write_time,
127                fill_defined,
128                fill_value,
129            },
130            pos,
131        ))
132    }
133}
134
135// ======================================================================= tests
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn roundtrip_default() {
143        let msg = FillValueMessage::default();
144        let encoded = msg.encode();
145        assert_eq!(encoded.len(), 4);
146        let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
147        assert_eq!(consumed, 4);
148        assert_eq!(decoded, msg);
149    }
150
151    #[test]
152    fn roundtrip_user_defined() {
153        let msg = FillValueMessage::with_value(vec![0xDE, 0xAD, 0xBE, 0xEF]);
154        let encoded = msg.encode();
155        // 4 header + 4 size + 4 data = 12
156        assert_eq!(encoded.len(), 12);
157        let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
158        assert_eq!(consumed, 12);
159        assert_eq!(decoded, msg);
160        assert_eq!(
161            decoded.fill_value.as_ref().unwrap(),
162            &vec![0xDE, 0xAD, 0xBE, 0xEF]
163        );
164    }
165
166    #[test]
167    fn roundtrip_undefined() {
168        let msg = FillValueMessage::undefined();
169        let encoded = msg.encode();
170        assert_eq!(encoded.len(), 4);
171        let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
172        assert_eq!(consumed, 4);
173        assert_eq!(decoded, msg);
174    }
175
176    #[test]
177    fn roundtrip_empty_user_data() {
178        let msg = FillValueMessage {
179            alloc_time: 1,
180            fill_write_time: 2,
181            fill_defined: 2,
182            fill_value: Some(vec![]),
183        };
184        let encoded = msg.encode();
185        // 4 header + 4 size + 0 data = 8
186        assert_eq!(encoded.len(), 8);
187        let (decoded, consumed) = FillValueMessage::decode(&encoded).unwrap();
188        assert_eq!(consumed, 8);
189        assert_eq!(decoded, msg);
190    }
191
192    #[test]
193    fn decode_bad_version() {
194        let buf = [1u8, 2, 0, 1]; // version 1
195        let err = FillValueMessage::decode(&buf).unwrap_err();
196        match err {
197            FormatError::InvalidVersion(1) => {}
198            other => panic!("unexpected error: {:?}", other),
199        }
200    }
201
202    #[test]
203    fn decode_buffer_too_short() {
204        let buf = [3u8, 2];
205        let err = FillValueMessage::decode(&buf).unwrap_err();
206        match err {
207            FormatError::BufferTooShort { .. } => {}
208            other => panic!("unexpected error: {:?}", other),
209        }
210    }
211
212    #[test]
213    fn decode_user_defined_truncated_size() {
214        // fill_defined=2 but not enough bytes for the u32 size field
215        let buf = [3u8, 2, 0, 2, 0xFF];
216        let err = FillValueMessage::decode(&buf).unwrap_err();
217        match err {
218            FormatError::BufferTooShort { .. } => {}
219            other => panic!("unexpected error: {:?}", other),
220        }
221    }
222
223    #[test]
224    fn decode_user_defined_truncated_data() {
225        // fill_defined=2, size=4, but only 2 bytes of data
226        let buf = [3u8, 2, 0, 2, 4, 0, 0, 0, 0xAA, 0xBB];
227        let err = FillValueMessage::decode(&buf).unwrap_err();
228        match err {
229            FormatError::BufferTooShort {
230                needed: 12,
231                available: 10,
232            } => {}
233            other => panic!("unexpected error: {:?}", other),
234        }
235    }
236
237    #[test]
238    fn version_byte() {
239        let encoded = FillValueMessage::default().encode();
240        assert_eq!(encoded[0], 3);
241    }
242}