backport some nice things from routing engine and cleanup a bit master
authorTim "S.D.Eagle" Zeitz <dev.tim.zeitz@gmail.com>
Tue, 3 Dec 2019 10:17:38 +0000 (11:17 +0100)
committerTim "S.D.Eagle" Zeitz <dev.tim.zeitz@gmail.com>
Tue, 3 Dec 2019 10:17:38 +0000 (11:17 +0100)
12 files changed:
Cargo.lock
Cargo.toml
README.md
src/bin/compare_vector.rs
src/bin/decode_vector.rs
src/bin/encode_vector.rs
src/bin/example.rs
src/cli.rs
src/index_heap.rs
src/io.rs
src/lib.rs
src/time.rs

index bc66e43..52822a5 100644 (file)
@@ -1,33 +1,35 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
 [[package]]
 name = "libc"
-version = "0.2.43"
+version = "0.2.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "redox_syscall"
-version = "0.1.40"
+version = "0.1.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "stud-rust-base"
 version = "0.1.0"
 dependencies = [
- "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "time"
-version = "0.1.40"
+version = "0.1.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "winapi"
-version = "0.3.6"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -45,9 +47,9 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [metadata]
-"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
-"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
-"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
-"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
+"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
+"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
index efe5553..344beb8 100644 (file)
@@ -2,6 +2,7 @@
 name = "stud-rust-base"
 version = "0.1.0"
 authors = ["Tim Zeitz <tim.zeitz@kit.edu>"]
+edition = '2018'
 
 [dependencies]
-time = "0.1.40"
+time = "^0.1.40"
index 4e8cb76..59210f9 100644 (file)
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ Mit `cargo check` kann man das Programm checken ohne zu bauen, das kann einem ei
 
 Rust hat einen exzellenten Linter, der einem sehr hilft idiomatischen und performanten Code zu schreiben.
 Das ist insbesondere wenn man noch nicht viel Erfahrung mit der Sprache hat extrem sinnvoll!
-Installieren kann man Clippy mit `rustup component add clippy-preview`.
+Installieren kann man Clippy mit `rustup component add clippy`.
 Anstatt `cargo check` ruft man dann `cargo clippy` auf und kann sich auf viel hilfreiches Feedback freuen.
 
 # Rust Routenplanungs-Basis-Framework
@@ -53,12 +53,11 @@ Die entsprechenden Funktionen sind über Traits definiert und können so direkt
 Das kann z.B. so aussehen:
 
 ```Rust
-extern crate stud_rust_base;
 use stud_rust_base::io::*;
 
-let head = Vec::<u32>::load_from("head_file_name").expect("could not read head");
-let lat = Vec::<f32>::load_from("node_latitude_file_name").expect("could not read lat");
-head.write_to("output_file").expect("could not write head");
+let head = Vec::<u32>::load_from("head_file_name")?;
+let lat = Vec::<f32>::load_from("node_latitude_file_name")?;
+head.write_to(&"output_file")?;
 ```
 
 Die Dateien in `src/bin/` sind einmal ein Beispielprogramm sowieso Hilfsprogramme.
@@ -79,12 +78,11 @@ Diese heißen `first_out`, `head` und `weight`.
 Um über die ausgehenden Kanten eines Knoten zu iterieren können Sie den folgenden Code verwenden:
 
 ```Rust
-extern crate stud_rust_base;
 use stud_rust_base::{types::*, io::*};
 
-let first_out = Vec::<EdgeId>::load_from("first_out_file_name").expect("could not read first_out");
-let head = Vec::<NodeId>::load_from("head_file_name").expect("could not read head");
-let travel_time = Vec::<Weight>::load_from("weight_file_name").expect("could not read travel_time");
+let first_out = Vec::<EdgeId>::load_from("first_out_file_name")?;
+let head = Vec::<NodeId>::load_from("head_file_name")?;
+let travel_time = Vec::<Weight>::load_from("weight_file_name")?;
 
 let node_id = 42;
 for edge_id in first_out[node_id] .. first_out[node_id + 1] {
@@ -108,9 +106,9 @@ Die Aufgabengraphen haben die Größe des Deutschlandgraphen.
 
 ## Hinweise zur Nutzung im Routenplanungspraktikum
 
-Der Quellcode soll durch das Ausführen von `cargo build --all` mit dem aktuellen stabilen Compiler (1.29.2) übersetzt werden können.
+Der Quellcode soll durch das Ausführen von `cargo build --all` mit dem aktuellen stabilen Compiler (1.38.0) übersetzt werden können.
 Auf den Poolraumrechner ist kein Rust Compiler vorinstalliert.
 Sie können aber für ihren Nutzer lokal `rustup` und damit dann einen aktuellen Compiler installieren.
 Die Nutzung von nicht stabilen nightly Features ist nicht erlaubt.
 Das verwenden externer crates ist nicht erlaubt.
-Die Rust-Standardbibliothek ist nicht extern.
+Die Rust-Standardbibliothek gilt nicht als extern.
index 5d42c18..2f566ed 100644 (file)
@@ -1,4 +1,3 @@
-extern crate stud_rust_base;
 use stud_rust_base::{io::*, cli::CliErr};
 use std::{env, fmt::Display, error::Error};
 
index 691a7a0..4dca2e7 100644 (file)
@@ -1,4 +1,3 @@
-extern crate stud_rust_base;
 use stud_rust_base::{io::*, cli::CliErr};
 use std::{env, error::Error};
 
index c399669..a51a63a 100644 (file)
@@ -1,4 +1,3 @@
-extern crate stud_rust_base;
 use stud_rust_base::{io::*, cli::CliErr};
 use std::{env, error::Error};
 
index c0dbaf7..68056b8 100644 (file)
@@ -1,30 +1,29 @@
-extern crate stud_rust_base;
+use stud_rust_base::{io::*, time::report_time, types::*};
 
-use stud_rust_base::{
-    types::*,
-    io::*,
-    time::report_time,
-};
+use std::{env, error::Error, path::Path};
 
-use std::{env, path::Path};
-
-fn main() {
+fn main() -> Result<(), Box<dyn Error>> {
     let mut args = env::args();
     args.next();
 
     let arg = &args.next().expect("No directory arg given");
     let path = Path::new(arg);
 
-    let first_out = Vec::<EdgeId>::load_from(path.join("first_out").to_str().unwrap()).expect("could not read first_out");
-    let head = Vec::<NodeId>::load_from(path.join("head").to_str().unwrap()).expect("could not read head");
-    let travel_time = Vec::<Weight>::load_from(path.join("travel_time").to_str().unwrap()).expect("could not read travel_time");
+    let first_out = Vec::<EdgeId>::load_from(path.join("first_out"))?;
+    let head = Vec::<NodeId>::load_from(path.join("head"))?;
+    let travel_time = Vec::<Weight>::load_from(path.join("travel_time"))?;
 
     report_time("iterating over arcs of some node", || {
         let node_id = 42;
-        for edge_id in first_out[node_id] .. first_out[node_id + 1] {
-            println!("There is an arc from {} to {} with weight {}", node_id, head[edge_id as usize], travel_time[edge_id as usize]);
+        for edge_id in first_out[node_id]..first_out[node_id + 1] {
+            println!(
+                "There is an arc from {} to {} with weight {}",
+                node_id, head[edge_id as usize], travel_time[edge_id as usize]
+            );
         }
     });
 
-    vec![42; 42].write_to(path.join("distances").to_str().unwrap()).expect("could not write distances");
+    vec![42; 42].write_to(&path.join("distances"))?;
+
+    Ok(())
 }
index e66421d..fc083d1 100644 (file)
@@ -1,6 +1,6 @@
 //! Utility module for command line interfaces
 
-use std::{fmt, fmt::Display, error::Error};
+use std::{error::Error, fmt, fmt::Display};
 
 /// An error struct to wrap simple static error messages
 #[derive(Debug)]
index a7af9ca..477dc87 100644 (file)
 //!     }
 //! }
 //!
-//! fn main() {
-//!     let mut heap = IndexdMinHeap::new(3);
-//!     heap.push(State { node: 0, distance: 42 });
-//!     heap.push(State { node: 1, distance: 23 });
-//!     heap.push(State { node: 2, distance: 50000 });
-//!     assert_eq!(heap.peek().cloned(), Some(State { node: 1, distance: 23 }));
-//!     heap.decrease_key(State { node: 0, distance: 1 });
-//!     assert_eq!(heap.pop(), Some(State { node: 0, distance: 1 }));
-//! }
+//! let mut heap = IndexdMinHeap::new(3);
+//! heap.push(State { node: 0, distance: 42 });
+//! heap.push(State { node: 1, distance: 23 });
+//! heap.push(State { node: 2, distance: 50000 });
+//! assert_eq!(heap.peek().cloned(), Some(State { node: 1, distance: 23 }));
+//! heap.decrease_key(State { node: 0, distance: 1 });
+//! assert_eq!(heap.pop(), Some(State { node: 0, distance: 1 }));
 //!
 //! ```
 
@@ -55,7 +53,7 @@ pub trait Indexing {
 #[derive(Debug)]
 pub struct IndexdMinHeap<T: Ord + Indexing> {
     positions: Vec<usize>,
-    data: Vec<T>
+    data: Vec<T>,
 }
 
 const TREE_ARITY: usize = 4;
@@ -68,7 +66,7 @@ impl<T: Ord + Indexing> IndexdMinHeap<T> {
     pub fn new(max_index: usize) -> IndexdMinHeap<T> {
         IndexdMinHeap {
             positions: vec![INVALID_POSITION; max_index],
-            data: Vec::new()
+            data: Vec::new(),
         }
     }
 
@@ -170,7 +168,10 @@ impl<T: Ord + Indexing> IndexdMinHeap<T> {
             let mut hole = Hole::new(&mut self.data, position);
 
             loop {
-                if let Some(smallest_child) = IndexdMinHeap::<T>::children_index_range(position, heap_size).min_by_key(|&child_index| hole.get(child_index)) {
+                if let Some(smallest_child) =
+                    IndexdMinHeap::<T>::children_index_range(position, heap_size)
+                        .min_by_key(|&child_index| hole.get(child_index))
+                {
                     if hole.get(smallest_child) >= hole.element() {
                         self.positions[hole.element().as_index()] = position;
                         return; // no child is smaller
@@ -194,12 +195,10 @@ impl<T: Ord + Indexing> IndexdMinHeap<T> {
     }
 }
 
-
 // This is an optimization copied straight from the rust stdlib binary heap
 // it allows to avoid always swapping elements pairwise and rather
 // move each element only once.
 
-
 /// Hole represents a hole in a slice i.e. an index without valid value
 /// (because it was moved from or duplicated).
 /// In drop, `Hole` will restore the slice by filling the hole
index 419fa45..52057af 100644 (file)
--- a/src/io.rs
+++ b/src/io.rs
@@ -1,26 +1,26 @@
 //! This module contains a few traits and blanket implementations
-//! for (de)serializing and writing/reading numeric data to/from the disc.
+//! for (de)serializing and writing/reading data to/from the disc.
 //! To use it you should import the `Load` and `Store` traits and use the
 //! `load_from` and `write_to` methods.
 //!
 //! # Example
 //!
-//! ```
-//! use stud_rust_base::io::*;
+//! ```no_run
+//! use stud_rust_base::io::*;
 //!
-//! fn test() {
-//!     let head = Vec::<u32>::load_from("head_file_name").expect("could not read head");
-//!     let lat = Vec::<f32>::load_from("node_latitude_file_name").expect("could not read lat");
-//!     head.write_to("output_file").expect("could not write head");
-//! }
+//! let head = Vec::<u32>::load_from("head_file_name")?;
+//! let lat = Vec::<f32>::load_from("node_latitude_file_name")?;
+//! head.write_to(&"output_file")?;
+//! # Ok::<(), Box<dyn std::error::Error>>(())
 //! ```
 
-use std::fs;
-use std::fs::File;
-use std::io::prelude::*;
-use std::io::Result;
-use std::mem;
-use std::slice;
+use std::{
+    fs::{metadata, File},
+    io::{prelude::*, Result},
+    mem,
+    path::Path,
+    slice,
+};
 
 /// A trait which allows accessing the data of an object as a slice of bytes.
 /// The bytes should represent a serialization of the object and allow
@@ -49,6 +49,12 @@ impl<T: Copy> DataBytes for [T] {
     }
 }
 
+impl<T: Copy> DataBytes for Vec<T> {
+    fn data_bytes(&self) -> &[u8] {
+        &self[..].data_bytes()
+    }
+}
+
 impl<T: Copy> DataBytesMut for [T] {
     fn data_bytes_mut(&mut self) -> &mut [u8] {
         let num_bytes = self.len() * mem::size_of::<T>();
@@ -64,10 +70,10 @@ impl<T: Copy> DataBytesMut for Vec<T> {
 }
 
 /// A trait which extends the `DataBytes` trait and exposes a method to write objects to disk.
-pub trait Store : DataBytes {
-    /// Writes the serialized object to the file with the given filename
-    fn write_to(&self, filename: &str) -> Result<()> {
-        File::create(filename)?.write_all(self.data_bytes())
+pub trait Store: DataBytes {
+    /// Writes the serialized object to the file with the given path
+    fn write_to(&self, path: &dyn AsRef<Path>) -> Result<()> {
+        File::create(path)?.write_all(self.data_bytes())
     }
 }
 
@@ -75,16 +81,16 @@ impl<T: DataBytes> Store for T {}
 impl<T> Store for [T] where [T]: DataBytes {}
 
 /// A trait to load serialized data back into objects.
-pub trait Load : DataBytesMut + Sized {
+pub trait Load: DataBytesMut + Sized {
     /// This method must create an object of the correct size for serialized data with the given number of bytes.
     /// It should not be necessary to call this method directly.
     fn new_with_bytes(num_bytes: usize) -> Self;
 
     /// This method will load serialized data from the disk, create an object of the appropriate size,
     /// deserialize the bytes into the object and return the object.
-    fn load_from(filename: &str) -> Result<Self> {
-        let metadata = fs::metadata(filename)?;
-        let mut file = File::open(filename)?;
+    fn load_from<P: AsRef<Path>>(path: P) -> Result<Self> {
+        let metadata = metadata(path.as_ref())?;
+        let mut file = File::open(path)?;
 
         let mut object = Self::new_with_bytes(metadata.len() as usize);
         assert_eq!(metadata.len() as usize, object.data_bytes_mut().len());
index 85f3191..d0ab4df 100644 (file)
@@ -1,7 +1,5 @@
 //! A small base framework for route planning student projects.
 
-extern crate time as time_crate;
-
 pub mod cli;
 pub mod index_heap;
 pub mod io;
index 8a3843c..687f3e4 100644 (file)
@@ -1,15 +1,13 @@
 //! This module contains a few utilities to measure how long executing algorithms takes.
 //! It utilizes the `time` crate.
 
-use time_crate as time;
-
 /// This function will measure how long it takes to execute the given lambda,
 /// print the time and return the result of the lambda.
 pub fn report_time<Out, F: FnOnce() -> Out>(name: &str, f: F) -> Out {
     let start = time::now();
-    println!("starting {}", name);
+    eprintln!("starting {}", name);
     let res = f();
-    println!("done {} - took: {}", name, (time::now() - start));
+    eprintln!("done {} - took: {}", name, (time::now() - start));
     res
 }
 
@@ -46,7 +44,7 @@ impl Timer {
 
     /// Print the passed time in ms since the timer was started
     pub fn report_passed_ms(&self) {
-        println!("{}ms", (time::now() - self.start).num_milliseconds());
+        eprintln!("{}ms", (time::now() - self.start).num_milliseconds());
     }
 
     /// Return the number of ms passed since the timer was started as a `i64`