use std::sync::mpsc;
use std::thread;
use std::io::{stdin, stdout};
use std::fs;
use clap::Parser;
use std::path::PathBuf;
mod elements;
mod readers;
use readers::read_file;
mod filter;
use filter::filter_elements;
mod writers;
use writers::write_file;
#[derive(Parser)]
#[command(name = "skyway")]
#[command(author = "Jacob Hall <email@jacobhall.net>")]
#[command(version = env!("CARGO_PKG_VERSION"))]
#[command(about = "Converts OpenStreetMap data between various file formats")]
struct Cli {
#[arg(long)]
filter: Option<Vec<String>>,
#[arg(long)]
from: String,
#[arg(long)]
to: String,
#[arg(long)]
input: Option<String>,
#[arg(long)]
output: Option<String>,
}
fn main() {
let cli = Cli::parse();
#[allow(clippy::needless_late_init)]
let metadata: elements::Metadata;
let (reader_sender, reader_reciever) = mpsc::channel();
let (metadata_sender, metadata_reciever) = mpsc::channel();
let read_thread = thread::spawn(move || {
match cli.input {
None => {
read_file(reader_sender, metadata_sender, &cli.from, stdin())
},
Some(a) => match fs::File::open(PathBuf::from(a)) {
Ok(b) => {
read_file(reader_sender, metadata_sender, &cli.from, b)
},
Err(e) => {
panic!("Unable to open input file: {e:?}");
}
}
}
});
metadata = match metadata_reciever.iter().next() {
Some(m) => m,
None => {
panic!("No metadata received from reader!");
},
};
let mut filter_threads = Vec::new();
let mut this_sender: mpsc::Sender<elements::Element>;
let mut last_reciever: mpsc::Receiver<elements::Element> = reader_reciever;
let mut next_receiver: mpsc::Receiver<elements::Element>;
if let Some(filters) = cli.filter {
for filter in filters {
let filter_contents = match fs::read_to_string(filter) {
Ok(v) => v,
Err(e) => {
panic!("Unable to read filter file: {e:?}");
}
};
(this_sender, next_receiver) = mpsc::channel();
filter_threads.push(Some(thread::spawn(move || {
filter_elements(filter_contents.as_str(), last_reciever, this_sender);
})));
last_reciever = next_receiver;
}
}
let write_thread = thread::spawn(move || {
match cli.output {
None => {
write_file(last_reciever, metadata, &cli.to, stdout())
},
Some(a) => match fs::File::create(PathBuf::from(a)) {
Ok(b) => {
write_file(last_reciever, metadata, &cli.to, b)
},
Err(e) => {
panic!("Unable to open output file: {e:?}");
}
}
}
});
read_thread.join().expect("Couldn't join on read thread!!");
for filter_thread in filter_threads {
let Some(ft) = filter_thread else { continue };
ft.join().expect("Couldn't join on filter thread!!");
}
write_thread.join().expect("Couldn't join on write thread!!");
}