Fibonblerfi Part 2
2025-10-31
This is a refactor of the previous code example. First, I took Ross Baker’s kind advice from his reply on Mastodon. But then I went down quite a rabbit hole as I followed my “custom input type” plan.
To start I created the FibonacciNumber struct, and started implementing FromStr. I struggled to implement the Err for the Result type at first, because I was trying to combine an IntErrorKind::PosOverflow (to be returned for numbers greater than 100) and a ParseIntError. I couldn’t figure out how to limit my error enum to just the PosOverflow variant, the compiler kept telling me to use IntErrorKind. Eventually I gave up and just created my own variants. But once I had the enum it needed to be a proper std::error::Error which required implementing Debug (easy, because I could derive it) and Display (more toil but an easy enough pattern to follow).
I got momentarily distracted by the power of Display and implemented one for FibonacciNumber that gave each number the proper ordinal indicator. This was very satisfying.
Eventually I remembered the goal was FromStr and finished implementing that, returning either a Ok(FibonacciNumber) or an Err(FibonacciNumberError) in each branch.
The only nuance about using the FibonacciNumber was that I had to update my fibonacci function to borrow the number instead of moving it. I’m still learning about ownership in Rust so I’m not going to comment further on that other than to say: the compiler told me exactly what to do and I listened to it!
As previously: constructive feedback is much appreciated!
1use std::{fmt::Display, io, str::FromStr};
2
3#[derive(Debug)]
4enum FibonacciNumberError {
5 TooBigError,
6 ParseError,
7}
8impl Display for FibonacciNumberError {
9 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10 match self {
11 FibonacciNumberError::TooBigError => {
12 write!(f, "Number must be a positive integer less than 101.")
13 }
14 FibonacciNumberError::ParseError => write!(f, "Number must be a positive integer."),
15 }
16 }
17}
18impl std::error::Error for FibonacciNumberError {}
19
20struct FibonacciNumber {
21 n: u8,
22}
23impl Display for FibonacciNumber {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 if [11, 12, 13].contains(&self.n) {
26 write!(f, "{}th", self.n)
27 } else {
28 match self.n % 10 {
29 1 => write!(f, "{}st", self.n),
30 2 => write!(f, "{}nd", self.n),
31 3 => write!(f, "{}rd", self.n),
32 _ => write!(f, "{}th", self.n),
33 }
34 }
35 }
36}
37impl FromStr for FibonacciNumber {
38 type Err = FibonacciNumberError;
39 fn from_str(s: &str) -> Result<Self, Self::Err> {
40 match s.trim().parse() {
41 Ok(num) => {
42 if num > 100 {
43 Err(FibonacciNumberError::TooBigError)
44 } else {
45 Ok(FibonacciNumber { n: num })
46 }
47 }
48 Err(_) => Err(FibonacciNumberError::ParseError),
49 }
50 }
51}
52
53fn main() {
54 println!("Enter fibonacci number to generate.");
55 let n: FibonacciNumber = loop {
56 let mut string_n = String::new();
57 io::stdin()
58 .read_line(&mut string_n)
59 .expect("Failed to read number!");
60
61 match string_n.parse() {
62 Ok(num) => break num,
63 Err(e) => {
64 println!("{e}");
65 continue;
66 }
67 }
68 };
69
70 let generated = fibonacci(&n);
71 println!("The {n} fibonacci number is {generated}.")
72}
73
74fn fibonacci(fib_num: &FibonacciNumber) -> u128 {
75 match fib_num {
76 FibonacciNumber { n: 0 } => 0,
77 _ => {
78 let mut minus2: u128 = 0;
79 let mut minus1: u128 = 1;
80 let mut maybe_nth: u128 = 1;
81 let mut counter = fib_num.n;
82 while counter > 1 {
83 maybe_nth = minus2 + minus1;
84 minus2 = minus1;
85 minus1 = maybe_nth;
86 counter -= 1;
87 }
88 maybe_nth
89 }
90 }
91}
