use std::{io::*, fs::File}; // note that bufread::MultiBzDecoder is _distinct_ from read::MultiBzDecoder use bzip2::bufread::*; // i don't like that there are multiple result types // that seems Bad // also having to explicitly box dyn Error sucks, fine fuck you it's the rust way type Lookup = std::result::Result, Box>; // WHY can you not implement traits on external types, like what?? // fortunately we needed to copy-paste the parse_wiki_text library to fix some bugs anyhow pub fn lookup(word: &str) -> Lookup { if let Ok(file) = File::open(crate::index_path) { return lookup_local(word, file); } else { return lookup_online(word); } } fn lookup_local(word: &str, file: File) -> Lookup { let reader = BufReader::new(MultiBzDecoder::new(BufReader::new(file))); for line in reader.lines() { let line = line.expect("Failed to read line"); // format: file-offset:page-id:page-title let line = line.splitn(3, ":").collect::>(); assert!(line.len() == 3, "Failed to parse line. Is your index file valid?"); let offset = line.get(0).unwrap().parse::()?; let id = line.get(1).unwrap().parse::()?; let title = *line.get(2).unwrap(); // this dereference now makes sense if title == word { let file = File::open(crate::dictionary_path)?; let mut reader = BufReader::new(file); // note: our chunk contains multiple pages let offset = reader.seek(SeekFrom::Start(offset)) .expect("Bad offset. Is your index file valid?"); let reader = BufReader::new(BzDecoder::new(reader)); let mut buffer = String::new(); let mut page = false; for line in reader.lines() { let line = line.unwrap(); if line == format!(" {}", title) { buffer.push_str(" "); buffer.push_str("\n"); page = true; } if page { buffer.push_str(&line); buffer.push_str("\n"); if line == " " { break; } } } return Ok(Some(buffer)); } } return Ok(None); } fn lookup_online(word: &str) -> Lookup { todo!(); }