107 lines
2.7 KiB
Rust
107 lines
2.7 KiB
Rust
use libc;
|
|
use std::fs::File;
|
|
use std::io::{Bufreader, Bytes};
|
|
use std::path::Path;
|
|
|
|
const PARITY: u8 = 0o200;
|
|
const RECORD_SEPARATOR: u8 = 30;
|
|
const OFFSET: u8 = 14;
|
|
const BIGRAMS: usize = BIGRAMS;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Squozen {
|
|
bigrams: [char; BIGRAMS],
|
|
path: Path,
|
|
}
|
|
|
|
pub impl Squozen {
|
|
pub fn new(filename: Path) -> Result<Squozen, Error> {
|
|
let mut dbfile = File::open(filename)?;
|
|
let mut db = Bufreader::new(dbfile);
|
|
let mut bigrams: [char; BIGRAMS] = [0; BIGRAMS];
|
|
db.read_exact(&mut bigrams)?;
|
|
Ok(Squozen {
|
|
bigrams,
|
|
path: filename.clone(),
|
|
})
|
|
}
|
|
|
|
pub fn paths(&mut self) -> StoredPath {
|
|
StoredPath::new(&self);
|
|
}
|
|
|
|
/*
|
|
pub fn iter(&mut self) -> StoredPath {
|
|
FoundPath::new(&self);
|
|
}
|
|
*/
|
|
}
|
|
|
|
pub struct StoredPath<'a> {
|
|
source: Squozen,
|
|
path: [char; libc::PATH_MAX],
|
|
db: Bytes<Bufreader>,
|
|
ch: u8,
|
|
last: usize,
|
|
found: bool,
|
|
}
|
|
|
|
pub impl<'a> StoredPath {
|
|
pub fn new(squozen: Squozen) -> StoredPath {
|
|
let mut dbfile = File::open(&squozen.path)?;
|
|
let mut dbbuffer = Bufreader::new(dbfile);
|
|
dbbuffer.seek(BIGRAMS);
|
|
let mut db = dbbuffer.bytes();
|
|
let mut ch = db.next()?;
|
|
StoredPath {
|
|
squozen,
|
|
db,
|
|
ch,
|
|
path: [0; libc::PATH_MAX],
|
|
last: 0,
|
|
}
|
|
}
|
|
|
|
// Note that in either case, the file pointer will be pointing at the first
|
|
// valid character of the database, or it will be over.
|
|
pub fn getw(&mut self) -> Result<u16> {
|
|
let ch1 = self.db.next()?;
|
|
let ch2 = self.db.next()?;
|
|
Ok(u16::from_le_bytes(&[ch1, ch2]))
|
|
}
|
|
|
|
pub fn get_offset(&mut self) -> Result<usize> {
|
|
if self.ch == RECORD_SEPARATOR {
|
|
let offset = self.getw()?;
|
|
Ok(usize::from(offset))
|
|
} else {
|
|
Ok(usize::from(self.ch))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub impl<'a> Iterator for StoredPath {
|
|
type Item = &[char; libc::PATH_MAX];
|
|
|
|
fn next(&mut self) -> Option<&Self::Item> {
|
|
let offset = self.get_offset();
|
|
let position = 0;
|
|
loop {
|
|
self.ch = self.db.next()?;
|
|
if self.ch <= RECORD_SEPARATOR {
|
|
break;
|
|
}
|
|
if self.ch < PARITY {
|
|
self.path[self.last + position] = ch;
|
|
position += 1;
|
|
} else {
|
|
let bg = self.ch & PARITY - 1;
|
|
self.path[self.last + position] = self.squozen.bigrams[bg * 2];
|
|
self.path[self.last + position + 1] = self.squozen.bigrams[bg * 2 + 1];
|
|
position += 2;
|
|
}
|
|
}
|
|
Some(&self.path)
|
|
}
|
|
}
|