#[derive(Debug)] struct User { name:Vec, age:i64 } fn parse_age(s:&[u8])->Option { let n=std::str::from_utf8(s).ok()?.parse().ok()?; if (0..=150).contains(&n) {Some(n)} else {None} } fn load(text: &[u8]) -> Result, Vec> { let mut users = Vec::new(); for (number, line) in text.split(|&b| b == b'\n').enumerate() { if !line.is_empty() { users.push(parse_record(line, number + 1)?); } } Ok(users) } fn parse_record(line: &[u8], lineno: usize) -> Result> { let comma = line.iter().position(|&b| b == b',') .ok_or_else(|| format!("line {lineno}: expected name,age").into_bytes())?; let age = parse_age(&line[comma + 1..]) .ok_or_else(|| format!("line {lineno}: bad age").into_bytes())?; Ok(User { name: line[..comma].trim_ascii().to_vec(), age }) } fn main() { for input in [b"ada,36\ngrace,45".as_slice(),b"ada,36\nbroken",b"ada,invalid"] { match load(input) { Ok(users) => { assert_eq!((&users[0].name,users[0].age),(&b"ada".to_vec(),36)); println!("loaded {} users",users.len()); } Err(error) => { use std::io::Write;let mut out=std::io::stdout().lock();out.write_all(b"error: ").unwrap();out.write_all(&error).unwrap();out.write_all(b"\n").unwrap(); } } } }