1#![warn(missing_docs)]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![doc = include_str!("../README.md")]
4
5#[derive(Debug)]
7pub enum FindError {
8 NotFound(Number),
10}
11
12impl core::fmt::Display for FindError {
13 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
14 match self {
15 FindError::NotFound(number) => {
16 write!(f, "The number `{}` was not found in the sequence", number)
17 }
18 }
19 }
20}
21
22#[cfg(feature = "std")]
23impl std::error::Error for FindError {}
24
25type FindResult<T> = Result<T, FindError>;
26
27pub trait IntoNumber {
31 fn into_number(self) -> Number;
33}
34
35#[cfg(feature = "big-int")]
39pub type Number = num_bigint::BigInt;
40
41#[cfg(not(feature = "big-int"))]
45pub type Number = i128;
46
47impl IntoNumber for i128 {
48 fn into_number(self) -> Number {
49 cfg_if::cfg_if! {
50 if #[cfg(feature = "big-int")] {
51 use num_bigint::ToBigInt;
52
53 self.to_bigint().unwrap()
54 } else {
55 self
56 }
57 }
58 }
59}
60
61fn update_array(numbers: &mut [Number; 2]) {
62 let old_x = &numbers[0];
63 let old_y = &numbers[1];
64 let new_y = old_x + old_y;
65 numbers[0] = old_y + 0;
67 numbers[1] = new_y;
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
72pub struct Sequence(pub Number, pub Number);
73
74impl Sequence {
75 pub fn new(sequence: impl Into<Self>) -> Self {
84 sequence.into()
85 }
86
87 pub fn fibonacci() -> Self {
99 Self::new([1, 1])
100 }
101
102 pub fn calculate(self, n: usize) -> Number {
114 let mut numbers = [self.0, self.1];
115
116 for _ in 2..n {
117 update_array(&mut numbers);
118 }
119
120 cfg_if::cfg_if! {
121 if #[cfg(feature = "big-int")] {
122 use num_bigint::ToBigInt;
123 numbers[1].to_bigint().unwrap()
124 } else {
125 numbers[1]
126 }
127 }
128 }
129
130 pub fn find(self, number: Number) -> FindResult<usize> {
143 let mut numbers = [self.0, self.1];
144
145 if number == numbers[0] {
146 return Ok(1);
147 } else if number == numbers[1] {
148 return Ok(2);
149 }
150
151 let mut n = 2;
152 loop {
153 update_array(&mut numbers);
154 n += 1;
155
156 if numbers[1] > number {
157 break Err(FindError::NotFound(number));
158 }
159
160 if numbers[1] == number {
161 break Ok(n);
162 }
163 }
164 }
165}
166
167impl From<[i128; 2]> for Sequence {
168 fn from(array: [i128; 2]) -> Sequence {
169 Sequence(array[0].into_number(), array[1].into_number())
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 cfg_if::cfg_if! {
176 if #[cfg(feature = "big-int")] {
177 use num_bigint::BigInt;
178 use std::str::FromStr;
179 }
180 }
181
182 use super::*;
183
184 #[cfg(feature = "big-int")]
186 #[test]
187 fn test_get_500th() {
188 let nth500 = BigInt::from_str("139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125").unwrap();
189
190 let fib = Sequence::fibonacci();
191
192 assert_eq!(fib.calculate(500), nth500);
193 }
194
195 #[test]
196 fn test_get_first() {
197 let first = 1.into_number();
198
199 let fib = Sequence::fibonacci();
200
201 assert_eq!(fib.calculate(1), first);
202 }
203
204 #[test]
205 fn test_get_third() {
206 let third = 2.into_number();
207
208 let fib = Sequence::fibonacci();
209
210 assert_eq!(fib.calculate(3), third);
211 }
212
213 #[test]
214 fn test_find_first() {
215 let first = 1.into_number();
216
217 let fib = Sequence::fibonacci();
218
219 assert_eq!(fib.find(first).unwrap(), 1);
220 }
221
222 #[test]
223 fn test_find_third() {
224 let third = 2.into_number();
225
226 let fib = Sequence::fibonacci();
227
228 assert_eq!(fib.find(third).unwrap(), 3);
229 }
230
231 #[test]
232 fn test_find_fifteenth() {
233 let fifteenth = 610.into_number();
234
235 let fib = Sequence::fibonacci();
236
237 assert_eq!(fib.find(fifteenth).unwrap(), 15);
238 }
239}