1use lazy_static::lazy_static;
2use num_bigint::BigInt;
3use regex::Regex;
4use std::fs::File;
5use std::io::BufRead;
6use std::io::BufReader;
7use std::path::PathBuf;
8use std::str::FromStr;
9
10pub struct OEISDatabase {
12 series: Vec<Series>,
13}
14
15impl OEISDatabase {
16 pub fn series(&self) -> &Vec<Series> {
17 &self.series
18 }
19
20 pub fn from_path(path: &PathBuf) -> Result<Self, std::io::Error> {
21 let f = File::open(path);
22 match f {
23 Ok(f) => {
24 let reader = BufReader::new(f);
25 let series = reader
26 .lines()
27 .map(|s| s.unwrap())
28 .skip_while(|s| s.starts_with('#'))
29 .map(|s| Series::from_str(&s).unwrap())
30 .collect();
31
32 Ok(Self { series })
33 }
34 Err(e) => Err(e),
35 }
36 }
37}
38
39#[derive(Debug, Clone, Hash, PartialEq)]
40pub enum NumberValue {
41 InRange(i128),
42 OutOfRange(BigInt),
43}
44
45#[derive(Debug, Clone, Hash)]
47pub struct Series {
48 id: usize,
49 values: Vec<NumberValue>,
50}
51
52impl Series {
53 pub fn id(&self) -> usize {
54 self.id
55 }
56 pub fn values(&self) -> &Vec<NumberValue> {
57 &self.values
58 }
59}
60
61lazy_static! {
62 static ref RE: Regex = Regex::new(r#"A(?P<Id>\d{6}) (?P<vals>[,\-?\d*,]+),"#).unwrap();
63}
64
65impl FromStr for Series {
66 type Err = ();
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 let caps = RE.captures(s);
70 match caps {
71 Some(m) => Ok(Self {
72 id: m.name("Id").unwrap().as_str().parse().unwrap(),
73 values: m
74 .name("vals")
75 .unwrap()
76 .as_str()
77 .split(',')
78 .filter(|s| !s.is_empty())
79 .map(|s| match s.parse::<i128>() {
81 Ok(n) => NumberValue::InRange(n),
82 Err(_) => {
83 NumberValue::OutOfRange(BigInt::parse_bytes(s.as_bytes(), 10).unwrap())
84 }
85 })
86 .collect(),
87 }),
88 None => Err(()),
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 #[test]
97 fn a344199() {
98 let text = "A344199 ,18,36,60,252,708,834,900,2178,7722,7980,";
99 let s = Series::from_str(text).unwrap();
100 assert_eq!(s.id(), 344199);
101 assert_eq!(
102 *s.values(),
103 vec![18, 36, 60, 252, 708, 834, 900, 2178, 7722, 7980]
104 .iter()
105 .map(|e| NumberValue::InRange(*e))
106 .collect::<Vec<NumberValue>>()
107 );
108 }
109
110 #[test]
111 fn a000001() {
112 let text = "A000001 ,0,1,1,1,2,1,2,1,5,2,2,1,5,1,2,1,14,1,5,1,5,2,2,1,15,2,2,5,4,1,4,1,51,1,2,1,14,1,2,2,14,1,6,1,4,2,2,1,52,2,5,1,5,1,15,2,13,2,2,1,13,1,2,4,267,1,4,1,5,1,4,1,50,1,2,3,4,1,6,1,52,15,2,1,15,1,2,1,12,1,10,1,4,2,";
113 let s = Series::from_str(text).unwrap();
114 assert_eq!(s.id(), 1);
115 assert_eq!(
116 *s.values(),
117 vec![
118 0, 1, 1, 1, 2, 1, 2, 1, 5, 2, 2, 1, 5, 1, 2, 1, 14, 1, 5, 1, 5, 2, 2, 1, 15, 2, 2,
119 5, 4, 1, 4, 1, 51, 1, 2, 1, 14, 1, 2, 2, 14, 1, 6, 1, 4, 2, 2, 1, 52, 2, 5, 1, 5,
120 1, 15, 2, 13, 2, 2, 1, 13, 1, 2, 4, 267, 1, 4, 1, 5, 1, 4, 1, 50, 1, 2, 3, 4, 1, 6,
121 1, 52, 15, 2, 1, 15, 1, 2, 1, 12, 1, 10, 1, 4, 2
122 ]
123 .iter()
124 .map(|e| NumberValue::InRange(*e))
125 .collect::<Vec<NumberValue>>()
126 );
127 }
128}