-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrunner.rs
134 lines (112 loc) · 4.31 KB
/
runner.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::{error::Error, fs::File, io::BufReader, path::PathBuf};
/// The library crate to perform the actual operations
use kml_to_fgfp::{self, Airport, EmitterConfig, EventReader};
/// The config for the transformation of the .kml file into .fgfp. Taken as an argument by the
/// [`run`](run) function.
///
/// You can create an instance of this struct using [`Config::build()`](Config::build).
pub struct Config {
input: PathBuf,
output: PathBuf,
departure: Option<String>,
destination: Option<String>,
}
impl Config {
/// Creates a `Config` type. **Assumes** the first iteration of `args` is the program name, so
/// it's ignored.
///
/// Parameter:
/// - `args` - An iterator, meant to iterate over the binary's arguments and flags.
///
/// # Errors
///
/// The functions will fail if `args` does not contain input and output files, or if a flag is
/// not recognized.
pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, Box<dyn Error>> {
args.next();
let input = match args.next() {
Some(path) => PathBuf::from(path),
_ => return Err("Didn't get an input file".into()),
};
let output = match args.next() {
Some(path) => PathBuf::from(path),
_ => return Err("Didn't get a destination directory".into()),
};
let departure = args.next();
let destination = args.next();
Ok(Config {
input,
output,
departure,
destination,
})
}
/// Prints the configuration options to stderr.
///
/// # Example
///
/// ```
/// # use kml_to_fgp::*;
/// Config::print_config()
/// ```
pub fn print_config() {
eprint!(
"\
Usage:
\x1B[01m{} INPUT OUTPUT [DEPARTURE_AIRPORT] [DESTINATION AIRPORT]\x1B[00m\n
INPUT is the Google Earth (.kml) file.\n
OUTPUT is the name of the generated FlightGear flight plan (.fgfp) file.\n
[DEPARTURE_AIRPORT] is an optional argument detailing the departure airport's
ICAO designation. It would look something like `SAEZ`. You can also type a `/`
to add a specific runway, so it would look like `SAEZ/11`.\n
[DESTINATION_AIRPORT] is an optional argument detailing the destination
airport's ICAO designation. It would look something like `YSSY`. You can also
type a `/` to add a specific runway, so it would look like `YSSY/34L`.\n
Version: {}, {} License
",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
env!("CARGO_PKG_LICENSE")
);
}
}
/// This function coordinates the use of this crate's library to process the .kml and create a .fgfp
/// file.
///
/// # Errors
/// This function can fail if some part of the process tries to write invalid xml or for io errors.
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
// Create the writer object.
let mut output_file = File::create(config.output)?;
let mut writer = EmitterConfig::new()
.perform_indent(true)
.indent_string("\t")
.create_writer(&mut output_file);
// 1. Write the beginning of the tree.
kml_to_fgfp::write_start_of_tree(&mut writer)?;
// 2. Write the destination and arrival airports.
let departure = config.departure.map(|ap| airport_decoder(&ap));
let destination = config.destination.map(|ap| airport_decoder(&ap));
kml_to_fgfp::write_airports(&mut writer, &departure, &destination)?;
// Create the reader object.
let input_file = File::open(config.input)?;
let input_file = BufReader::new(input_file);
let parser = EventReader::new(input_file);
// 3. Transform the route in the .kml to .fgfp.
kml_to_fgfp::transform_route(parser, &mut writer, &departure, &destination)?;
// 4. Close the xml tree.
kml_to_fgfp::close_tree(&mut writer)?;
Ok(())
}
/// Decodes a string into an [`Airport`](kml_to_fgfp::Airport). Such that, for example, the string
/// `SAEZ/11` refers to the airport SAEZ and runway 11.
fn airport_decoder(code: &str) -> Airport {
let mut ident = String::from("ICAO");
let mut runway = None;
if code.contains('/') {
let data: Vec<&str> = code.split('/').map(|d| d.trim()).collect();
ident = String::from(data[0]);
runway = Some(String::from(data[1]));
}
Airport { ident, runway }
}