3.1 - פריסת זיכרון ותקפות ערכים - פתרון
פתרון מעבר מבייטים לערך מאומת¶
הפענוח מעתיק ארבעה בייטים למערך קטן וממיר אותו למספר. אין בו הפניה לא מיושרת, וגם אין קריאה מבייטי ריפוד של מבנה.
#[derive(Debug, PartialEq)]
struct Header { kind: u8, length: u32 }
fn encode(header: &Header) -> [u8; 5] {
let mut bytes = [0u8; 5];
bytes[0] = header.kind;
bytes[1..].copy_from_slice(&header.length.to_le_bytes());
bytes
}
fn decode(bytes: &[u8]) -> Option<Header> {
if bytes.len() != 5 || !matches!(bytes[0], 1 | 2) { return None; }
let length = u32::from_le_bytes(bytes[1..5].try_into().ok()?);
Some(Header { kind: bytes[0], length })
}
fn main() {
let header = Header { kind: 2, length: 1234 };
assert_eq!(decode(&encode(&header)), Some(header));
let shifted = [0, 1, 4, 3, 2, 1, 0];
assert_eq!(decode(&shifted[1..6]), Some(Header { kind: 1, length: 0x01020304 }));
assert_eq!(decode(&[3, 0, 0, 0, 0]), None);
assert_eq!(decode(&[]), None);
}
הפורמט מוגדר כחמישה בייטים, בעוד מבנה C עשוי לכלול padding. ה־Header שבפתרון הוא מודל לוגי בלבד. בשכבת API אמיתית אפשר גם להגביל את יצירת kind חוקי באמצעות enum, ולהמיר אליו רק אחרי בדיקת הקלט.