<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

pub fn single_night(file: &str) -> i64 {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let edge_cmds = reader.lines()
        .filter_map(Result::ok)
        .map(|line| {
            let words = line.split_whitespace().collect::<Vec<&str>>();
            let from = words[0].to_owned();
            let to = words[2].to_owned();
            let distance = words[4].parse::<i64>().expect("parse error");

            (from, to, distance)
        })
        .collect::<Vec<(String, String, i64)>>();
    println!("{:?}", edge_cmds);

    let mut nodes = Vec::new();
    for &(ref from, ref to, _) in edge_cmds.iter() {
        nodes.push(from);
        nodes.push(to);
    }
    nodes.sort();
    nodes.dedup();
    println!("{:?}", nodes);

    let mut edge_lengths = HashMap::new();
    let mut edges = HashMap::new();
    for &(ref from, ref to, ref distance) in edge_cmds.iter() {
        if let Ok(from_idx) = nodes.binary_search(&&from) {
            if let Ok(to_idx) = nodes.binary_search(&&to) {
                println!("{} <-> {}", from_idx, to_idx);
                {
                    edge_lengths.insert((from_idx, to_idx), *distance);
                    let mut neighbors = edges.entry(from_idx).or_insert(Vec::new());
                    neighbors.push(to_idx);
                }
                {
                    // bi-directional
                    edge_lengths.insert((to_idx, from_idx), *distance);
                    let mut neighbors = edges.entry(to_idx).or_insert(Vec::new());
                    neighbors.push(from_idx);
                }
            }
        }
    }
    println!("{:?}", edge_lengths);
    println!("{:?}", edges);
    (0..nodes.len()).map(|i| dijkstra(&nodes, &edges, &edge_lengths, i)).min().unwrap()
}

fn dijkstra(nodes: &Vec<&String>,
            edges: &HashMap<usize, Vec<usize>>,
            edge_lengths: &HashMap<(usize, usize), i64>,
            source: usize)
            -> i64 {

    let mut q = nodes.iter()
        .enumerate()
        .map(|en| {
            let (i, _) = en;
            Some(i)
        })
        .collect::<Vec<Option<usize>>>();
    let mut dist = vec![i64::max_value(); nodes.len()];
    let mut prev = vec![None; nodes.len()];

    dist[source] = 0;

    loop {
        if q.iter().all(Option::is_none) {
            break;
        }
        if let Some((min_idx, _)) =
            dist.iter()
                .enumerate()
                .filter(|d| q[d.0].is_some())
                .inspect(|&e| println!("{:?}", e))
                .min_by_key(|&(_, v)| {
                    v
                }) {
            println!("");
            println!("q: {:?}", q);
            println!("distances: {:?},", dist);
            println!("dist[{}] = {}", min_idx, dist[min_idx]);
            let node_idx = q[min_idx];
            q[min_idx] = None;
            if let Some(node_idx) = node_idx {
                if let Some(neighbors) = edges.get(&node_idx) {
                    for neighbor in neighbors.iter().filter(|&&n| q[n].is_some()) {
                        let edge_key = (node_idx, *neighbor);
                        if let Some(length) = edge_lengths.get(&edge_key) {
                            let alt = dist[node_idx] + length;
                            println!("neighbor = {:?}", neighbor);
                            println!("alt = {:?}", alt);
                            if alt < dist[*neighbor] {
                                dist[*neighbor] = alt;
                                println!("dist[{}] = {}", neighbor, dist[*neighbor]);
                                prev[*neighbor] = Some(node_idx);
                            }
                        }
                    }
                }
            }
        }
    }
    println!("distances: {:?},", dist);
    println!("path: {:?},", prev);
    dist.iter().sum()
}

#[derive(Debug)]
struct Edge {
    from: usize,
    to: usize,
    length: i64,
}
<commit_msg>Dijkstra's will not work.<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

pub fn single_night(file: &str) -> i64 {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let edge_cmds = reader.lines()
        .filter_map(Result::ok)
        .map(|line| {
            let words = line.split_whitespace().collect::<Vec<&str>>();
            let from = words[0].to_owned();
            let to = words[2].to_owned();
            let distance = words[4].parse::<i64>().expect("parse error");

            (from, to, distance)
        })
        .collect::<Vec<(String, String, i64)>>();
//    println!("{:?}", edge_cmds);

    let mut nodes = Vec::new();
    for &(ref from, ref to, _) in edge_cmds.iter() {
        nodes.push(from);
        nodes.push(to);
    }
    nodes.sort();
    nodes.dedup();
    println!("{:?}", nodes);

    let mut edge_lengths = HashMap::new();
    let mut edges = HashMap::new();
    for &(ref from, ref to, ref distance) in edge_cmds.iter() {
        if let Ok(from_idx) = nodes.binary_search(&&from) {
            if let Ok(to_idx) = nodes.binary_search(&&to) {
//                println!("{} <-> {}", from_idx, to_idx);
                {
                    edge_lengths.insert((from_idx, to_idx), *distance);
                    let mut neighbors = edges.entry(from_idx).or_insert(Vec::new());
                    neighbors.push(to_idx);
                }
                {
                    // bi-directional
                    edge_lengths.insert((to_idx, from_idx), *distance);
                    let mut neighbors = edges.entry(to_idx).or_insert(Vec::new());
                    neighbors.push(from_idx);
                }
            }
        }
    }
    println!("{:?}", edges);
    println!("{:?}", edge_lengths);
    (0..nodes.len()).map(|i| salesman(&nodes, &edges, &edge_lengths, i))
        .inspect(|distance| println!("{}", distance))
        .min().unwrap()
}

fn salesman(nodes: &Vec<&String>,
            edges: &HashMap<usize, Vec<usize>>,
            edge_lengths: &HashMap<(usize, usize), i64>,
            source: usize)
            -> i64 {

    let mut q = nodes.iter()
        .enumerate()
        .map(|en| {
            let (i, _) = en;
            Some(i)
        })
    .collect::<Vec<Option<usize>>>();

    let mut visited = vec![false; nodes.len()];
    visited[source] = true;
    let mut curr = source;
    let mut sum = 0;
    let mut count = 0;

    loop {
        if visited.iter().all(|&b| b) {
            break;
        }
        count += 1;
        if count == 500 {
            return i64::max_value();
        }
        if let Some(node_idx) = q[curr] {
            if let Some(neighbors) = edges.get(&node_idx) {
                if let Some((&min_idx, &length)) = neighbors.iter()
                    .filter(|&&n| q[n].is_some())
                        .map(|neighbor| {
                            let edge_key = (node_idx, *neighbor);
                            let length = edge_lengths.get(&edge_key).unwrap();
                            (neighbor, length)
                        })
                .min_by_key(|&(_, &length)| length)
                {
                    println!("min: {:?}", min_idx);
                    visited[min_idx] = true;
                    curr = min_idx;
                    sum += length;
                    count = 0;
                }
            }
        }
    }
    sum
}

#[derive(Debug)]
struct Edge {
    from: usize,
    to: usize,
    length: i64,
}
<|endoftext|>


<commit_before>//! A thread-local reference-counted slice type.

use core::prelude::*;

use core::{cmp, fmt, mem, ops};
use core::hash::{Hash, Hasher};

use alloc::rc::{self, Rc, Weak};
use alloc::boxed::Box;

/// A reference-counted slice type.
///
/// This is exactly like `&[T]` except without lifetimes, so the
/// allocation only disappears once all `RcSlice`s have disappeared.
///
/// NB. this can lead to applications effectively leaking memory if a
/// short subslice of a long `RcSlice` is held.
///
/// # Examples
///
/// ```rust
/// use shared_slice::rc::RcSlice;
///
/// let x = RcSlice::new(Box::new(["foo", "bar", "baz"]));
/// println!("{:?}", x); // ["foo", "bar", "baz"]
/// println!("{:?}", x.slice(1, 3)); // ["bar", "baz"]
/// ```
///
/// Constructing with a dynamic number of elements:
///
/// ```rust
/// # #![allow(unstable)]
/// use shared_slice::rc::RcSlice;
///
/// let n = 5;
///
/// let v: Vec<u8> = (0u8..n).collect(); // 0, ..., 4
///
/// let x = RcSlice::new(v.into_boxed_slice());
/// assert_eq!(&*x, [0, 1, 2, 3, 4]);
/// ```
pub struct RcSlice<T> {
    data: *const [T],
    counts: Rc<()>,
}

/// A non-owning reference-counted slice type.
///
/// This is to `RcSlice` as `std::rc::Weak` is to `std::rc::Rc`, and
/// allows one to have cyclic references without stopping memory from
/// being deallocated.
pub struct WeakSlice<T> {
    data: *const [T],
    counts: Weak<()>,
}

impl<T> RcSlice<T> {
    /// Construct a new `RcSlice` containing the elements of `slice`.
    ///
    /// This reuses the allocation of `slice`.
    pub fn new(slice: Box<[T]>) -> RcSlice<T> {
        RcSlice {
            data: unsafe {mem::transmute(slice)},
            counts: Rc::new(())
        }
    }

    /// Downgrade self into a weak slice.
    pub fn downgrade(&self) -> WeakSlice<T> {
        WeakSlice {
            data: self.data,
            counts: self.counts.downgrade()
        }
    }

    /// Construct a new `RcSlice` that only points to elements at
    /// indices `lo` (inclusive) through `hi` (exclusive).
    ///
    /// This consumes `self` to avoid unnecessary reference-count
    /// modifications. Use `.clone()` if it is necessary to refer to
    /// `self` after calling this.
    ///
    /// # Panics
    ///
    /// Panics if `lo > hi` or if either are strictly greater than
    /// `self.len()`.
    pub fn slice(mut self, lo: usize, hi: usize) -> RcSlice<T> {
        self.data = unsafe {&(&*self.data)[lo..hi]};
        self
    }
    /// Construct a new `RcSlice` that only points to elements at
    /// indices up to `hi` (exclusive).
    ///
    /// This consumes `self` to avoid unnecessary reference-count
    /// modifications. Use `.clone()` if it is necessary to refer to
    /// `self` after calling this.
    ///
    /// # Panics
    ///
    /// Panics if `hi > self.len()`.
    pub fn slice_to(self, hi: usize) -> RcSlice<T> {
        self.slice(0, hi)
    }
    /// Construct a new `RcSlice` that only points to elements at
    /// indices starting at  `lo` (inclusive).
    ///
    /// This consumes `self` to avoid unnecessary reference-count
    /// modifications. Use `.clone()` if it is necessary to refer to
    /// `self` after calling this.
    ///
    /// # Panics
    ///
    /// Panics if `lo > self.len()`.
    pub fn slice_from(self, lo: usize) -> RcSlice<T> {
        let hi = self.len();
        self.slice(lo, hi)
    }
}

impl<T> Clone for RcSlice<T> {
    fn clone(&self) -> RcSlice<T> {
        RcSlice {
            data: self.data,
            counts: self.counts.clone()
        }
    }
}

impl<T> ops::Deref for RcSlice<T> {
    type Target = [T];
    fn deref<'a>(&'a self) -> &'a [T] {
        unsafe {&*self.data}
    }
}

impl<T> AsRef<[T]> for RcSlice<T> {
    fn as_ref(&self) -> &[T] { &**self }
}

impl<T: PartialEq> PartialEq for RcSlice<T> {
    fn eq(&self, other: &RcSlice<T>) -> bool { **self == **other }
    fn ne(&self, other: &RcSlice<T>) -> bool { **self != **other }
}
impl<T: Eq> Eq for RcSlice<T> {}

impl<T: PartialOrd> PartialOrd for RcSlice<T> {
    fn partial_cmp(&self, other: &RcSlice<T>) -> Option<cmp::Ordering> {
        (**self).partial_cmp(&**other)
    }
    fn lt(&self, other: &RcSlice<T>) -> bool { **self < **other }
    fn le(&self, other: &RcSlice<T>) -> bool { **self <= **other }
    fn gt(&self, other: &RcSlice<T>) -> bool { **self > **other }
    fn ge(&self, other: &RcSlice<T>) -> bool { **self >= **other }
}
impl<T: Ord> Ord for RcSlice<T> {
    fn cmp(&self, other: &RcSlice<T>) -> cmp::Ordering { (**self).cmp(&**other) }
}

impl<T: Hash> Hash for RcSlice<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&**self, state)
    }
}

impl<T: fmt::Debug> fmt::Debug for RcSlice<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<T> WeakSlice<T> {
    /// Attempt to upgrade `self` to a strongly-counted `RcSlice`.
    ///
    /// Returns `None` if this is not possible (the data has already
    /// been freed).
    pub fn upgrade(&self) -> Option<RcSlice<T>> {
        self.counts.upgrade().map(|counts| {
            RcSlice {
                data: self.data,
                counts: counts
            }
        })
    }
}

// only RcSlice needs a destructor, since it entirely controls the
// actual allocated data; the deallocation of the counts (which is the
// only thing a WeakSlice needs to do if it is the very last pointer)
// is already handled by Rc<()>/Weak<()>.
impl<T> Drop for RcSlice<T> {
    fn drop(&mut self) {
        let strong = rc::strong_count(&self.counts);
        if strong == 1 {
            // last one, so let's clean up the stored data
            unsafe {
                let _: Box<[T]> = mem::transmute(self.data);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{RcSlice, WeakSlice};
    use std::cell::Cell;
    use std::cmp::Ordering;
    #[test]
    fn clone() {
        let x = RcSlice::new(Box::new([Cell::new(false)]));
        let y = x.clone();

        assert_eq!(x[0].get(), false);
        assert_eq!(y[0].get(), false);

        x[0].set(true);
        assert_eq!(x[0].get(), true);
        assert_eq!(y[0].get(), true);
    }

    #[test]
    fn test_upgrade_downgrade() {
        let x = RcSlice::new(Box::new([1]));
        let y: WeakSlice<_> = x.downgrade();

        assert_eq!(y.upgrade(), Some(x.clone()));

        drop(x);

        assert!(y.upgrade().is_none())
    }

    #[test]
    fn test_total_cmp() {
        let x = RcSlice::new(Box::new([1, 2, 3]));
        let y = RcSlice::new(Box::new([1, 2, 3]));
        let z = RcSlice::new(Box::new([1, 2, 4]));
        assert_eq!(x, x);
        assert_eq!(x, y);
        assert!(x != z);
        assert!(y != z);

        assert!(x < z);
        assert!(x <= z);
        assert!(!(x > z));
        assert!(!(x >= z));

        assert!(!(z < x));
        assert!(!(z <= x));
        assert!(z > x);
        assert!(z >= x);

        assert_eq!(x.partial_cmp(&x), Some(Ordering::Equal));
        assert_eq!(x.partial_cmp(&y), Some(Ordering::Equal));
        assert_eq!(x.partial_cmp(&z), Some(Ordering::Less));
        assert_eq!(z.partial_cmp(&y), Some(Ordering::Greater));

        assert_eq!(x.cmp(&x), Ordering::Equal);
        assert_eq!(x.cmp(&y), Ordering::Equal);
        assert_eq!(x.cmp(&z), Ordering::Less);
        assert_eq!(z.cmp(&y), Ordering::Greater);
    }

    #[test]
    fn test_partial_cmp() {
        use std::f64;
        let x = RcSlice::new(Box::new([1.0, f64::NAN]));
        let y = RcSlice::new(Box::new([1.0, f64::NAN]));
        let z = RcSlice::new(Box::new([2.0, f64::NAN]));
        let w = RcSlice::new(Box::new([f64::NAN, 1.0]));
        assert!(!(x == y));
        assert!(x != y);

        assert!(!(x < y));
        assert!(!(x <= y));
        assert!(!(x > y));
        assert!(!(x >= y));

        assert!(x < z);
        assert!(x <= z);
        assert!(!(x > z));
        assert!(!(x >= z));

        assert!(!(z < w));
        assert!(!(z <= w));
        assert!(!(z > w));
        assert!(!(z >= w));

        assert_eq!(x.partial_cmp(&x), None);
        assert_eq!(x.partial_cmp(&y), None);
        assert_eq!(x.partial_cmp(&z), Some(Ordering::Less));
        assert_eq!(z.partial_cmp(&x), Some(Ordering::Greater));

        assert_eq!(x.partial_cmp(&w), None);
        assert_eq!(y.partial_cmp(&w), None);
        assert_eq!(z.partial_cmp(&w), None);
        assert_eq!(w.partial_cmp(&w), None);
    }

    #[test]
    fn test_show() {
        let x = RcSlice::new(Box::new([1, 2]));
        assert_eq!(format!("{:?}", x), "[1, 2]");

        let y: RcSlice<i32> = RcSlice::new(Box::new([]));
        assert_eq!(format!("{:?}", y), "[]");
    }

    #[test]
    fn test_slice() {
        let x = RcSlice::new(Box::new([1, 2, 3]));
        let real = [1, 2, 3];
        for i in (0..3 + 1) {
            for j in (i..3 + 1) {
                let slice: RcSlice<_> = x.clone().slice(i, j);
                assert_eq!(&*slice, &real[i..j]);
            }
            assert_eq!(&*x.clone().slice_to(i), &real[..i]);
            assert_eq!(&*x.clone().slice_from(i), &real[i..]);
        }
    }
}
<commit_msg>Testcase that shows RcSlice's free bug<commit_after>//! A thread-local reference-counted slice type.

use core::prelude::*;

use core::{cmp, fmt, mem, ops};
use core::hash::{Hash, Hasher};

use alloc::rc::{self, Rc, Weak};
use alloc::boxed::Box;

/// A reference-counted slice type.
///
/// This is exactly like `&[T]` except without lifetimes, so the
/// allocation only disappears once all `RcSlice`s have disappeared.
///
/// NB. this can lead to applications effectively leaking memory if a
/// short subslice of a long `RcSlice` is held.
///
/// # Examples
///
/// ```rust
/// use shared_slice::rc::RcSlice;
///
/// let x = RcSlice::new(Box::new(["foo", "bar", "baz"]));
/// println!("{:?}", x); // ["foo", "bar", "baz"]
/// println!("{:?}", x.slice(1, 3)); // ["bar", "baz"]
/// ```
///
/// Constructing with a dynamic number of elements:
///
/// ```rust
/// # #![allow(unstable)]
/// use shared_slice::rc::RcSlice;
///
/// let n = 5;
///
/// let v: Vec<u8> = (0u8..n).collect(); // 0, ..., 4
///
/// let x = RcSlice::new(v.into_boxed_slice());
/// assert_eq!(&*x, [0, 1, 2, 3, 4]);
/// ```
pub struct RcSlice<T> {
    data: *const [T],
    counts: Rc<()>,
}

/// A non-owning reference-counted slice type.
///
/// This is to `RcSlice` as `std::rc::Weak` is to `std::rc::Rc`, and
/// allows one to have cyclic references without stopping memory from
/// being deallocated.
pub struct WeakSlice<T> {
    data: *const [T],
    counts: Weak<()>,
}

impl<T> RcSlice<T> {
    /// Construct a new `RcSlice` containing the elements of `slice`.
    ///
    /// This reuses the allocation of `slice`.
    pub fn new(slice: Box<[T]>) -> RcSlice<T> {
        RcSlice {
            data: unsafe {mem::transmute(slice)},
            counts: Rc::new(())
        }
    }

    /// Downgrade self into a weak slice.
    pub fn downgrade(&self) -> WeakSlice<T> {
        WeakSlice {
            data: self.data,
            counts: self.counts.downgrade()
        }
    }

    /// Construct a new `RcSlice` that only points to elements at
    /// indices `lo` (inclusive) through `hi` (exclusive).
    ///
    /// This consumes `self` to avoid unnecessary reference-count
    /// modifications. Use `.clone()` if it is necessary to refer to
    /// `self` after calling this.
    ///
    /// # Panics
    ///
    /// Panics if `lo > hi` or if either are strictly greater than
    /// `self.len()`.
    pub fn slice(mut self, lo: usize, hi: usize) -> RcSlice<T> {
        self.data = unsafe {&(&*self.data)[lo..hi]};
        self
    }
    /// Construct a new `RcSlice` that only points to elements at
    /// indices up to `hi` (exclusive).
    ///
    /// This consumes `self` to avoid unnecessary reference-count
    /// modifications. Use `.clone()` if it is necessary to refer to
    /// `self` after calling this.
    ///
    /// # Panics
    ///
    /// Panics if `hi > self.len()`.
    pub fn slice_to(self, hi: usize) -> RcSlice<T> {
        self.slice(0, hi)
    }
    /// Construct a new `RcSlice` that only points to elements at
    /// indices starting at  `lo` (inclusive).
    ///
    /// This consumes `self` to avoid unnecessary reference-count
    /// modifications. Use `.clone()` if it is necessary to refer to
    /// `self` after calling this.
    ///
    /// # Panics
    ///
    /// Panics if `lo > self.len()`.
    pub fn slice_from(self, lo: usize) -> RcSlice<T> {
        let hi = self.len();
        self.slice(lo, hi)
    }
}

impl<T> Clone for RcSlice<T> {
    fn clone(&self) -> RcSlice<T> {
        RcSlice {
            data: self.data,
            counts: self.counts.clone()
        }
    }
}

impl<T> ops::Deref for RcSlice<T> {
    type Target = [T];
    fn deref<'a>(&'a self) -> &'a [T] {
        unsafe {&*self.data}
    }
}

impl<T> AsRef<[T]> for RcSlice<T> {
    fn as_ref(&self) -> &[T] { &**self }
}

impl<T: PartialEq> PartialEq for RcSlice<T> {
    fn eq(&self, other: &RcSlice<T>) -> bool { **self == **other }
    fn ne(&self, other: &RcSlice<T>) -> bool { **self != **other }
}
impl<T: Eq> Eq for RcSlice<T> {}

impl<T: PartialOrd> PartialOrd for RcSlice<T> {
    fn partial_cmp(&self, other: &RcSlice<T>) -> Option<cmp::Ordering> {
        (**self).partial_cmp(&**other)
    }
    fn lt(&self, other: &RcSlice<T>) -> bool { **self < **other }
    fn le(&self, other: &RcSlice<T>) -> bool { **self <= **other }
    fn gt(&self, other: &RcSlice<T>) -> bool { **self > **other }
    fn ge(&self, other: &RcSlice<T>) -> bool { **self >= **other }
}
impl<T: Ord> Ord for RcSlice<T> {
    fn cmp(&self, other: &RcSlice<T>) -> cmp::Ordering { (**self).cmp(&**other) }
}

impl<T: Hash> Hash for RcSlice<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&**self, state)
    }
}

impl<T: fmt::Debug> fmt::Debug for RcSlice<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<T> WeakSlice<T> {
    /// Attempt to upgrade `self` to a strongly-counted `RcSlice`.
    ///
    /// Returns `None` if this is not possible (the data has already
    /// been freed).
    pub fn upgrade(&self) -> Option<RcSlice<T>> {
        self.counts.upgrade().map(|counts| {
            RcSlice {
                data: self.data,
                counts: counts
            }
        })
    }
}

// only RcSlice needs a destructor, since it entirely controls the
// actual allocated data; the deallocation of the counts (which is the
// only thing a WeakSlice needs to do if it is the very last pointer)
// is already handled by Rc<()>/Weak<()>.
impl<T> Drop for RcSlice<T> {
    fn drop(&mut self) {
        let strong = rc::strong_count(&self.counts);
        if strong == 1 {
            // last one, so let's clean up the stored data
            unsafe {
                let _: Box<[T]> = mem::transmute(self.data);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use super::{RcSlice, WeakSlice};
    use std::cell::Cell;
    use std::cmp::Ordering;

    #[test]
    fn clone() {
        let x = RcSlice::new(Box::new([Cell::new(false)]));
        let y = x.clone();

        assert_eq!(x[0].get(), false);
        assert_eq!(y[0].get(), false);

        x[0].set(true);
        assert_eq!(x[0].get(), true);
        assert_eq!(y[0].get(), true);
    }

    #[test]
    fn test_upgrade_downgrade() {
        let x = RcSlice::new(Box::new([1]));
        let y: WeakSlice<_> = x.downgrade();

        assert_eq!(y.upgrade(), Some(x.clone()));

        drop(x);

        assert!(y.upgrade().is_none())
    }

    #[test]
    fn test_total_cmp() {
        let x = RcSlice::new(Box::new([1, 2, 3]));
        let y = RcSlice::new(Box::new([1, 2, 3]));
        let z = RcSlice::new(Box::new([1, 2, 4]));
        assert_eq!(x, x);
        assert_eq!(x, y);
        assert!(x != z);
        assert!(y != z);

        assert!(x < z);
        assert!(x <= z);
        assert!(!(x > z));
        assert!(!(x >= z));

        assert!(!(z < x));
        assert!(!(z <= x));
        assert!(z > x);
        assert!(z >= x);

        assert_eq!(x.partial_cmp(&x), Some(Ordering::Equal));
        assert_eq!(x.partial_cmp(&y), Some(Ordering::Equal));
        assert_eq!(x.partial_cmp(&z), Some(Ordering::Less));
        assert_eq!(z.partial_cmp(&y), Some(Ordering::Greater));

        assert_eq!(x.cmp(&x), Ordering::Equal);
        assert_eq!(x.cmp(&y), Ordering::Equal);
        assert_eq!(x.cmp(&z), Ordering::Less);
        assert_eq!(z.cmp(&y), Ordering::Greater);
    }

    #[test]
    fn test_partial_cmp() {
        use std::f64;
        let x = RcSlice::new(Box::new([1.0, f64::NAN]));
        let y = RcSlice::new(Box::new([1.0, f64::NAN]));
        let z = RcSlice::new(Box::new([2.0, f64::NAN]));
        let w = RcSlice::new(Box::new([f64::NAN, 1.0]));
        assert!(!(x == y));
        assert!(x != y);

        assert!(!(x < y));
        assert!(!(x <= y));
        assert!(!(x > y));
        assert!(!(x >= y));

        assert!(x < z);
        assert!(x <= z);
        assert!(!(x > z));
        assert!(!(x >= z));

        assert!(!(z < w));
        assert!(!(z <= w));
        assert!(!(z > w));
        assert!(!(z >= w));

        assert_eq!(x.partial_cmp(&x), None);
        assert_eq!(x.partial_cmp(&y), None);
        assert_eq!(x.partial_cmp(&z), Some(Ordering::Less));
        assert_eq!(z.partial_cmp(&x), Some(Ordering::Greater));

        assert_eq!(x.partial_cmp(&w), None);
        assert_eq!(y.partial_cmp(&w), None);
        assert_eq!(z.partial_cmp(&w), None);
        assert_eq!(w.partial_cmp(&w), None);
    }

    #[test]
    fn test_show() {
        let x = RcSlice::new(Box::new([1, 2]));
        assert_eq!(format!("{:?}", x), "[1, 2]");

        let y: RcSlice<i32> = RcSlice::new(Box::new([]));
        assert_eq!(format!("{:?}", y), "[]");
    }

    #[test]
    fn test_slice() {
        let x = RcSlice::new(Box::new([1, 2, 3]));
        let real = [1, 2, 3];
        for i in (0..3 + 1) {
            for j in (i..3 + 1) {
                let slice: RcSlice<_> = x.clone().slice(i, j);
                assert_eq!(&*slice, &real[i..j]);
            }
            assert_eq!(&*x.clone().slice_to(i), &real[..i]);
            assert_eq!(&*x.clone().slice_from(i), &real[i..]);
        }
    }

    #[test]
    fn test_drop() {
        let drop_flag = Rc::new(Cell::new(0));
        struct Foo(Rc<Cell<i32>>);

        impl Drop for Foo {
            fn drop(&mut self) {
                let n = self.0.get();
                self.0.set(n + 1);
            }
        }

        let whole = RcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())]));

        drop(whole);
        assert_eq!(drop_flag.get(), 2);

        drop_flag.set(0);

        let whole = RcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())]));
        let part = whole.slice(1, 2);
        drop(part);
        assert_eq!(drop_flag.get(), 2);
    }
}
<|endoftext|>


<commit_before>//! This module focuses on handling errors generated when using Ardite in a
//! graceful manner.

use std::io::Error as IOError;
use std::error::Error as ErrorTrait;
use std::fmt::{Display, Formatter, Result as FmtResult};

#[cfg(test)]
use regex::Regex;
use serde_json::error::Error as JSONError;
use serde_yaml::error::Error as YAMLError;

use value::{Object, Value};

/// Any error generated by Ardite or it‘s drivers should be output using this
/// type. This allows for a comprehensive display of the error when a service
/// reports it to the user.
///
/// Information included with the error includes an `ErrorCode` (which maps to
/// an HTTP status code), a message, and an optional hint telling the user how
/// to fix the error.
///
/// Typically hints should be included for what would be considered the `4xx`
/// (in HTTP language) class of error codes.
///
/// # Tips For Writing Good Hint Messages
/// - Write in the second person (“You should…”).
/// - Always recommend a solution (“You should try…”, not “You must do…”).
/// - Be as specific as possible, if you have line numbers give them. If you
///   have file paths provide them.
/// - If it is a common error which generally confuses developers, provide a
///   link to a page which better explains the error and specific steps to
///   fix it.
#[derive(PartialEq, Debug)]
pub struct Error {
  /// A specific error code which describes the error.
  code: ErrorCode,
  /// A message providing more detail beyond the error code.
  message: String,
  /// A hint to the user on what to do next to try and avoid the error
  /// happening again. This is optional.
  hint: Option<String>
}

impl Error {
  /// Easily create a new error.
  pub fn new<S>(code: ErrorCode, message: S, hint: Option<S>) -> Self where S: Into<String> {
    Error {
      code: code,
      message: message.into(),
      hint: hint.map(|string| string.into())
    }
  }

  /// Get the code for the error.
  pub fn code(&self) -> &ErrorCode {
    &self.code
  }

  /// Get the message for the error.
  pub fn message(&self) -> &str {
    &self.message
  }

  /// Get the hint—for the error (see what I did there?).
  pub fn hint(&self) -> Option<&str> {
    self.hint.as_ref().map(|s| s.as_str())
  }

  /// Gets an object which represents the error.
  ///
  /// # Example
  /// ```rust
  /// #[macro_use(value)]
  /// extern crate ardite;
  ///
  /// use ardite::error::{Error, NotFound};
  ///
  /// # fn main() {
  ///
  /// let error = Error::new(NotFound, "Not found…", Some("Go to the light!"));
  ///
  /// let value = value!({
  ///   "error" => true,
  ///   "message" => "Not found…",
  ///   "hint" => "Go to the light!"
  /// });
  ///
  /// assert_eq!(error.to_value(), value);
  ///
  /// # }
  /// ```
  pub fn to_value(&self) -> Value {
    let mut object = Object::new();

    // TODO: implement an insert method which isn‘t as strict.
    object.insert("error".to_owned(), Value::Boolean(true));
    object.insert("message".to_owned(), Value::String(self.message.clone()));

    if let Some(ref hint) = self.hint {
      object.insert("hint".to_owned(), Value::String(hint.clone()));
    }

    Value::Object(object)
  }

  /// Convenience function for saying a thing failed validation using
  /// `ErrorCode::BadRequest`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::invalid("Failed validation.", "Try fixing your syntax!");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::BadRequest, "Failed validation.", Some("Try fixing your syntax!")));
  /// ```
  pub fn invalid<S1, S2>(message: S1, hint: S2) -> Self where S1: Into<String>, S2: Into<String> {
    Error {
      code: ErrorCode::BadRequest,
      message: message.into(),
      hint: Some(hint.into())
    }
  }

  /// Convenience function for saying there was an internal error using
  /// `ErrorCode::Internal`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::internal("Something blew up.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::Internal, "Something blew up.", None));
  /// ```
  pub fn internal<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::Internal,
      message: message.into(),
      hint: None
    }
  }

  /// Convenience function for creating an unimplemented error with a plain
  /// message describing what is unimplemented using
  /// `ErrorCode::NotImplemented`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::unimplemented("Cache invalidation is hard.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::NotImplemented, "Cache invalidation is hard.", None));
  /// ```
  pub fn unimplemented<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::NotImplemented,
      message: message.into(),
      hint: None
    }
  }

  /// Special assertion for error messages. Takes a regular expression string
  /// argument which will automatically be constructed into a regualr
  /// expression. Only available in testing environments. Panics if the regular
  /// expression doesn’t match the error message string.
  #[cfg(test)]
  pub fn assert_message(&self, regex_str: &str) {
    if !Regex::new(regex_str).unwrap().is_match(&self.message) {
      panic!("Error message \"{}\" does not match regex /{}/", self.message, regex_str);
    }
  }
}

impl Display for Error {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "\ncode: {}", self.code));
    try!(write!(fmt, "\nmessage: {}", self.message));

    if let Some(ref hint) = self.hint {
      try!(write!(fmt, "\nhint: {}", hint));
    }

    Ok(())
  }
}

impl ErrorTrait for Error {
  fn description(&self) -> &str {
    self.message.as_str()
  }
}

impl From<IOError> for Error {
  fn from(error: IOError) -> Self {
    Error {
      code: ErrorCode::Internal,
      message: error.description().to_owned(),
      hint: None
    }
  }
}

impl From<JSONError> for Error {
  fn from(error: JSONError) -> Self {
    match error {
      JSONError::Syntax(_, line, column) => {
        Error {
          code: ErrorCode::BadRequest,
          message: "Syntax error.".to_owned(),
          hint: Some(format!("Max sure your JSON syntax is correct around line {} column {}.", line, column))
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

impl From<YAMLError> for Error {
  fn from(error: YAMLError) -> Self {
    match error {
      YAMLError::Custom(ref message) => {
        Error {
          code: ErrorCode::BadRequest,
          message: message.to_owned(),
          hint: Some("Make sure your YAML syntax is correct.".to_owned())
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

/// The code of an error. Designed to easily map to [HTTP status codes][1],
/// however only a subset of these codes are supported and some custom codes
/// were added.
///
/// [1]: http://www.restapitutorial.com/httpstatuscodes.html
#[derive(PartialEq, Debug)]
pub enum ErrorCode {
  /// A bad syntax was used.
  BadRequest,
  /// Permissions do not allow this to happen.
  Forbidden,
  /// Resource was not found.
  NotFound,
  /// The requested resource is not acceptable.
  NotAcceptable,
  /// Present data made the request fail.
  Conflict,
  /// There was an invalid range.
  BadRange,
  /// Something bad happened inside a driver.
  Internal,
  /// The feature has not been implemented.
  NotImplemented
}

pub use error::ErrorCode::*;

impl ErrorCode {
  pub fn code(&self) -> u16 {
    match *self {
      BadRequest => 400,
      Forbidden => 403,
      NotFound => 404,
      NotAcceptable => 406,
      Conflict => 409,
      BadRange => 416,
      Internal => 500,
      NotImplemented => 501
    }
  }

  pub fn reason(&self) -> &str {
    match *self {
      BadRequest => "Bad Request",
      Forbidden => "Forbidden",
      NotFound => "Not Found",
      NotAcceptable => "Not Acceptable",
      Conflict => "Conflict",
      BadRange => "Range Not Satisfiable",
      Internal => "Internal Error",
      NotImplemented => "Not Implemented"
    }
  }
}

impl Display for ErrorCode {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "{} {}", self.code(), self.reason()));
    Ok(())
  }
}
<commit_msg>refactor(error): rename error code method<commit_after>//! This module focuses on handling errors generated when using Ardite in a
//! graceful manner.

use std::io::Error as IOError;
use std::error::Error as ErrorTrait;
use std::fmt::{Display, Formatter, Result as FmtResult};

#[cfg(test)]
use regex::Regex;
use serde_json::error::Error as JSONError;
use serde_yaml::error::Error as YAMLError;

use value::{Object, Value};

/// Any error generated by Ardite or it‘s drivers should be output using this
/// type. This allows for a comprehensive display of the error when a service
/// reports it to the user.
///
/// Information included with the error includes an `ErrorCode` (which maps to
/// an HTTP status code), a message, and an optional hint telling the user how
/// to fix the error.
///
/// Typically hints should be included for what would be considered the `4xx`
/// (in HTTP language) class of error codes.
///
/// # Tips For Writing Good Hint Messages
/// - Write in the second person (“You should…”).
/// - Always recommend a solution (“You should try…”, not “You must do…”).
/// - Be as specific as possible, if you have line numbers give them. If you
///   have file paths provide them.
/// - If it is a common error which generally confuses developers, provide a
///   link to a page which better explains the error and specific steps to
///   fix it.
#[derive(PartialEq, Debug)]
pub struct Error {
  /// A specific error code which describes the error.
  code: ErrorCode,
  /// A message providing more detail beyond the error code.
  message: String,
  /// A hint to the user on what to do next to try and avoid the error
  /// happening again. This is optional.
  hint: Option<String>
}

impl Error {
  /// Easily create a new error.
  pub fn new<S>(code: ErrorCode, message: S, hint: Option<S>) -> Self where S: Into<String> {
    Error {
      code: code,
      message: message.into(),
      hint: hint.map(|string| string.into())
    }
  }

  /// Get the code for the error.
  pub fn code(&self) -> &ErrorCode {
    &self.code
  }

  /// Get the message for the error.
  pub fn message(&self) -> &str {
    &self.message
  }

  /// Get the hint—for the error (see what I did there?).
  pub fn hint(&self) -> Option<&str> {
    self.hint.as_ref().map(|s| s.as_str())
  }

  /// Gets an object which represents the error.
  ///
  /// # Example
  /// ```rust
  /// #[macro_use(value)]
  /// extern crate ardite;
  ///
  /// use ardite::error::{Error, NotFound};
  ///
  /// # fn main() {
  ///
  /// let error = Error::new(NotFound, "Not found…", Some("Go to the light!"));
  ///
  /// let value = value!({
  ///   "error" => true,
  ///   "message" => "Not found…",
  ///   "hint" => "Go to the light!"
  /// });
  ///
  /// assert_eq!(error.to_value(), value);
  ///
  /// # }
  /// ```
  pub fn to_value(&self) -> Value {
    let mut object = Object::new();

    // TODO: implement an insert method which isn‘t as strict.
    object.insert("error".to_owned(), Value::Boolean(true));
    object.insert("message".to_owned(), Value::String(self.message.clone()));

    if let Some(ref hint) = self.hint {
      object.insert("hint".to_owned(), Value::String(hint.clone()));
    }

    Value::Object(object)
  }

  /// Convenience function for saying a thing failed validation using
  /// `ErrorCode::BadRequest`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::invalid("Failed validation.", "Try fixing your syntax!");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::BadRequest, "Failed validation.", Some("Try fixing your syntax!")));
  /// ```
  pub fn invalid<S1, S2>(message: S1, hint: S2) -> Self where S1: Into<String>, S2: Into<String> {
    Error {
      code: ErrorCode::BadRequest,
      message: message.into(),
      hint: Some(hint.into())
    }
  }

  /// Convenience function for saying there was an internal error using
  /// `ErrorCode::Internal`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::internal("Something blew up.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::Internal, "Something blew up.", None));
  /// ```
  pub fn internal<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::Internal,
      message: message.into(),
      hint: None
    }
  }

  /// Convenience function for creating an unimplemented error with a plain
  /// message describing what is unimplemented using
  /// `ErrorCode::NotImplemented`.
  ///
  /// # Example
  /// ```rust
  /// use ardite::error::{Error, ErrorCode};
  ///
  /// let error = Error::unimplemented("Cache invalidation is hard.");
  ///
  /// assert_eq!(error, Error::new(ErrorCode::NotImplemented, "Cache invalidation is hard.", None));
  /// ```
  pub fn unimplemented<S>(message: S) -> Self where S: Into<String> {
    Error {
      code: ErrorCode::NotImplemented,
      message: message.into(),
      hint: None
    }
  }

  /// Special assertion for error messages. Takes a regular expression string
  /// argument which will automatically be constructed into a regualr
  /// expression. Only available in testing environments. Panics if the regular
  /// expression doesn’t match the error message string.
  #[cfg(test)]
  pub fn assert_message(&self, regex_str: &str) {
    if !Regex::new(regex_str).unwrap().is_match(&self.message) {
      panic!("Error message \"{}\" does not match regex /{}/", self.message, regex_str);
    }
  }
}

impl Display for Error {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "\ncode: {}", self.code));
    try!(write!(fmt, "\nmessage: {}", self.message));

    if let Some(ref hint) = self.hint {
      try!(write!(fmt, "\nhint: {}", hint));
    }

    Ok(())
  }
}

impl ErrorTrait for Error {
  fn description(&self) -> &str {
    self.message.as_str()
  }
}

impl From<IOError> for Error {
  fn from(error: IOError) -> Self {
    Error {
      code: ErrorCode::Internal,
      message: error.description().to_owned(),
      hint: None
    }
  }
}

impl From<JSONError> for Error {
  fn from(error: JSONError) -> Self {
    match error {
      JSONError::Syntax(_, line, column) => {
        Error {
          code: ErrorCode::BadRequest,
          message: "Syntax error.".to_owned(),
          hint: Some(format!("Max sure your JSON syntax is correct around line {} column {}.", line, column))
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

impl From<YAMLError> for Error {
  fn from(error: YAMLError) -> Self {
    match error {
      YAMLError::Custom(ref message) => {
        Error {
          code: ErrorCode::BadRequest,
          message: message.to_owned(),
          hint: Some("Make sure your YAML syntax is correct.".to_owned())
        }
      },
      _ => {
        Error {
          code: ErrorCode::Internal,
          message: error.description().to_owned(),
          hint: None
        }
      }
    }
  }
}

/// The code of an error. Designed to easily map to [HTTP status codes][1],
/// however only a subset of these codes are supported and some custom codes
/// were added.
///
/// [1]: http://www.restapitutorial.com/httpstatuscodes.html
#[derive(PartialEq, Debug)]
pub enum ErrorCode {
  /// A bad syntax was used.
  BadRequest,
  /// Permissions do not allow this to happen.
  Forbidden,
  /// Resource was not found.
  NotFound,
  /// The requested resource is not acceptable.
  NotAcceptable,
  /// Present data made the request fail.
  Conflict,
  /// There was an invalid range.
  BadRange,
  /// Something bad happened inside a driver.
  Internal,
  /// The feature has not been implemented.
  NotImplemented
}

pub use error::ErrorCode::*;

impl ErrorCode {
  pub fn to_u16(&self) -> u16 {
    match *self {
      BadRequest => 400,
      Forbidden => 403,
      NotFound => 404,
      NotAcceptable => 406,
      Conflict => 409,
      BadRange => 416,
      Internal => 500,
      NotImplemented => 501
    }
  }

  pub fn reason(&self) -> &str {
    match *self {
      BadRequest => "Bad Request",
      Forbidden => "Forbidden",
      NotFound => "Not Found",
      NotAcceptable => "Not Acceptable",
      Conflict => "Conflict",
      BadRange => "Range Not Satisfiable",
      Internal => "Internal Error",
      NotImplemented => "Not Implemented"
    }
  }
}

impl Display for ErrorCode {
  fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
    try!(write!(fmt, "{} {}", self.to_u16(), self.reason()));
    Ok(())
  }
}
<|endoftext|>


<commit_before>use super::error::{ErrorKind, Result, ResultExt};
use super::header::{decode, encode};
use super::{ServicePair, ServiceResult};
use crate::rosmsg::RosMsg;
use byteorder::{LittleEndian, ReadBytesExt};
use std;
use std::collections::HashMap;
use std::io;
use std::io::Write;
use std::net::TcpStream;
use std::sync::Arc;
use std::thread;

pub struct ClientResponse<T> {
    handle: thread::JoinHandle<Result<ServiceResult<T>>>,
}

impl<T> ClientResponse<T> {
    pub fn read(self) -> Result<ServiceResult<T>> {
        self.handle
            .join()
            .unwrap_or_else(|_| Err(ErrorKind::ServiceResponseUnknown.into()))
    }
}

impl<T: Send + 'static> ClientResponse<T> {
    pub fn callback<F>(self, callback: F)
    where
        F: FnOnce(Result<ServiceResult<T>>) + Send + 'static,
    {
        thread::spawn(move || callback(self.read()));
    }
}

struct ClientInfo {
    caller_id: String,
    uri: String,
    service: String,
}

#[derive(Clone)]
pub struct Client<T: ServicePair> {
    info: std::sync::Arc<ClientInfo>,
    phantom: std::marker::PhantomData<T>,
}

fn connect_to_tcp_with_multiple_attempts(uri: &str, attempts: usize) -> std::io::Result<TcpStream> {
    let mut err = std::io::Error::new(
        std::io::ErrorKind::Other,
        "Tried to connect via TCP with 0 connection attempts",
    );
    let mut repeat_delay_ms = 1;
    for _ in 0..attempts {
        match TcpStream::connect(uri) {
            Ok(stream) => {
                return Ok(stream);
            }
            Err(error) => err = error,
        }
        std::thread::sleep(std::time::Duration::from_millis(repeat_delay_ms));
        repeat_delay_ms *= 2;
    }
    Err(err)
}

impl<T: ServicePair> Client<T> {
    pub fn new(caller_id: &str, uri: &str, service: &str) -> Client<T> {
        Client {
            info: std::sync::Arc::new(ClientInfo {
                caller_id: String::from(caller_id),
                uri: String::from(uri),
                service: String::from(service),
            }),
            phantom: std::marker::PhantomData,
        }
    }

    pub fn req(&self, args: &T::Request) -> Result<ServiceResult<T::Response>> {
        Self::request_body(
            args,
            &self.info.uri,
            &self.info.caller_id,
            &self.info.service,
        )
    }

    pub fn req_async(&self, args: T::Request) -> ClientResponse<T::Response> {
        let info = Arc::clone(&self.info);
        ClientResponse {
            handle: thread::spawn(move || {
                Self::request_body(&args, &info.uri, &info.caller_id, &info.service)
            }),
        }
    }

    fn request_body(
        args: &T::Request,
        uri: &str,
        caller_id: &str,
        service: &str,
    ) -> Result<ServiceResult<T::Response>> {
        let trimmed_uri = uri.trim_start_matches("rosrpc://");
        let mut stream = connect_to_tcp_with_multiple_attempts(trimmed_uri, 15)
            .chain_err(|| ErrorKind::ServiceConnectionFail(service.into(), uri.into()))?;

        // Service request starts by exchanging connection headers
        exchange_headers::<T, _>(&mut stream, caller_id, service)?;

        let mut writer = io::Cursor::new(Vec::with_capacity(128));
        // skip the first 4 bytes that will contain the message length
        writer.set_position(4);

        args.encode(&mut writer)?;

        // write the message length to the start of the header
        let message_length = (writer.position() - 4) as u32;
        writer.set_position(0);
        message_length.encode(&mut writer)?;

        // Send request to service
        stream.write_all(&writer.into_inner())?;

        // Service responds with a boolean byte, signalling success
        let success = read_verification_byte(&mut stream)
            .chain_err(|| ErrorKind::ServiceResponseInterruption)?;
        Ok(if success {
            // Decode response as response type upon success

            // TODO: validate response length
            let _length = stream.read_u32::<LittleEndian>();

            Ok(RosMsg::decode(&mut stream)?)
        } else {
            // Decode response as string upon failure
            Err(RosMsg::decode(&mut stream)?)
        })
    }
}

#[inline]
fn read_verification_byte<R: std::io::Read>(reader: &mut R) -> std::io::Result<bool> {
    reader.read_u8().map(|v| v != 0)
}

fn write_request<T, U>(mut stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write,
{
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("callerid"), String::from(caller_id));
    fields.insert(String::from("service"), String::from(service));
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    encode(&mut stream, &fields)?;
    Ok(())
}

fn read_response<T, U>(mut stream: &mut U) -> Result<()>
where
    T: ServicePair,
    U: std::io::Read,
{
    let fields = decode(&mut stream)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    Ok(())
}

fn exchange_headers<T, U>(stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write + std::io::Read,
{
    write_request::<T, U>(stream, caller_id, service)?;
    read_response::<T, U>(stream)
}
<commit_msg>Clean up sockets in client<commit_after>use super::error::{ErrorKind, Result, ResultExt};
use super::header::{decode, encode};
use super::{ServicePair, ServiceResult};
use crate::rosmsg::RosMsg;
use byteorder::{LittleEndian, ReadBytesExt};
use log::error;
use std;
use std::collections::HashMap;
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::sync::Arc;
use std::thread;

pub struct ClientResponse<T> {
    handle: thread::JoinHandle<Result<ServiceResult<T>>>,
}

impl<T> ClientResponse<T> {
    pub fn read(self) -> Result<ServiceResult<T>> {
        self.handle
            .join()
            .unwrap_or_else(|_| Err(ErrorKind::ServiceResponseUnknown.into()))
    }
}

impl<T: Send + 'static> ClientResponse<T> {
    pub fn callback<F>(self, callback: F)
    where
        F: FnOnce(Result<ServiceResult<T>>) + Send + 'static,
    {
        thread::spawn(move || callback(self.read()));
    }
}

struct ClientInfo {
    caller_id: String,
    uri: String,
    service: String,
}

#[derive(Clone)]
pub struct Client<T: ServicePair> {
    info: std::sync::Arc<ClientInfo>,
    phantom: std::marker::PhantomData<T>,
}

fn connect_to_tcp_with_multiple_attempts(uri: &str, attempts: usize) -> io::Result<TcpStream> {
    let mut err = io::Error::new(
        io::ErrorKind::Other,
        "Tried to connect via TCP with 0 connection attempts",
    );
    let mut repeat_delay_ms = 1;
    for _ in 0..attempts {
        match TcpStream::connect(uri) {
            Ok(stream) => {
                return Ok(stream);
            }
            Err(error) => err = error,
        }
        std::thread::sleep(std::time::Duration::from_millis(repeat_delay_ms));
        repeat_delay_ms *= 2;
    }
    Err(err)
}

impl<T: ServicePair> Client<T> {
    pub fn new(caller_id: &str, uri: &str, service: &str) -> Client<T> {
        Client {
            info: std::sync::Arc::new(ClientInfo {
                caller_id: String::from(caller_id),
                uri: String::from(uri),
                service: String::from(service),
            }),
            phantom: std::marker::PhantomData,
        }
    }

    pub fn req(&self, args: &T::Request) -> Result<ServiceResult<T::Response>> {
        Self::request_body(
            args,
            &self.info.uri,
            &self.info.caller_id,
            &self.info.service,
        )
    }

    pub fn req_async(&self, args: T::Request) -> ClientResponse<T::Response> {
        let info = Arc::clone(&self.info);
        ClientResponse {
            handle: thread::spawn(move || {
                Self::request_body(&args, &info.uri, &info.caller_id, &info.service)
            }),
        }
    }

    fn request_body(
        args: &T::Request,
        uri: &str,
        caller_id: &str,
        service: &str,
    ) -> Result<ServiceResult<T::Response>> {
        let trimmed_uri = uri.trim_start_matches("rosrpc://");
        let mut stream = connect_to_tcp_with_multiple_attempts(trimmed_uri, 15)
            .chain_err(|| ErrorKind::ServiceConnectionFail(service.into(), uri.into()))?;

        // Service request starts by exchanging connection headers
        exchange_headers::<T, _>(&mut stream, caller_id, service)?;

        let mut writer = io::Cursor::new(Vec::with_capacity(128));
        // skip the first 4 bytes that will contain the message length
        writer.set_position(4);

        args.encode(&mut writer)?;

        // write the message length to the start of the header
        let message_length = (writer.position() - 4) as u32;
        writer.set_position(0);
        message_length.encode(&mut writer)?;

        // Send request to service
        stream.write_all(&writer.into_inner())?;

        // Service responds with a boolean byte, signalling success
        let success = read_verification_byte(&mut stream)
            .chain_err(|| ErrorKind::ServiceResponseInterruption)?;
        Ok(if success {
            // Decode response as response type upon success

            // TODO: validate response length
            let _length = stream.read_u32::<LittleEndian>();

            let data = RosMsg::decode(&mut stream)?;

            let mut dump = vec![];
            if let Err(err) = stream.read_to_end(&mut dump) {
                error!("Failed to read from TCP stream: {:?}", err)
            }

            Ok(data)
        } else {
            // Decode response as string upon failure
            let data = RosMsg::decode(&mut stream)?;

            let mut dump = vec![];
            if let Err(err) = stream.read_to_end(&mut dump) {
                error!("Failed to read from TCP stream: {:?}", err)
            }

            Err(data)
        })
    }
}

#[inline]
fn read_verification_byte<R: std::io::Read>(reader: &mut R) -> std::io::Result<bool> {
    reader.read_u8().map(|v| v != 0)
}

fn write_request<T, U>(mut stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write,
{
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("callerid"), String::from(caller_id));
    fields.insert(String::from("service"), String::from(service));
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    encode(&mut stream, &fields)?;
    Ok(())
}

fn read_response<T, U>(mut stream: &mut U) -> Result<()>
where
    T: ServicePair,
    U: std::io::Read,
{
    let fields = decode(&mut stream)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    Ok(())
}

fn exchange_headers<T, U>(stream: &mut U, caller_id: &str, service: &str) -> Result<()>
where
    T: ServicePair,
    U: std::io::Write + std::io::Read,
{
    write_request::<T, U>(stream, caller_id, service)?;
    read_response::<T, U>(stream)
}
<|endoftext|>


<commit_before>//! User-input events and their effects.

use std::fmt;
use std::rc::Rc;

use ncurses;

use Cursive;

/// Callback is a function that can be triggered by an event.
/// It has a mutable access to the cursive root.
pub type Callback = Box<Fn(&mut Cursive)>;

/// Answer to an event notification.
/// The event can be consumed or ignored.
pub enum EventResult {
    /// The event was ignored. The parent can keep handling it.
    Ignored,
    /// The event was consumed. An optionnal callback to run is attached.
    Consumed(Option<Rc<Callback>>),
}

/// Represents a key, or a combination of keys.
#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Key {
    /// Both Enter and numpad Enter
    Enter,
    /// Tabulation key
    Tab,
    ShiftTab,
    Backspace,

    /// Escape key.
    Esc,
    /// The 5 in the center of the keypad, when numlock is disabled.
    NumpadCenter,

    Left,
    /// Left arrow while shift is pressed.
    ShiftLeft,
    AltLeft,
    AltShiftLeft,
    CtrlLeft,
    CtrlShiftLeft,
    CtrlAltLeft,

    Right,
    /// Right arrow while shift is pressed.
    ShiftRight,
    AltRight,
    AltShiftRight,
    CtrlRight,
    CtrlShiftRight,
    CtrlAltRight,

    Up,
    ShiftUp,
    AltUp,
    AltShiftUp,
    CtrlUp,
    CtrlShiftUp,
    CtrlAltUp,

    Down,
    ShiftDown,
    AltDown,
    AltShiftDown,
    CtrlDown,
    CtrlShiftDown,
    CtrlAltDown,

    PageUp,
    ShiftPageUp,
    AltPageUp,
    AltShiftPageUp,
    CtrlPageUp,
    CtrlShiftPageUp,
    CtrlAltPageUp,

    PageDown,
    ShiftPageDown,
    AltPageDown,
    AltShiftPageDown,
    CtrlPageDown,
    CtrlShiftPageDown,
    CtrlAltPageDown,

    Home,
    ShiftHome,
    AltHome,
    AltShiftHome,
    CtrlHome,
    CtrlShiftHome,
    CtrlAltHome,

    End,
    ShiftEnd,
    AltEnd,
    AltShiftEnd,
    CtrlEnd,
    CtrlShiftEnd,
    CtrlAltEnd,

    /// Delete key
    Del,
    ShiftDel,
    AltDel,
    AltShiftDel,
    CtrlDel,
    CtrlShiftDel,

    /// Insert key.
    Ins,
    /// Insert key while ctrl is pressed.
    CtrlIns,
    AltIns,
    CtrlAltIns,

    F(u8),
    CtrlF(u8),
    ShiftF(u8),
    CtrlShiftF(u8),
    CtrlChar(char),
    Unknown(i32),
}

impl Key {
    /// Returns the Key enum corresponding to the given ncurses event.
    pub fn from_ncurses(ch: i32) -> Self {
        match ch {
            // Tab is '\t'
            9 => Key::Tab,
            // Treat '\n' and the numpad Enter the same
            10 | ncurses::KEY_ENTER => Key::Enter,
            // This is the escape key when pressed by itself.
            // When used for control sequences, it should have been caught earlier.
            27 => Key::Esc,
            // `Backspace` sends 127, but Ctrl-H sends `Backspace`
            127 | ncurses::KEY_BACKSPACE => Key::Backspace,
            // Values under 256 are chars.

            // Values 512 and above are probably extensions
            // Those keys don't seem to be documented...
            519 => Key::AltDel,
            520 => Key::AltShiftDel,
            521 => Key::CtrlDel,
            522 => Key::CtrlShiftDel,
            // 523: CtrlAltDel?

            // 524?

            525 => Key::AltDown,
            526 => Key::AltShiftDown,
            527 => Key::CtrlDown,
            528 => Key::CtrlShiftDown,
            529 => Key::CtrlAltDown,

            530 => Key::AltEnd,
            531 => Key::AltShiftEnd,
            532 => Key::CtrlEnd,
            533 => Key::CtrlShiftEnd,
            534 => Key::CtrlAltEnd,

            535 => Key::AltHome,
            536 => Key::AltShiftHome,
            537 => Key::CtrlHome,
            538 => Key::CtrlShiftHome,
            539 => Key::CtrlAltHome,

            540 => Key::AltIns,
            // 541: AltShiftIns?
            542 => Key::CtrlIns,
            // 543: CtrlShiftIns?
            544 => Key::CtrlAltIns,

            545 => Key::AltLeft,
            546 => Key::AltShiftLeft,
            547 => Key::CtrlLeft,
            548 => Key::CtrlShiftLeft,
            549 => Key::CtrlAltLeft,

            550 => Key::AltPageDown,
            551 => Key::AltShiftPageDown,
            552 => Key::CtrlPageDown,
            553 => Key::CtrlShiftPageDown,
            554 => Key::CtrlAltPageDown,

            555 => Key::AltPageUp,
            556 => Key::AltShiftPageUp,
            557 => Key::CtrlPageUp,
            558 => Key::CtrlShiftPageUp,
            559 => Key::CtrlAltPageUp,

            560 => Key::AltRight,
            561 => Key::AltShiftRight,
            562 => Key::CtrlRight,
            563 => Key::CtrlShiftRight,
            564 => Key::CtrlAltRight,
            // 565?

            566 => Key::AltUp,
            567 => Key::AltShiftUp,
            568 => Key::CtrlUp,
            569 => Key::CtrlShiftUp,
            570 => Key::CtrlAltUp,

            ncurses::KEY_B2 => Key::NumpadCenter,
            ncurses::KEY_DC => Key::Del,
            ncurses::KEY_IC => Key::Ins,
            ncurses::KEY_BTAB => Key::ShiftTab,
            ncurses::KEY_SLEFT => Key::ShiftLeft,
            ncurses::KEY_SRIGHT => Key::ShiftRight,
            ncurses::KEY_LEFT => Key::Left,
            ncurses::KEY_RIGHT => Key::Right,
            ncurses::KEY_UP => Key::Up,
            ncurses::KEY_DOWN => Key::Down,
            ncurses::KEY_SR => Key::ShiftUp,
            ncurses::KEY_SF => Key::ShiftDown,
            ncurses::KEY_PPAGE => Key::PageUp,
            ncurses::KEY_NPAGE => Key::PageDown,
            ncurses::KEY_HOME => Key::Home,
            ncurses::KEY_END => Key::End,
            ncurses::KEY_SHOME => Key::ShiftHome,
            ncurses::KEY_SEND => Key::ShiftEnd,
            ncurses::KEY_SDC => Key::ShiftDel,
            ncurses::KEY_SNEXT => Key::ShiftPageDown,
            ncurses::KEY_SPREVIOUS => Key::ShiftPageUp,
            // All Fn keys use the same enum with associated number
            f @ ncurses::KEY_F1...ncurses::KEY_F12 => Key::F((f - ncurses::KEY_F0) as u8),
            f @ 277...288 => Key::ShiftF((f - 281 + 5) as u8),
            f @ 289...300 => Key::CtrlF((f - 293 + 5) as u8),
            f @ 301...312 => Key::CtrlShiftF((f - 305 + 5) as u8),
            // Shift and Ctrl F{1-4} need escape sequences...
            //
            // TODO: shift and ctrl Fn keys
            // Avoids 8-10 (H,I,J), they are used by other commands.
            c @ 1...7 | c @ 11...25 => Key::CtrlChar(('a' as u8 + (c - 1) as u8) as char),
            _ => Key::Unknown(ch),
        }
    }
}

impl fmt::Display for Key {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Key::Unknown(ch) => write!(f, "Unknown: {}", ch),
            Key::CtrlChar(ch) => write!(f, "Ctrl-{}", ch),
            Key::F(n) => write!(f, "F{}", n),
            Key::ShiftF(n) => write!(f, "Shift-F{}", n),
            Key::CtrlF(n) => write!(f, "Ctrl-F{}", n),
            Key::CtrlShiftF(n) => write!(f, "Ctrl-Shift-F{}", n),
            key => {
                write!(f,
                       "{}",
                       match key {
                           Key::NumpadCenter => "Numpad center",
                           Key::Backspace => "Backspace",
                           Key::Enter => "Enter",
                           Key::Tab => "Tab",
                           Key::ShiftTab => "Shift-Tab",

                           Key::PageUp => "PageUp",
                           Key::ShiftPageUp => "Shift-PageUp",
                           Key::AltPageUp => "Alt-PageUp",
                           Key::AltShiftPageUp => "Alt-Shift-PageUp",
                           Key::CtrlPageUp => "Ctrl-PageUp",
                           Key::CtrlShiftPageUp => "Ctrl-Shift-PageUp",
                           Key::CtrlAltPageUp => "Ctrl-Alt-PageUp",

                           Key::PageDown => "PageDown",
                           Key::ShiftPageDown => "Shift-PageDown",
                           Key::AltPageDown => "Alt-PageDown",
                           Key::AltShiftPageDown => "Alt-Shift-PageDown",
                           Key::CtrlPageDown => "Ctrl-PageDown",
                           Key::CtrlShiftPageDown => "Ctrl-Shift-PageDown",
                           Key::CtrlAltPageDown => "Ctrl-Alt-PageDown",

                           Key::Left => "Left",
                           Key::ShiftLeft => "Shift-Left",
                           Key::AltLeft => "Alt-Left",
                           Key::AltShiftLeft => "Alt-Shift-Left",
                           Key::CtrlLeft => "Ctrl-Left",
                           Key::CtrlShiftLeft => "Ctrl-Shift-Left",
                           Key::CtrlAltLeft => "Ctrl-Alt-Left",

                           Key::Right => "Right",
                           Key::ShiftRight => "Shift-Right",
                           Key::AltRight => "Alt-Right",
                           Key::AltShiftRight => "Alt-Shift-Right",
                           Key::CtrlRight => "Ctrl-Right",
                           Key::CtrlShiftRight => "Ctrl-Shift-Right",
                           Key::CtrlAltRight => "Ctrl-Alt-Right",

                           Key::Down => "Down",
                           Key::ShiftDown => "Shift-Down",
                           Key::AltDown => "Alt-Down",
                           Key::AltShiftDown => "Alt-Shift-Down",
                           Key::CtrlDown => "Ctrl-Down",
                           Key::CtrlShiftDown => "Ctrl-Shift-Down",
                           Key::CtrlAltDown => "Ctrl-Alt-Down",

                           Key::Up => "Up",
                           Key::ShiftUp => "Shift-Up",
                           Key::AltUp => "Alt-Up",
                           Key::AltShiftUp => "Alt-Shift-Up",
                           Key::CtrlUp => "Ctrl-Up",
                           Key::CtrlShiftUp => "Ctrl-Shift-Up",
                           Key::CtrlAltUp => "Ctrl-Alt-Up",

                           Key::Del => "Del",
                           Key::ShiftDel => "Shift-Del",
                           Key::AltDel => "Alt-Del",
                           Key::AltShiftDel => "Alt-Shift-Del",
                           Key::CtrlDel => "Ctrl-Del",
                           Key::CtrlShiftDel => "Ctrl-Shift-Del",

                           Key::Home => "Home",
                           Key::ShiftHome => "Shift-Home",
                           Key::AltHome => "Alt-Home",
                           Key::AltShiftHome => "Alt-Shift-Home",
                           Key::CtrlHome => "Ctrl-Home",
                           Key::CtrlShiftHome => "Ctrl-Shift-Home",
                           Key::CtrlAltHome => "Ctrl-Alt-Home",

                           Key::End => "End",
                           Key::ShiftEnd => "Shift-End",
                           Key::AltEnd => "Alt-End",
                           Key::AltShiftEnd => "Alt-Shift-End",
                           Key::CtrlEnd => "Ctrl-End",
                           Key::CtrlShiftEnd => "Ctrl-Shift-End",
                           Key::CtrlAltEnd => "Ctrl-Alt-End",

                           Key::Ins => "Ins",
                           Key::AltIns => "Alt-Ins",
                           Key::CtrlIns => "Ctrl-Ins",
                           Key::CtrlAltIns => "Ctrl-Alt-Ins",

                           Key::Esc => "Esc",
                           _ => "Missing key label",
                       })
            }
        }
    }
}

/// Represents an event as seen by the application.
///
#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Event {
    /// A text character was entered.
    CharEvent(char),
    /// A key was pressed.
    KeyEvent(Key),
}

/// Generic trait to convert a value to an event.
pub trait ToEvent {
    fn to_event(self) -> Event;
}

impl ToEvent for char {
    fn to_event(self) -> Event {
        Event::CharEvent(self)
    }
}

impl ToEvent for Key {
    fn to_event(self) -> Event {
        Event::KeyEvent(self)
    }
}

impl ToEvent for Event {
    fn to_event(self) -> Event {
        self
    }
}
<commit_msg>Added a `Resize` event<commit_after>//! User-input events and their effects.

use std::fmt;
use std::rc::Rc;

use ncurses;

use Cursive;

/// Callback is a function that can be triggered by an event.
/// It has a mutable access to the cursive root.
pub type Callback = Box<Fn(&mut Cursive)>;

/// Answer to an event notification.
/// The event can be consumed or ignored.
pub enum EventResult {
    /// The event was ignored. The parent can keep handling it.
    Ignored,
    /// The event was consumed. An optionnal callback to run is attached.
    Consumed(Option<Rc<Callback>>),
}

/// Represents a key, or a combination of keys.
#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Key {
    /// Both Enter and numpad Enter
    Enter,
    /// Tabulation key
    Tab,
    ShiftTab,
    Backspace,

    /// Indicates the window was resized
    ///
    /// (Not really a key)
    Resize,

    /// Escape key.
    Esc,
    /// The 5 in the center of the keypad, when numlock is disabled.
    NumpadCenter,

    Left,
    /// Left arrow while shift is pressed.
    ShiftLeft,
    AltLeft,
    AltShiftLeft,
    CtrlLeft,
    CtrlShiftLeft,
    CtrlAltLeft,

    Right,
    /// Right arrow while shift is pressed.
    ShiftRight,
    AltRight,
    AltShiftRight,
    CtrlRight,
    CtrlShiftRight,
    CtrlAltRight,

    Up,
    ShiftUp,
    AltUp,
    AltShiftUp,
    CtrlUp,
    CtrlShiftUp,
    CtrlAltUp,

    Down,
    ShiftDown,
    AltDown,
    AltShiftDown,
    CtrlDown,
    CtrlShiftDown,
    CtrlAltDown,

    PageUp,
    ShiftPageUp,
    AltPageUp,
    AltShiftPageUp,
    CtrlPageUp,
    CtrlShiftPageUp,
    CtrlAltPageUp,

    PageDown,
    ShiftPageDown,
    AltPageDown,
    AltShiftPageDown,
    CtrlPageDown,
    CtrlShiftPageDown,
    CtrlAltPageDown,

    Home,
    ShiftHome,
    AltHome,
    AltShiftHome,
    CtrlHome,
    CtrlShiftHome,
    CtrlAltHome,

    End,
    ShiftEnd,
    AltEnd,
    AltShiftEnd,
    CtrlEnd,
    CtrlShiftEnd,
    CtrlAltEnd,

    /// Delete key
    Del,
    ShiftDel,
    AltDel,
    AltShiftDel,
    CtrlDel,
    CtrlShiftDel,

    /// Insert key.
    Ins,
    /// Insert key while ctrl is pressed.
    CtrlIns,
    AltIns,
    CtrlAltIns,

    F(u8),
    ShiftF(u8),
    AltF(u8),
    CtrlF(u8),
    CtrlShiftF(u8),
    CtrlChar(char),
    Unknown(i32),
}

impl Key {
    /// Returns the Key enum corresponding to the given ncurses event.
    pub fn from_ncurses(ch: i32) -> Self {
        match ch {
            // Values under 256 are chars and control values

            // Tab is '\t'
            9 => Key::Tab,
            // Treat '\n' and the numpad Enter the same
            10 | ncurses::KEY_ENTER => Key::Enter,
            // This is the escape key when pressed by itself.
            // When used for control sequences, it should have been caught earlier.
            27 => Key::Esc,
            // `Backspace` sends 127, but Ctrl-H sends `Backspace`
            127 | ncurses::KEY_BACKSPACE => Key::Backspace,

            410 => Key::Resize,

            // Values 512 and above are probably extensions
            // Those keys don't seem to be documented...
            519 => Key::AltDel,
            520 => Key::AltShiftDel,
            521 => Key::CtrlDel,
            522 => Key::CtrlShiftDel,
            // 523: CtrlAltDel?

            // 524?

            525 => Key::AltDown,
            526 => Key::AltShiftDown,
            527 => Key::CtrlDown,
            528 => Key::CtrlShiftDown,
            529 => Key::CtrlAltDown,

            530 => Key::AltEnd,
            531 => Key::AltShiftEnd,
            532 => Key::CtrlEnd,
            533 => Key::CtrlShiftEnd,
            534 => Key::CtrlAltEnd,

            535 => Key::AltHome,
            536 => Key::AltShiftHome,
            537 => Key::CtrlHome,
            538 => Key::CtrlShiftHome,
            539 => Key::CtrlAltHome,

            540 => Key::AltIns,
            // 541: AltShiftIns?
            542 => Key::CtrlIns,
            // 543: CtrlShiftIns?
            544 => Key::CtrlAltIns,

            545 => Key::AltLeft,
            546 => Key::AltShiftLeft,
            547 => Key::CtrlLeft,
            548 => Key::CtrlShiftLeft,
            549 => Key::CtrlAltLeft,

            550 => Key::AltPageDown,
            551 => Key::AltShiftPageDown,
            552 => Key::CtrlPageDown,
            553 => Key::CtrlShiftPageDown,
            554 => Key::CtrlAltPageDown,

            555 => Key::AltPageUp,
            556 => Key::AltShiftPageUp,
            557 => Key::CtrlPageUp,
            558 => Key::CtrlShiftPageUp,
            559 => Key::CtrlAltPageUp,

            560 => Key::AltRight,
            561 => Key::AltShiftRight,
            562 => Key::CtrlRight,
            563 => Key::CtrlShiftRight,
            564 => Key::CtrlAltRight,
            // 565?

            566 => Key::AltUp,
            567 => Key::AltShiftUp,
            568 => Key::CtrlUp,
            569 => Key::CtrlShiftUp,
            570 => Key::CtrlAltUp,

            ncurses::KEY_B2 => Key::NumpadCenter,
            ncurses::KEY_DC => Key::Del,
            ncurses::KEY_IC => Key::Ins,
            ncurses::KEY_BTAB => Key::ShiftTab,
            ncurses::KEY_SLEFT => Key::ShiftLeft,
            ncurses::KEY_SRIGHT => Key::ShiftRight,
            ncurses::KEY_LEFT => Key::Left,
            ncurses::KEY_RIGHT => Key::Right,
            ncurses::KEY_UP => Key::Up,
            ncurses::KEY_DOWN => Key::Down,
            ncurses::KEY_SR => Key::ShiftUp,
            ncurses::KEY_SF => Key::ShiftDown,
            ncurses::KEY_PPAGE => Key::PageUp,
            ncurses::KEY_NPAGE => Key::PageDown,
            ncurses::KEY_HOME => Key::Home,
            ncurses::KEY_END => Key::End,
            ncurses::KEY_SHOME => Key::ShiftHome,
            ncurses::KEY_SEND => Key::ShiftEnd,
            ncurses::KEY_SDC => Key::ShiftDel,
            ncurses::KEY_SNEXT => Key::ShiftPageDown,
            ncurses::KEY_SPREVIOUS => Key::ShiftPageUp,
            // All Fn keys use the same enum with associated number
            f @ ncurses::KEY_F1...ncurses::KEY_F12 => Key::F((f - ncurses::KEY_F0) as u8),
            f @ 277...288 => Key::ShiftF((f - 277) as u8),
            f @ 289...300 => Key::CtrlF((f - 289) as u8),
            f @ 301...312 => Key::CtrlShiftF((f - 300) as u8),
            f @ 313...324 => Key::AltF((f - 313) as u8),
            // Shift and Ctrl F{1-4} need escape sequences...
            //
            // TODO: shift and ctrl Fn keys
            // Avoids 8-10 (H,I,J), they are used by other commands.
            c @ 1...7 | c @ 11...25 => Key::CtrlChar(('a' as u8 + (c - 1) as u8) as char),
            _ => Key::Unknown(ch),
        }
    }
}

impl fmt::Display for Key {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Key::Unknown(ch) => write!(f, "Unknown: {}", ch),
            Key::CtrlChar(ch) => write!(f, "Ctrl-{}", ch),
            Key::F(n) => write!(f, "F{}", n),
            Key::ShiftF(n) => write!(f, "Shift-F{}", n),
            Key::AltF(n) => write!(f, "Alt-F{}", n),
            Key::CtrlF(n) => write!(f, "Ctrl-F{}", n),
            Key::CtrlShiftF(n) => write!(f, "Ctrl-Shift-F{}", n),
            key => {
                write!(f,
                       "{}",
                       match key {
                           Key::Resize => "Screen resize",
                           Key::NumpadCenter => "Numpad center",
                           Key::Backspace => "Backspace",
                           Key::Enter => "Enter",
                           Key::Tab => "Tab",
                           Key::ShiftTab => "Shift-Tab",

                           Key::PageUp => "PageUp",
                           Key::ShiftPageUp => "Shift-PageUp",
                           Key::AltPageUp => "Alt-PageUp",
                           Key::AltShiftPageUp => "Alt-Shift-PageUp",
                           Key::CtrlPageUp => "Ctrl-PageUp",
                           Key::CtrlShiftPageUp => "Ctrl-Shift-PageUp",
                           Key::CtrlAltPageUp => "Ctrl-Alt-PageUp",

                           Key::PageDown => "PageDown",
                           Key::ShiftPageDown => "Shift-PageDown",
                           Key::AltPageDown => "Alt-PageDown",
                           Key::AltShiftPageDown => "Alt-Shift-PageDown",
                           Key::CtrlPageDown => "Ctrl-PageDown",
                           Key::CtrlShiftPageDown => "Ctrl-Shift-PageDown",
                           Key::CtrlAltPageDown => "Ctrl-Alt-PageDown",

                           Key::Left => "Left",
                           Key::ShiftLeft => "Shift-Left",
                           Key::AltLeft => "Alt-Left",
                           Key::AltShiftLeft => "Alt-Shift-Left",
                           Key::CtrlLeft => "Ctrl-Left",
                           Key::CtrlShiftLeft => "Ctrl-Shift-Left",
                           Key::CtrlAltLeft => "Ctrl-Alt-Left",

                           Key::Right => "Right",
                           Key::ShiftRight => "Shift-Right",
                           Key::AltRight => "Alt-Right",
                           Key::AltShiftRight => "Alt-Shift-Right",
                           Key::CtrlRight => "Ctrl-Right",
                           Key::CtrlShiftRight => "Ctrl-Shift-Right",
                           Key::CtrlAltRight => "Ctrl-Alt-Right",

                           Key::Down => "Down",
                           Key::ShiftDown => "Shift-Down",
                           Key::AltDown => "Alt-Down",
                           Key::AltShiftDown => "Alt-Shift-Down",
                           Key::CtrlDown => "Ctrl-Down",
                           Key::CtrlShiftDown => "Ctrl-Shift-Down",
                           Key::CtrlAltDown => "Ctrl-Alt-Down",

                           Key::Up => "Up",
                           Key::ShiftUp => "Shift-Up",
                           Key::AltUp => "Alt-Up",
                           Key::AltShiftUp => "Alt-Shift-Up",
                           Key::CtrlUp => "Ctrl-Up",
                           Key::CtrlShiftUp => "Ctrl-Shift-Up",
                           Key::CtrlAltUp => "Ctrl-Alt-Up",

                           Key::Del => "Del",
                           Key::ShiftDel => "Shift-Del",
                           Key::AltDel => "Alt-Del",
                           Key::AltShiftDel => "Alt-Shift-Del",
                           Key::CtrlDel => "Ctrl-Del",
                           Key::CtrlShiftDel => "Ctrl-Shift-Del",

                           Key::Home => "Home",
                           Key::ShiftHome => "Shift-Home",
                           Key::AltHome => "Alt-Home",
                           Key::AltShiftHome => "Alt-Shift-Home",
                           Key::CtrlHome => "Ctrl-Home",
                           Key::CtrlShiftHome => "Ctrl-Shift-Home",
                           Key::CtrlAltHome => "Ctrl-Alt-Home",

                           Key::End => "End",
                           Key::ShiftEnd => "Shift-End",
                           Key::AltEnd => "Alt-End",
                           Key::AltShiftEnd => "Alt-Shift-End",
                           Key::CtrlEnd => "Ctrl-End",
                           Key::CtrlShiftEnd => "Ctrl-Shift-End",
                           Key::CtrlAltEnd => "Ctrl-Alt-End",

                           Key::Ins => "Ins",
                           Key::AltIns => "Alt-Ins",
                           Key::CtrlIns => "Ctrl-Ins",
                           Key::CtrlAltIns => "Ctrl-Alt-Ins",

                           Key::Esc => "Esc",
                           _ => "Missing key label",
                       })
            }
        }
    }
}

/// Represents an event as seen by the application.
///
#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Event {
    /// A text character was entered.
    CharEvent(char),
    /// A key was pressed.
    KeyEvent(Key),
}

/// Generic trait to convert a value to an event.
pub trait ToEvent {
    fn to_event(self) -> Event;
}

impl ToEvent for char {
    fn to_event(self) -> Event {
        Event::CharEvent(self)
    }
}

impl ToEvent for Key {
    fn to_event(self) -> Event {
        Event::KeyEvent(self)
    }
}

impl ToEvent for Event {
    fn to_event(self) -> Event {
        self
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate unicode_segmentation;

use std::cmp;
use self::unicode_segmentation::UnicodeSegmentation;
use self::walkdir::WalkDir;

pub fn find_duplicates(dir: &str, expected_dist: i32) {
    let paths = get_paths(dir);
    for i in 0..paths.len() {
        let mut duplicates: Vec<&NamePath> = vec![];
        let ref path1 = paths[i];
        for j in (i + 1)..paths.len() {
            let ref path2 = paths[j];
            let dist = edit_distance(&path1.name, &path2.name);
            if dist <= expected_dist {
                duplicates.push(path2);
            }
        }
        if duplicates.len() > 0 {
            println!("-----------------------------------------------------------------------");
            println!("* {} --> {} *", path1.name, path1.path);
            println!("-----------------------------------------------------------------------");
            for dupe in duplicates {
                println!("- Possible duplicate: {} --> {}", dupe.name, dupe.path);
            }
        }
    }
}

fn edit_distance(str1: &str, str2: &str) -> i32 {
    let str1_vec = UnicodeSegmentation::graphemes(str1, true).collect::<Vec<&str>>();
    let str2_vec = UnicodeSegmentation::graphemes(str2, true).collect::<Vec<&str>>();
    let str1_size = str1_vec.len() + 1;
    let str2_size = str2_vec.len() + 1;
    let mut dp = vec![vec![0; str2_size]; str1_size];
    for i in 0..str1_size {
        for j in 0..str2_size {
            if i == 0 {
                dp[i][j] = j;
            } else if j == 0 {
                dp[i][j] = i;
            } else if str1_vec[i - 1] == str2_vec[j - 1] {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = 1 + cmp::min(
                    dp[i][j - 1],
                    cmp::min(dp[i - 1][j],
                        dp[i - 1][j - 1]));
            }
        }
    }
    dp[str1_size - 1 as usize][str2_size - 1 as usize] as i32
}

#[derive(Debug)]
struct NamePath {
    name: String,
    path: String,
}

fn get_paths<'a>(dir: &str) -> Vec<NamePath> {
    let mut name_paths: Vec<NamePath> = vec![];
    let walker = WalkDir::new(dir).into_iter();
    for entry in walker.filter_map(|e| e.ok()) {
        let path = entry.path();
        if path.is_file() {
            // TODO: deal with unwrap
            let name_path = NamePath{
                name: path.file_name().unwrap().to_str().unwrap().to_string(),
                path: path.to_str().unwrap().to_string(),
            };
            name_paths.push(name_path);
        }
    }
    name_paths
}

#[cfg(test)]
mod test {
    use fdupe;
    use std::path::Path;

    #[test]
    fn test_edit_distance() {
        assert_eq!(2, fdupe::edit_distance("hello", "holla"));
        assert_eq!(2, fdupe::edit_distance("hell", "holla"));
        assert_eq!(3, fdupe::edit_distance("abc", "def"));
        assert_eq!(1, fdupe::edit_distance("忠犬ハチ公", "忠犬ハチ"));
        assert_eq!(2, fdupe::edit_distance("犬ハチ公", "忠犬ハチ"));
    }

    #[test]
    fn test_get_paths() {
        assert_eq!(5, fdupe::get_paths(Path::new("src").join("testdata").to_str().unwrap()).len());
    }

    #[test]
    fn test_find_duplicates() {
        fdupe::find_duplicates(Path::new("src").join("testdata").to_str().unwrap(), 3);
    }
}<commit_msg>Remove TODO<commit_after>extern crate walkdir;
extern crate unicode_segmentation;

use std::cmp;
use self::unicode_segmentation::UnicodeSegmentation;
use self::walkdir::WalkDir;

pub fn find_duplicates(dir: &str, expected_dist: i32) {
    let paths = get_paths(dir);
    for i in 0..paths.len() {
        let mut duplicates: Vec<&NamePath> = vec![];
        let ref path1 = paths[i];
        for j in (i + 1)..paths.len() {
            let ref path2 = paths[j];
            let dist = edit_distance(&path1.name, &path2.name);
            if dist <= expected_dist {
                duplicates.push(path2);
            }
        }
        if duplicates.len() > 0 {
            println!("-----------------------------------------------------------------------");
            println!("* {} --> {} *", path1.name, path1.path);
            println!("-----------------------------------------------------------------------");
            for dupe in duplicates {
                println!("- Possible duplicate: {} --> {}", dupe.name, dupe.path);
            }
        }
    }
}

fn edit_distance(str1: &str, str2: &str) -> i32 {
    let str1_vec = UnicodeSegmentation::graphemes(str1, true).collect::<Vec<&str>>();
    let str2_vec = UnicodeSegmentation::graphemes(str2, true).collect::<Vec<&str>>();
    let str1_size = str1_vec.len() + 1;
    let str2_size = str2_vec.len() + 1;
    let mut dp = vec![vec![0; str2_size]; str1_size];
    for i in 0..str1_size {
        for j in 0..str2_size {
            if i == 0 {
                dp[i][j] = j;
            } else if j == 0 {
                dp[i][j] = i;
            } else if str1_vec[i - 1] == str2_vec[j - 1] {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = 1 + cmp::min(
                    dp[i][j - 1],
                    cmp::min(dp[i - 1][j],
                        dp[i - 1][j - 1]));
            }
        }
    }
    dp[str1_size - 1 as usize][str2_size - 1 as usize] as i32
}

#[derive(Debug)]
struct NamePath {
    name: String,
    path: String,
}

fn get_paths<'a>(dir: &str) -> Vec<NamePath> {
    let mut name_paths: Vec<NamePath> = vec![];
    let walker = WalkDir::new(dir).into_iter();
    for entry in walker.filter_map(|e| e.ok()) {
        let path = entry.path();
        if path.is_file() {
            let name_path = NamePath{
                name: path.file_name().unwrap().to_str().unwrap().to_string(),
                path: path.to_str().unwrap().to_string(),
            };
            name_paths.push(name_path);
        }
    }
    name_paths
}

#[cfg(test)]
mod test {
    use fdupe;
    use std::path::Path;

    #[test]
    fn test_edit_distance() {
        assert_eq!(2, fdupe::edit_distance("hello", "holla"));
        assert_eq!(2, fdupe::edit_distance("hell", "holla"));
        assert_eq!(3, fdupe::edit_distance("abc", "def"));
        assert_eq!(1, fdupe::edit_distance("忠犬ハチ公", "忠犬ハチ"));
        assert_eq!(2, fdupe::edit_distance("犬ハチ公", "忠犬ハチ"));
    }

    #[test]
    fn test_get_paths() {
        assert_eq!(5, fdupe::get_paths(Path::new("src").join("testdata").to_str().unwrap()).len());
    }

    #[test]
    fn test_find_duplicates() {
        fdupe::find_duplicates(Path::new("src").join("testdata").to_str().unwrap(), 3);
    }
}<|endoftext|>