Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: improvements #6

Merged
merged 6 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/commands/derive_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use log::info;

use crate::{
data::{
database,
database::Database,
maps::{link_map::LinkMap, page_map::PageMap},
parsers::{links, pages, redirects},
},
Expand Down Expand Up @@ -112,7 +112,8 @@ fn derive_db_command(args: DeriveDbArgs) {
.with_finish_message("Serialized and written to file")
.build();
spinner.enable_background();
database::serialize(output.as_str(), &links, &lookup);
Database::new(links, lookup).to_file(output.as_str());

spinner.finish();
}
}
23 changes: 13 additions & 10 deletions src/commands/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clap::Args;
use crate::{
data::{
algorithm::bfs,
database,
database::Database,
maps::page_map::{PageMap, PageMapResult},
},
indication::ProgressBuilder,
Expand All @@ -27,20 +27,23 @@ impl ArgExecutor for InteractiveArgs {
fn interactive_cmd(args: &InteractiveArgs) {
let db = args.db.to_string();

let spinner = ProgressBuilder::spinner()
.with_message("📝 Deserializing DB")
.build();
spinner.enable_background();
let data = database::deserialize(&db);
spinner.finish();
let db = {
let spinner = ProgressBuilder::spinner()
.with_message("📝 Deserializing DB")
.build();
spinner.enable_background();
let data = Database::from_file(&db);
spinner.finish();
data
};

println!(
"Usage: Enter a start page and a target page to find the shortest path between them
If you want to exit press ctrl+d or ctrl+c\n"
);

let links = data.links;
let lookup = data.pages;
let links = db.links;
let lookup = db.pages;

fn page_input_loop(prompt: &str, pages: &PageMap) -> Option<PageMapResult> {
loop {
Expand Down Expand Up @@ -75,12 +78,12 @@ If you want to exit press ctrl+d or ctrl+c\n"
let end = end.unwrap();

let (path, time) = {
let time_before = std::time::Instant::now();
let spinner = ProgressBuilder::spinner()
.with_message("Searching for path")
.build();
spinner.enable_background();

let time_before = std::time::Instant::now();
let path = bfs::find_shortest_path(start.id, end.id, &links);
let time = time_before.elapsed().as_millis();

Expand Down
31 changes: 19 additions & 12 deletions src/data/algorithm/bfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ use log::debug;

use crate::data::maps::link_map::LinkMap;

fn rebuild_path(predecessors: HashMap<i32, i32>, start: i32, end: i32) -> Vec<i32> {
let mut out_path = VecDeque::new();
out_path.push_front(end);
let mut at = end;
while let Some(&node) = predecessors.get(&at) {
if at == start {
break;
}
out_path.push_front(node);
at = node;
}

Vec::from(out_path)
}

pub fn find_shortest_path(start: i32, end: i32, links: &LinkMap) -> Option<Vec<i32>> {
if start == end {
return Some(vec![start]);
Expand All @@ -12,6 +27,7 @@ pub fn find_shortest_path(start: i32, end: i32, links: &LinkMap) -> Option<Vec<i
let mut queue = VecDeque::new();
let mut predecessor = HashMap::new();
let mut visited = HashSet::new(); // note: having a set of visited nodes improves performance by a few percent while increasing memory usage

queue.push_back(start);
predecessor.insert(start, start);
visited.insert(start);
Expand All @@ -20,9 +36,11 @@ pub fn find_shortest_path(start: i32, end: i32, links: &LinkMap) -> Option<Vec<i

while let Some(at) = queue.pop_front() {
let neighbors = links.get(at);

if neighbors.is_none() {
continue;
}

for &neighbor in neighbors.unwrap() {
if visited.contains(&neighbor) {
continue;
Expand All @@ -33,19 +51,8 @@ pub fn find_shortest_path(start: i32, end: i32, links: &LinkMap) -> Option<Vec<i
visited.insert(neighbor);

if neighbor == end {
let mut out_path = VecDeque::new();
out_path.push_front(neighbor);
let mut at = neighbor;
while let Some(&node) = predecessor.get(&at) {
if at == start {
break;
}
out_path.push_front(node);
at = node;
}

debug!("Found path in {} steps", steps);
return Some(Vec::from(out_path));
return Some(rebuild_path(predecessor, start, end));
}
}

Expand Down
32 changes: 15 additions & 17 deletions src/data/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@ use serde::{Deserialize, Serialize};

use crate::data::maps::{link_map::LinkMap, page_map::PageMap};

#[derive(Serialize)]
struct SerializerDatabase<'a> {
pub links: &'a LinkMap,
pub pages: &'a PageMap,
}

#[derive(Deserialize)]
#[derive(Serialize, Deserialize)]
pub struct Database {
pub links: LinkMap,
pub pages: PageMap,
}

pub fn serialize(outfile: &str, links: &LinkMap, pages: &PageMap) {
let db = SerializerDatabase { links, pages };
impl Database {
pub fn new(links: LinkMap, pages: PageMap) -> Self {
Self { links, pages }
}

let file = std::fs::File::create(outfile).unwrap();
let writer = std::io::BufWriter::new(file);
pub fn to_file(&self, outfile: &str) {
let file = std::fs::File::create(outfile).unwrap();
let writer = std::io::BufWriter::new(file);

ciborium::into_writer(&db, writer).expect("Error writing db");
}
ciborium::into_writer(self, writer).expect("Error writing db");
}

pub fn deserialize(infile: &str) -> Database {
let file = std::fs::File::open(infile).unwrap();
let reader = std::io::BufReader::new(file);
pub fn from_file(infile: &str) -> Database {
let file = std::fs::File::open(infile).unwrap();
let reader = std::io::BufReader::new(file);

ciborium::from_reader(reader).expect("Error reading db")
ciborium::from_reader(reader).expect("Error reading db")
}
}
15 changes: 10 additions & 5 deletions src/indication.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#![allow(dead_code)] // todo: remove this when tests are implemented
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};

fn progressbar_template(len: u64) -> ProgressBar {
fn progressbar(len: u64) -> ProgressBar {
let pb = ProgressBar::new(len);
pb.set_style(
ProgressStyle::with_template(
Expand Down Expand Up @@ -45,7 +44,7 @@ impl ProgressReporter {
finish_message: &'static str,
len: u64,
) -> Self {
let progress = progressbar_template(len);
let progress = progressbar(len);
progress.set_prefix(format!("[{}/{}]", step, steps));
progress.set_message(message.clone());

Expand Down Expand Up @@ -73,6 +72,7 @@ impl ProgressReporter {
}
}

#[cfg(test)]
pub fn new_empty() -> Self {
Self {
progress: None,
Expand Down Expand Up @@ -106,6 +106,7 @@ impl ProgressReporter {
enum ProgressType {
Progress,
Spinner,
#[cfg(test)]
Empty,
}

Expand All @@ -119,6 +120,7 @@ pub struct ProgressBuilder {
}

impl ProgressBuilder {
#[cfg(test)]
pub fn empty() -> Self {
Self {
bar_type: ProgressType::Empty,
Expand All @@ -129,6 +131,7 @@ impl ProgressBuilder {
step: None,
}
}

pub fn new() -> Self {
Self {
bar_type: ProgressType::Progress,
Expand Down Expand Up @@ -172,6 +175,7 @@ impl ProgressBuilder {
self
}

#[cfg(test)]
fn build_empty(self) -> ProgressReporter {
ProgressReporter::new_empty()
}
Expand All @@ -192,8 +196,8 @@ impl ProgressBuilder {
let finish_message = self.finish_message;

let steps = self
.steps
.map(|steps| (steps, self.step.expect("only steps given, no step")));
.step
.map(|step| (step, self.steps.expect("only step given, steps missing")));

ProgressReporter::new_spinner(message, finish_message, steps)
}
Expand All @@ -202,6 +206,7 @@ impl ProgressBuilder {
match self.bar_type {
ProgressType::Progress => self.build_progress(),
ProgressType::Spinner => self.build_spinner(),
#[cfg(test)]
ProgressType::Empty => self.build_empty(),
}
}
Expand Down
28 changes: 1 addition & 27 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use clap::{Parser, Subcommand};
use clap::Parser;

mod commands;
mod data;
Expand All @@ -11,32 +11,6 @@ struct Args {
command: Option<commands::Commands>,
}

#[derive(Subcommand, Debug)]
enum SubCommands {
DeriveDB {
/// Path to the page.sql file
#[arg(short, long)]
pages_sql: String,

/// Path to the redirects.sql file
#[arg(short, long)]
redirects_sql: String,

/// Path to the links.sql file
#[arg(short, long)]
links_sql: String,

/// Output Path
#[arg(short, long)]
output: String,
},

Test {
#[arg(short, long)]
db: String,
},
}

fn main() {
env_logger::init();
let args = Args::parse();
Expand Down