לדלג לתוכן

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, ולהמיר אליו רק אחרי בדיקת הקלט.