# Don't use `&String` in function parameters. It has virtually no use. Instead use `&str`, since it can be implicitly converted from `&String` # Handle errors You currently happily unwrap every `character.to_digit(10)`, though this may fail if e.g. letters are provided. # Check for valid input The input should be a string of exactly 9 digits. Your code happily accepts any amount of digits, though the result of their processing will not constitute a valid ISBN. # Represent the ISBN as a struct So you can have an object that represents a valid ISBN. # Suggested: `src/lib.rs` ```rust use std::fmt::{Display, Formatter}; use std::str::FromStr; const FACTORS: [u8; 9] = [10, 9, 8, 7, 6, 5, 4, 3, 2]; pub enum Error { InvalidDigit(char), InvalidLength(usize), } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidDigit(chr) => write!(f, "Invalid digit: {chr}"), Self::InvalidLength(len) => write!(f, "Invalid length: {len}"), } } } pub struct Isbn([u8; 10]); impl Display for Isbn { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { for digit in self.0 { if digit == 10 { write!(f, "X")?; } else { write!(f, "{digit}")?; } } Ok(()) } } impl From<[u8; 9]> for Isbn { fn from(value: [u8; 9]) -> Self { Self([ value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8], calculate_checksum(&value), ]) } } impl FromStr for Isbn { type Err = Error; fn from_str(s: &str) -> Result<Self, Self::Err> { let mut digits = Vec::new(); for c in s.chars() { if let Some(digit) = c.to_digit(10).and_then(|digit| u8::try_from(digit).ok()) { digits.push(digit); } else { return Err(Error::InvalidDigit(c)); } } let array: [u8; 9] = match digits.try_into() { Ok(array) => array, Err(error) => return Err(Error::InvalidLength(error.len())), }; Ok(Self::from(array)) } } fn calculate_checksum(digits: &[u8; 9]) -> u8 { let dot_product: u32 = digits .iter() .zip(FACTORS) .map(|(&x, y)| u32::from(x) * u32::from(y)) .sum(); for checksum in 0..=10u8 { if (dot_product + u32::from(checksum)) % 11 == 0 { return checksum; } } 0 } ``` `src/main.rs` ```rust use clap::Parser; use isbn::Isbn; use std::str::FromStr; #[derive(Debug, Parser)] struct Arguments { #[arg(index = 1)] digits: String, } fn main() { let arguments = Arguments::parse(); match Isbn::from_str(arguments.digits.as_str()) { Ok(isbn) => println!("The ISBN is: {isbn}"), Err(error) => eprintln!("{error}"), } } ``` `Cargo.toml` ```toml [package] name = "isbn" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] clap = { version = "4.3.8", features = ["derive"] } ```