Skip to main content

mpeg_ps/
system_header.rs

1//! System Header — ISO/IEC 13818-1 §2.5.3.5, Table 2-40.
2//!
3//! The (optional) system header follows immediately after the pack header
4//! stuffing bytes, in the first pack of the stream. It constrains the P-STD
5//! model: `rate_bound`, `audio_bound`/`video_bound`, and per-stream P-STD
6//! buffer-size bounds.
7
8use alloc::vec::Vec;
9
10use crate::error::{Error, Result};
11use broadcast_common::{Parse, Serialize};
12
13/// `system_header_start_code` — `0x000001BB`.
14pub const SYSTEM_HEADER_START_CODE: u32 = 0x0000_01BB;
15
16/// `stream_id` value that triggers the extension (extended_stream_id) form.
17const EXT_STREAM_ID: u8 = 0xB7;
18
19/// Fixed bytes before the stream loop: start_code(4) + header_length(2).
20pub(crate) const PREFIX_LEN: usize = 6;
21/// Mask of the 7 `reserved_bits` below `packet_rate_restriction_flag` (Table 2-40).
22const RESERVED_BITS_MASK: u8 = 0x7F;
23
24/// A per-stream P-STD buffer bound entry.
25#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize))]
27pub struct StdBufferBound {
28    /// The stream's `stream_id` (ISO/IEC 13818-1 Table 2-22).
29    pub stream_id: u8,
30    /// If `stream_id == 0xB7`, this is the extended `stream_id_extension` field.
31    /// Otherwise `None`.
32    pub stream_id_extension: Option<u8>,
33    /// `P-STD_buffer_bound_scale`: `false` = 128 bytes, `true` = 1024 bytes.
34    pub buffer_bound_scale: bool,
35    /// `P-STD_buffer_size_bound` in units of `buffer_bound_scale`.
36    pub buffer_size_bound: u16,
37}
38
39/// A parsed system header.
40#[derive(Debug, Clone, PartialEq, Eq)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize))]
42pub struct SystemHeader {
43    /// Upper bound on `program_mux_rate` across all packs (22-bit, 50 B/s units).
44    pub rate_bound: u32,
45    /// Upper bound on simultaneously-active audio streams (6-bit).
46    pub audio_bound: u8,
47    /// Fixed / variable bitrate indicator.
48    pub fixed_flag: bool,
49    /// Constrained system parameters flag.
50    pub csps_flag: bool,
51    /// System audio lock flag.
52    pub system_audio_lock_flag: bool,
53    /// System video lock flag.
54    pub system_video_lock_flag: bool,
55    /// Upper bound on simultaneously-active video streams (5-bit).
56    pub video_bound: u8,
57    /// Packet rate restriction flag.
58    pub packet_rate_restriction_flag: bool,
59    /// The 7 `reserved_bits` after `packet_rate_restriction_flag`
60    /// (Table 2-40), preserved so a header whose encoder wrote something
61    /// other than the conventional all-ones (`0x7F`) re-serializes
62    /// byte-identically (audit r14-MPS-W8).
63    pub reserved_bits: u8,
64    /// Per-stream P-STD buffer bounds (the `while (nextbits() == '1')` loop).
65    pub std_buffer_bounds: Vec<StdBufferBound>,
66}
67
68/// Bytes the stream loop occupies. Accumulated in `usize` (#1129): the
69/// previous `u16` accumulator overflowed for more than 10 921
70/// caller-constructed bounds, wrapping `header_length` and `serialized_len()`
71/// together so they stayed mutually consistent but both silently wrong,
72/// which then indexed past the (too-small) allocated buffer in
73/// `serialize_into`. `serialize_into` separately validates that this fits
74/// the 16-bit `header_length` wire field before writing it.
75fn stream_loop_len(system_header: &SystemHeader) -> usize {
76    let mut len: usize = 0;
77    for b in &system_header.std_buffer_bounds {
78        if b.stream_id_extension.is_some() {
79            len += 6;
80        } else {
81            len += 3;
82        }
83    }
84    len
85}
86
87impl<'a> Parse<'a> for SystemHeader {
88    type Error = Error;
89
90    fn parse(b: &'a [u8]) -> Result<Self> {
91        if b.len() < PREFIX_LEN {
92            return Err(Error::BufferTooShort {
93                need: PREFIX_LEN,
94                have: b.len(),
95                what: "system_header prefix",
96            });
97        }
98
99        if u32::from_be_bytes([b[0], b[1], b[2], b[3]]) != SYSTEM_HEADER_START_CODE {
100            return Err(Error::BadSystemHeaderStartCode(u32::from_be_bytes([
101                b[0], b[1], b[2], b[3],
102            ])));
103        }
104
105        let header_length = u16::from_be_bytes([b[4], b[5]]) as usize;
106        let body_end = PREFIX_LEN + header_length;
107        if b.len() < body_end {
108            return Err(Error::HeaderLengthOverflow {
109                header_length,
110                available: b.len().saturating_sub(PREFIX_LEN),
111            });
112        }
113        let body = &b[PREFIX_LEN..body_end];
114
115        // Wire layout (Table 2-40, after header_length):
116        // byte 0: marker(1)  | rate_bound[21:15](7)
117        // byte 1: rate_bound[14:7](8)
118        // byte 2: rate_bound[6:0](7) | marker(1)
119        // byte 3: audio_bound[5:0](6) | fixed_flag(1) | CSPS_flag(1)
120        // byte 4: system_audio_lock_flag(1) | system_video_lock_flag(1) | marker(1) | video_bound[4:0](5)
121        // byte 5: packet_rate_restriction_flag(1) | reserved(7)
122
123        if body.len() < 6 {
124            return Err(Error::BufferTooShort {
125                need: 6 + PREFIX_LEN,
126                have: b.len(),
127                what: "system_header fixed body",
128            });
129        }
130
131        // Marker bit checks
132        if body[0] & 0x80 == 0 {
133            return Err(Error::BadMarker("system_header rate_bound marker 1"));
134        }
135        if body[2] & 0x01 == 0 {
136            return Err(Error::BadMarker("system_header rate_bound marker 2"));
137        }
138        if body[4] & 0x20 == 0 {
139            return Err(Error::BadMarker("system_header video_bound marker"));
140        }
141
142        // rate_bound: 22 bits
143        let rate_bound = ((u32::from(body[0] & 0x7F) << 15)
144            | (u32::from(body[1]) << 7)
145            | u32::from(body[2] >> 1))
146            & 0x3F_FFFF;
147
148        // byte 3: audio_bound(6) | fixed_flag(1) | CSPS_flag(1)
149        let audio_bound = (body[3] >> 2) & 0x3F;
150        let fixed_flag = body[3] & 0x02 != 0;
151        let csps_flag = body[3] & 0x01 != 0;
152
153        // byte 4: system_audio_lock_flag(1) | system_video_lock_flag(1) | marker(1) | video_bound[4:0](5)
154        let system_audio_lock_flag = body[4] & 0x80 != 0;
155        let system_video_lock_flag = body[4] & 0x40 != 0;
156        // W1 (#1119): `video_bound` is the low 5 bits of byte 4, not 4 —
157        // `& 0x0F` dropped bit 4, so `video_bound` in 16..=31 round-tripped
158        // to `video_bound - 16` (serialize already used the correct `0x1F`,
159        // Table 2-40).
160        let video_bound = body[4] & 0x1F;
161
162        // byte 5: packet_rate_restriction_flag(1) | reserved(7)
163        let packet_rate_restriction_flag = body[5] & 0x80 != 0;
164        let reserved_bits = body[5] & RESERVED_BITS_MASK;
165
166        // Stream loop — each entry starts with MSB=1 (nextbits()=='1')
167        let mut pos = 6;
168        let mut std_buffer_bounds = Vec::new();
169        while pos < body.len() && body[pos] & 0x80 != 0 {
170            let stream_id = body[pos];
171            if stream_id == EXT_STREAM_ID {
172                // Extension form (6 bytes)
173                if pos + 6 > body.len() {
174                    return Err(Error::BufferTooShort {
175                        need: pos + 6,
176                        have: body.len(),
177                        what: "system_header extended stream entry",
178                    });
179                }
180                // byte pos+1: '11' + '000000'(6 bits)
181                if body[pos + 1] & 0xC0 != 0xC0 {
182                    return Err(Error::BadStreamIdExtensionPrefix(body[pos + 1]));
183                }
184                // byte pos+2: '0'(1) + stream_id_extension(7)
185                let stream_id_extension = body[pos + 2] & 0x7F;
186                // byte pos+3: '1011 0110'
187                if body[pos + 3] != 0xB6 {
188                    return Err(Error::BadStreamIdExtensionPrefix(body[pos + 3]));
189                }
190                // byte pos+4: '11' + scale(1) + size[12:7](5)
191                if body[pos + 4] & 0xC0 != 0xC0 {
192                    return Err(Error::BadMarker("P-STD_buffer_bound_scale prefix (ext)"));
193                }
194                let buffer_bound_scale = body[pos + 4] & 0x20 != 0;
195                // bytes pos+4/pos+5: '11'(2) | scale(1) | size[12:8](5), then size[7:0](8):
196                // the 13-bit size has no trailing marker bit (Table 2-40).
197                let buffer_size_bound =
198                    (u16::from(body[pos + 4] & 0x1F) << 8) | u16::from(body[pos + 5]);
199                std_buffer_bounds.push(StdBufferBound {
200                    stream_id,
201                    stream_id_extension: Some(stream_id_extension),
202                    buffer_bound_scale,
203                    buffer_size_bound,
204                });
205                pos += 6;
206            } else {
207                // Normal form (3 bytes)
208                if pos + 3 > body.len() {
209                    return Err(Error::BufferTooShort {
210                        need: pos + 3,
211                        have: body.len(),
212                        what: "system_header stream entry",
213                    });
214                }
215                // byte pos+1: '11' + scale(1) + size[12:7](5)
216                if body[pos + 1] & 0xC0 != 0xC0 {
217                    return Err(Error::BadMarker("P-STD_buffer_bound_scale prefix"));
218                }
219                let buffer_bound_scale = body[pos + 1] & 0x20 != 0;
220                // bytes pos+1/pos+2: '11'(2) | scale(1) | size[12:8](5), then size[7:0](8).
221                let buffer_size_bound =
222                    (u16::from(body[pos + 1] & 0x1F) << 8) | u16::from(body[pos + 2]);
223                std_buffer_bounds.push(StdBufferBound {
224                    stream_id,
225                    stream_id_extension: None,
226                    buffer_bound_scale,
227                    buffer_size_bound,
228                });
229                pos += 3;
230            }
231        }
232
233        Ok(SystemHeader {
234            rate_bound,
235            audio_bound,
236            fixed_flag,
237            csps_flag,
238            system_audio_lock_flag,
239            system_video_lock_flag,
240            video_bound,
241            packet_rate_restriction_flag,
242            reserved_bits,
243            std_buffer_bounds,
244        })
245    }
246}
247
248impl Serialize for SystemHeader {
249    type Error = Error;
250
251    fn serialized_len(&self) -> usize {
252        PREFIX_LEN + 6 + stream_loop_len(self)
253    }
254
255    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
256        let total = self.serialized_len();
257        if buf.len() < total {
258            return Err(Error::BufferTooShort {
259                need: total,
260                have: buf.len(),
261                what: "system_header serialize output",
262            });
263        }
264
265        // system_header_start_code
266        buf[0..4].copy_from_slice(&SYSTEM_HEADER_START_CODE.to_be_bytes());
267
268        // header_length (bytes after this field)
269        let header_length = broadcast_common::len::fit_u16(
270            6 + stream_loop_len(self),
271            "system_header.header_length",
272        )?;
273        buf[4..6].copy_from_slice(&header_length.to_be_bytes());
274
275        let rate_bound = self.rate_bound & 0x3F_FFFF;
276        // byte 6: marker(1) | rate_bound[21:15](7)
277        buf[6] = 0x80 | ((rate_bound >> 15) & 0x7F) as u8;
278        // byte 7: rate_bound[14:7]
279        buf[7] = ((rate_bound >> 7) & 0xFF) as u8;
280        // byte 8: rate_bound[6:0](7) | marker(1)
281        buf[8] = (((rate_bound & 0x7F) as u8) << 1) | 0x01;
282        // byte 9: audio_bound[5:0](6) | fixed_flag(1) | CSPS_flag(1)
283        buf[9] = (self.audio_bound & 0x3F) << 2
284            | (u8::from(self.fixed_flag) << 1)
285            | u8::from(self.csps_flag);
286        // byte 10: system_audio_lock_flag(1) | system_video_lock_flag(1) | marker(1) | video_bound[4:0](5)
287        buf[10] = (u8::from(self.system_audio_lock_flag) << 7)
288            | (u8::from(self.system_video_lock_flag) << 6)
289            | 0x20 // marker_bit (bit5 of byte 10)
290            | (self.video_bound & 0x1F);
291        // byte 11: packet_rate_restriction_flag(1) | reserved(7)
292        buf[11] = (u8::from(self.packet_rate_restriction_flag) << 7)
293            | (self.reserved_bits & RESERVED_BITS_MASK);
294
295        // Stream loop
296        let mut pos = 12;
297        for bound in &self.std_buffer_bounds {
298            if let Some(ext) = bound.stream_id_extension {
299                buf[pos] = bound.stream_id;
300                buf[pos + 1] = 0xC0;
301                buf[pos + 2] = ext & 0x7F;
302                buf[pos + 3] = 0xB6;
303                buf[pos + 4] = 0xC0
304                    | (u8::from(bound.buffer_bound_scale) << 5)
305                    | ((bound.buffer_size_bound >> 8) & 0x1F) as u8;
306                buf[pos + 5] = (bound.buffer_size_bound & 0xFF) as u8;
307                pos += 6;
308            } else {
309                buf[pos] = bound.stream_id;
310                buf[pos + 1] = 0xC0
311                    | (u8::from(bound.buffer_bound_scale) << 5)
312                    | ((bound.buffer_size_bound >> 8) & 0x1F) as u8;
313                buf[pos + 2] = (bound.buffer_size_bound & 0xFF) as u8;
314                pos += 3;
315            }
316        }
317
318        Ok(total)
319    }
320}
321
322#[cfg(test)]
323mod tests {
324    use super::*;
325    use alloc::vec;
326
327    #[test]
328    fn system_header_round_trip_no_streams() {
329        let bytes = vec![
330            0x00, 0x00, 0x01, 0xBB, // start_code
331            0x00, 0x06, // header_length = 6 (just the fixed part)
332            0x80, 0x00, 0x01, // rate_bound=0, markers
333            0x04, // audio_bound=1, fixed=0, CSPS=0
334            0x20, // audio_lock=0, video_lock=0, marker=1, video_bound=0
335            0xFF, // packet_rate=1, reserved=0x7F
336        ];
337        let h = SystemHeader::parse(&bytes).unwrap();
338        assert_eq!(h.rate_bound, 0);
339        assert_eq!(h.audio_bound, 1);
340        assert!(!h.fixed_flag);
341        assert!(!h.csps_flag);
342        assert!(!h.system_audio_lock_flag);
343        assert!(!h.system_video_lock_flag);
344        assert_eq!(h.video_bound, 0);
345        assert!(h.packet_rate_restriction_flag);
346        assert!(h.std_buffer_bounds.is_empty());
347
348        let mut out = vec![0u8; h.serialized_len()];
349        h.serialize_into(&mut out).unwrap();
350        assert_eq!(&out[..], &bytes[..]);
351
352        let h2 = SystemHeader::parse(&out).unwrap();
353        assert_eq!(h, h2);
354    }
355
356    /// W1 (#1119): `video_bound` (byte 4 bits `[4:0]`, Table 2-40) was
357    /// masked with `0x0F` (4 bits) on parse but `0x1F` (5 bits) on
358    /// serialize. `video_bound` in `16..=31` sets bit 4, which the old
359    /// parse dropped — `video_bound - 16` came back instead.
360    #[test]
361    fn video_bound_bit_4_round_trips() {
362        let bytes = vec![
363            0x00,
364            0x00,
365            0x01,
366            0xBB, // start_code
367            0x00,
368            0x06, // header_length = 6
369            0x80,
370            0x00,
371            0x01,        // rate_bound=0, markers
372            0x04,        // audio_bound=1, fixed=0, CSPS=0
373            0x20 | 0x1F, // audio_lock=0, video_lock=0, marker=1, video_bound=31 (bit 4 set)
374            0xFF,
375        ];
376        let h = SystemHeader::parse(&bytes).unwrap();
377        assert_eq!(
378            h.video_bound, 31,
379            "bit 4 of video_bound must not be dropped"
380        );
381
382        let mut out = vec![0u8; h.serialized_len()];
383        h.serialize_into(&mut out).unwrap();
384        assert_eq!(&out[..], &bytes[..]);
385    }
386
387    #[test]
388    fn system_header_round_trip_with_streams() {
389        let bytes = vec![
390            0x00, 0x00, 0x01, 0xBB, 0x00,
391            0x0C, // header_length = 12 (6 fixed + 6 for 2 streams)
392            0x80, 0x00, 0x01, 0x04, 0x20, 0xFF,
393            // stream 1: stream_id=0xE0, scale=1, size=0x1FFF
394            0xE0, 0xFF, 0xFF, // stream 2: stream_id=0xC0, scale=0, size=0x0100
395            0xC0, 0xC1, 0x00,
396        ];
397        let h = SystemHeader::parse(&bytes).unwrap();
398        assert_eq!(h.std_buffer_bounds.len(), 2);
399        assert_eq!(h.std_buffer_bounds[0].stream_id, 0xE0);
400        assert!(h.std_buffer_bounds[0].stream_id_extension.is_none());
401        assert!(h.std_buffer_bounds[0].buffer_bound_scale);
402        assert_eq!(h.std_buffer_bounds[0].buffer_size_bound, 0x1FFF);
403
404        assert_eq!(h.std_buffer_bounds[1].stream_id, 0xC0);
405        assert!(h.std_buffer_bounds[1].stream_id_extension.is_none());
406        assert!(!h.std_buffer_bounds[1].buffer_bound_scale);
407        assert_eq!(h.std_buffer_bounds[1].buffer_size_bound, 0x0100);
408
409        let mut out = vec![0u8; h.serialized_len()];
410        h.serialize_into(&mut out).unwrap();
411        assert_eq!(&out[..], &bytes[..]);
412
413        let h2 = SystemHeader::parse(&out).unwrap();
414        assert_eq!(h, h2);
415
416        // Mutation test
417        let h_mut = SystemHeader {
418            rate_bound: 12345,
419            ..h.clone()
420        };
421        let mut out2 = vec![0u8; h_mut.serialized_len()];
422        h_mut.serialize_into(&mut out2).unwrap();
423        assert_ne!(&out[..], &out2[..]);
424    }
425
426    /// r14-MPS-W8: an encoder that wrote `reserved_bits` other than the
427    /// conventional `0x7F` must re-serialize byte-identically.
428    #[test]
429    fn non_conventional_reserved_bits_round_trip() {
430        let bytes = vec![
431            0x00, 0x00, 0x01, 0xBB, // start_code
432            0x00, 0x06, // header_length
433            0x80, 0x00, 0x01, // rate_bound=0, markers
434            0x04, // audio_bound=1
435            0x20, // marker=1, video_bound=0
436            0x2A, // packet_rate=0, reserved_bits=0b010_1010
437        ];
438        let h = SystemHeader::parse(&bytes).unwrap();
439        assert_eq!(h.reserved_bits, 0x2A);
440        assert!(!h.packet_rate_restriction_flag);
441        let mut out = vec![0u8; h.serialized_len()];
442        h.serialize_into(&mut out).unwrap();
443        assert_eq!(out, bytes);
444    }
445
446    /// MPS-W7 (#1129): `stream_loop_len` accumulated in `u16`, overflowing
447    /// (debug panic / release wrap) for more than 10 921 extension-form
448    /// bounds (6 bytes each: true total 66 006 bytes > `u16::MAX`). The old
449    /// accumulator's overflow point is the same 65 535 boundary the wire
450    /// field itself has, so the only fixable difference is *how* an
451    /// over-limit count fails: the old code panicked (arithmetic overflow in
452    /// debug; an out-of-bounds buffer write in release, because
453    /// `serialized_len()` used the same wrapped, too-small value the loop
454    /// then wrote past). The fix must return a controlled `Err` here
455    /// instead — never panic. Confirmed pre-fix: this exact case panicked
456    /// with "attempt to add with overflow".
457    #[test]
458    fn many_bounds_past_old_u16_overflow_point_errs_not_panics() {
459        let std_buffer_bounds = (0..11_000)
460            .map(|_| StdBufferBound {
461                stream_id: EXT_STREAM_ID,
462                stream_id_extension: Some(0x05),
463                buffer_bound_scale: false,
464                buffer_size_bound: 0,
465            })
466            .collect::<Vec<_>>();
467        let h = SystemHeader {
468            rate_bound: 0,
469            audio_bound: 0,
470            fixed_flag: false,
471            csps_flag: false,
472            system_audio_lock_flag: false,
473            system_video_lock_flag: false,
474            video_bound: 0,
475            packet_rate_restriction_flag: false,
476            reserved_bits: RESERVED_BITS_MASK,
477            std_buffer_bounds,
478        };
479        // Must not panic building the (correctly-sized-in-usize) buffer or
480        // writing into it; the real total exceeds u16::MAX so this is a
481        // controlled Err, not a silently wrapped Ok.
482        let mut buf = vec![0u8; h.serialized_len()];
483        assert!(h.serialize_into(&mut buf).is_err());
484    }
485
486    /// A bound count whose real `header_length` exceeds the 16-bit wire
487    /// field (`6 + 25_000*3 = 75_006 > 65_535`) must error rather than wrap.
488    #[test]
489    fn header_length_over_u16_is_rejected_not_wrapped() {
490        let std_buffer_bounds = (0..25_000)
491            .map(|_| StdBufferBound {
492                stream_id: 0xC0,
493                stream_id_extension: None,
494                buffer_bound_scale: false,
495                buffer_size_bound: 0,
496            })
497            .collect::<Vec<_>>();
498        let h = SystemHeader {
499            rate_bound: 0,
500            audio_bound: 0,
501            fixed_flag: false,
502            csps_flag: false,
503            system_audio_lock_flag: false,
504            system_video_lock_flag: false,
505            video_bound: 0,
506            packet_rate_restriction_flag: false,
507            reserved_bits: RESERVED_BITS_MASK,
508            std_buffer_bounds,
509        };
510        let mut buf = vec![0u8; h.serialized_len()];
511        assert!(h.serialize_into(&mut buf).is_err());
512    }
513
514    /// The boundary: a bound count whose `header_length` still fits u16
515    /// serializes and round-trips.
516    #[test]
517    fn many_bounds_within_u16_header_length_round_trips() {
518        let std_buffer_bounds = (0..1000)
519            .map(|_| StdBufferBound {
520                stream_id: 0xC0,
521                stream_id_extension: None,
522                buffer_bound_scale: false,
523                buffer_size_bound: 0x0100,
524            })
525            .collect::<Vec<_>>();
526        let h = SystemHeader {
527            rate_bound: 0,
528            audio_bound: 0,
529            fixed_flag: false,
530            csps_flag: false,
531            system_audio_lock_flag: false,
532            system_video_lock_flag: false,
533            video_bound: 0,
534            packet_rate_restriction_flag: false,
535            reserved_bits: RESERVED_BITS_MASK,
536            std_buffer_bounds,
537        };
538        let mut buf = vec![0u8; h.serialized_len()];
539        h.serialize_into(&mut buf).unwrap();
540        let back = SystemHeader::parse(&buf).unwrap();
541        assert_eq!(back.std_buffer_bounds.len(), 1000);
542    }
543
544    #[test]
545    fn system_header_round_trip_extended_stream_id() {
546        let bytes = vec![
547            0x00, 0x00, 0x01, 0xBB, 0x00, 0x0C, // header_length = 12
548            0x80, 0x00, 0x01, 0x04, 0x20, 0xFF,
549            // extended stream: stream_id=0xB7, ext=0x05, scale=1, size=0x0100
550            0xB7, 0xC0, 0x05, 0xB6, 0xE1, 0x00,
551        ];
552        let h = SystemHeader::parse(&bytes).unwrap();
553        assert_eq!(h.std_buffer_bounds.len(), 1);
554        assert_eq!(h.std_buffer_bounds[0].stream_id, 0xB7);
555        assert_eq!(h.std_buffer_bounds[0].stream_id_extension, Some(0x05));
556        assert!(h.std_buffer_bounds[0].buffer_bound_scale);
557        assert_eq!(h.std_buffer_bounds[0].buffer_size_bound, 0x100);
558
559        let mut out = vec![0u8; h.serialized_len()];
560        h.serialize_into(&mut out).unwrap();
561        assert_eq!(&out[..], &bytes[..]);
562    }
563}