تمرين إعادة البناء
Deadline Planner
أعد كتابة مخطط مواعيد يرتب المهام حسب عدد الأيام المتبقية.
rust
~22 دقيقة
متوسط
أعد بناء الكود
Rebuild
هذا هو الكود. اكتبه بنفسك.
الكود المرجعي
use std::cmp::Ordering;
use std::env;
use std::fs;
use std::io;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug)]
struct Task {
name: String,
due: Date,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Date {
year: i32,
month: u32,
day: u32,
}
fn main() -> io::Result<()> {
let path = env::args()
.nth(1)
.unwrap_or_else(|| "deadlines.csv".to_string());
let data = fs::read_to_string(path).unwrap_or_else(|_| sample_deadlines());
let today = today_utc();
let mut tasks = parse_tasks(&data);
tasks.sort_by(|a, b| a.due.cmp(&b.due));
for task in tasks {
let days = days_between(today, task.due);
println!("{}: {} days", task.name, days);
}
Ok(())
}
fn parse_tasks(data: &str) -> Vec<Task> {
data.lines()
.skip(1)
.filter_map(|line| {
let (name, date) = line.split_once(',')?;
Some(Task {
name: name.trim().to_string(),
due: parse_date(date.trim())?,
})
})
.collect()
}
fn parse_date(text: &str) -> Option<Date> {
let mut parts = text.split('-');
Some(Date {
year: parts.next()?.parse().ok()?,
month: parts.next()?.parse().ok()?,
day: parts.next()?.parse().ok()?,
})
}
fn today_utc() -> Date {
let days = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64
/ 86_400;
date_from_days(days)
}
fn days_between(start: Date, end: Date) -> i64 {
days_from_date(end) - days_from_date(start)
}
fn days_from_date(date: Date) -> i64 {
let year = date.year - (date.month <= 2) as i32;
let era = (if year >= 0 { year } else { year - 399 }) / 400;
let year_of_era = year - era * 400;
let month = date.month as i32;
let day_of_year = (153 * (month + if month > 2 { -3 } else { 9 }) + 2) / 5 + date.day as i32 - 1;
let day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year;
(era * 146_097 + day_of_era - 719_468) as i64
}
fn date_from_days(days: i64) -> Date {
let days = days + 719_468;
let era = (if days >= 0 { days } else { days - 146_096 }) / 146_097;
let day_of_era = days - era * 146_097;
let year_of_era = (day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
let mut year = year_of_era as i32 + era as i32 * 400;
let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
let month_piece = (5 * day_of_year + 2) / 153;
let day = day_of_year - (153 * month_piece + 2) / 5 + 1;
let month = month_piece + if month_piece < 10 { 3 } else { -9 };
year += (month <= 2) as i32;
Date {
year,
month: month as u32,
day: day as u32,
}
}
impl Ord for Date {
fn cmp(&self, other: &Self) -> Ordering {
(self.year, self.month, self.day).cmp(&(other.year, other.month, other.day))
}
}
impl PartialOrd for Date {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
fn sample_deadlines() -> String {
"name,due\nRenew license,2026-05-10\nQuarterly report,2026-04-30\nTeam review,2026-05-03\n".to_string()
}اكتب هنا