1.2 - טיפוסים מספריים וזרימת ערכים בתוכנית - פתרון
פתרון בדיקת גודל בשלבים¶
נבחר לדחות רשומה ברוחב אפס, משום שבפורמט שלנו לכל רשומה חייב להיות ייצוג. נבצע את החשבון בטיפוס שמייצג את שדות הכותרת, ונבדוק גם את ההמרה ליעד.
fn message_size(count: u32, record_size: u32) -> Option<usize> {
if record_size == 0 {
return None;
}
let payload = count.checked_mul(record_size)?;
let total = payload.checked_add(16)?;
let total = usize::try_from(total).ok()?;
if total > 1024 * 1024 {
return None;
}
Some(total)
}
#[cfg(test)]
mod tests {
use super::message_size;
#[test]
fn sizes() {
assert_eq!(message_size(0, 8), Some(16));
assert_eq!(message_size(10, 8), Some(96));
assert_eq!(message_size(1, 1024 * 1024 - 16), Some(1024 * 1024));
assert_eq!(message_size(1, 1024 * 1024 - 15), None);
assert_eq!(message_size(u32::MAX, 2), None);
assert_eq!(message_size(1, u32::MAX), None);
assert_eq!(message_size(10, 0), None);
}
}
fn main() {
println!("{:?}", message_size(10, 8));
}
האופרטור ? על Option מחזיר מיד None כאשר החישוב נכשל. הטיפוס usize יכול להיות רחב יותר ביעד שלנו, אבל ההמרה עדיין נכתבת כחוזה מפורש. אפשר לבחור פורמט שמאפשר מכפלה רחבה יותר ולחשב ב־u64; במקרה כזה צריך להצהיר שזהו גבול הפורמט החדש ולבדוק את כל ההמרות בהתאם.
הבדיקה של החיבור חשובה בנפרד מהכפל. עבור רשומה אחת בגודל u32::MAX הכפל מצליח, אך אין מקום לכותרת. ההגבלה של מגה־בייט אינה מחליפה את בדיקת הגלישה, משום שחישוב שגלש כבר אינו מכיל את הגודל המקורי שאותו רצינו להשוות.