<commit_before>use std::collections::HashMap;
use std::iter::Iterator;
use std::cmp;

const DATA: &'static str = include_str!("../data/input_14.txt");

pub fn main() -> Vec<String> {
    let s1 = race(DATA, 2503);
    let s2 = race_2(DATA, 2503);
    vec![s1.to_string(), s2.to_string()]
}

struct Reindeer {
    name: String,
    speed: usize,
    stamina: usize,
    rest: usize,
}

impl Reindeer {
    fn from_str(input: &str) -> Reindeer {
        let (name, speed, stamina, rest) = scan_fmt!(input,
                                                     "{} can fly {d} km/s for {d} seconds, but \
                                                      then must rest for {d} seconds.",
                                                     String,
                                                     usize,
                                                     usize,
                                                     usize);
        Reindeer {
            name: name.unwrap(),
            speed: speed.unwrap(),
            stamina: stamina.unwrap(),
            rest: rest.unwrap(),
        }
    }

    fn speed_at_time(&self, second: usize) -> usize {
        // a reindeer flies in a cycle of full speed and rest
        // figure out where in the reindeers individual cycle it is
        // to determine out how fast it travels in any particular second
        let cycle = self.stamina + self.rest;
        if (second % cycle) < self.stamina {
            self.speed
        } else {
            0
        }
    }

    fn distance_at_time(&self, second: usize) -> usize {
        (0..second).map(|t| self.speed_at_time(t)).sum()
    }
}

fn race(input: &str, seconds: usize) -> usize {
    input.lines()
         .map(|line| Reindeer::from_str(line))
         .map(|r| r.distance_at_time(seconds))
         .max()
         .unwrap()
}

fn race_2(input: &str, seconds: usize) -> usize {
    let reindeer = input.lines()
                        .map(|line| Reindeer::from_str(line))
                        .collect::<Vec<_>>();
    let mut scorecard: HashMap<&str, (usize, usize)> = HashMap::new();
    for r in reindeer.iter() {
        scorecard.insert(&r.name[..], (0usize, 0));
    }

    let mut furthest = 0;
    for t in 0..seconds {
        for r in reindeer.iter() {
            if let Some(&mut (_, ref mut distance)) = scorecard.get_mut(&r.name[..]) {
                // *distance = r.distance_at_time(t+1);
                *distance += r.speed_at_time(t);
                furthest = cmp::max(furthest, *distance);
            }
        }
        for r in reindeer.iter() {
            if let Some(&mut (ref mut score, ref distance)) = scorecard.get_mut(&r.name[..]) {
                if *distance == furthest {
                    *score += 1;
                }
            }
        }
    }
    let winner = scorecard.iter()
                          .max_by_key(|&(_, v)| v.0)
                          .unwrap();
    (winner.1).0
}

#[test]
fn test_day14() {
    let input = ["Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.",
                 "Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds."]
                    .join("\n");
    assert_eq!(race(&input, 1000), 1120);
    assert_eq!(race_2(&input, 1000), 689);
}
<commit_msg>day 14: parsing and error handling cleanups<commit_after>use std::collections::HashMap;
use std::iter::Iterator;
use std::cmp;

const DATA: &'static str = include_str!("../data/input_14.txt");

pub fn main() -> Vec<String> {
    let s1 = race(DATA, 2503);
    let s2 = race_2(DATA, 2503);
    vec![s1.to_string(), s2.to_string()]
}

struct Reindeer {
    name: String,
    speed: usize,
    stamina: usize,
    rest: usize,
}

impl Reindeer {
    fn from_str(input: &str) -> Option<Reindeer> {
        if let (Some(name), Some(speed), Some(stamina), Some(rest)) = scan_fmt!(input,
                                                                                "{} can fly {d} \
                                                                                km/s for {d} \
                                                                                seconds, but \
                                                                                then must rest \
                                                                                for {d} seconds\
                                                                                .",
                                                                                String,
                                                                                usize,
                                                                                usize,
                                                                                usize) {
            Some(Reindeer {
                name: name,
                speed: speed,
                stamina: stamina,
                rest: rest,
            })
        } else {
            None
        }
    }

    fn speed_at_time(&self, second: usize) -> usize {
        // a reindeer flies in a cycle of full speed and rest
        // figure out where in the reindeers individual cycle it is
        // to determine out how fast it travels in any particular second
        let cycle = self.stamina + self.rest;
        if (second % cycle) < self.stamina {
            self.speed
        } else {
            0
        }
    }

    fn distance_at_time(&self, second: usize) -> usize {
        (0..second).map(|t| self.speed_at_time(t)).sum()
    }
}

fn race(input: &str, seconds: usize) -> usize {
    input.lines()
         .filter_map(|line| Reindeer::from_str(line))
         .map(|r| r.distance_at_time(seconds))
         .max()
         .unwrap_or(0)
}

fn race_2(input: &str, seconds: usize) -> usize {
    let reindeer = input.lines()
                        .filter_map(|line| Reindeer::from_str(line))
                        .collect::<Vec<_>>();
    let mut scorecard: HashMap<&str, (usize, usize)> = HashMap::new();
    for r in reindeer.iter() {
        scorecard.insert(&r.name[..], (0usize, 0));
    }

    let mut furthest = 0;
    for t in 0..seconds {
        for r in reindeer.iter() {
            if let Some(&mut (_, ref mut distance)) = scorecard.get_mut(&r.name[..]) {
                // *distance = r.distance_at_time(t+1);
                *distance += r.speed_at_time(t);
                furthest = cmp::max(furthest, *distance);
            }
        }
        for r in reindeer.iter() {
            if let Some(&mut (ref mut score, ref distance)) = scorecard.get_mut(&r.name[..]) {
                if *distance == furthest {
                    *score += 1;
                }
            }
        }
    }
    if let Some(winner) = scorecard.iter()
                                   .max_by_key(|&(_, v)| v.0) {
        (winner.1).0
    } else {
        0
    }
}

#[cfg(test)]
mod test {
    use super::{race, race_2};

    #[test]
    fn test_day14() {
        let input = ["Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds.",
                     "Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds."]
                        .join("\n");
        assert_eq!(race(&input, 1000), 1120);
        assert_eq!(race_2(&input, 1000), 689);
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use Error;
use Object;
use Runtime;
use Variable;
use RustObject;

pub fn obj_field<T: PopVariable>(rt: &Runtime, obj: &Object, name: &str) -> Result<T, String> {
    let var = try!(obj.get(&Arc::new(name.into()))
        .ok_or_else(|| format!("Object has no key `{}`", name)));
    PopVariable::pop_var(rt, var)
}

/// Implemented by types that can be popped from the runtime stack.
pub trait PopVariable: Sized {
    /// Converts variable to self.
    /// The variable should be resolved before call.
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String>;
}

/// Implemented by types that can be pushed to the runtime stack.
pub trait PushVariable {
    /// Converts from self to variable.
    fn push_var(&self) -> Variable;
}

/// Implemented by types that can be converted to and from vec4.
pub trait ConvertVec4: Sized {
    /// Converts vec4 to self.
    fn from(val: [f32; 4]) -> Self;
    fn to(&self) -> [f32; 4];
}

impl PopVariable for Variable {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        Ok(var.deep_clone(&rt.stack))
    }
}

impl PopVariable for RustObject {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::RustObject(ref robj) = var {
            Ok(robj.clone())
        } else {
            Err(rt.expected(var, "rust_object"))
        }
    }
}

impl PopVariable for String {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Text(ref s) = var {
            Ok((&**s).clone())
        } else {
            Err(rt.expected(var, "string"))
        }
    }
}

impl PopVariable for Arc<String> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Text(ref s) = var {
            Ok(s.clone())
        } else {
            Err(rt.expected(var, "string"))
        }
    }
}

impl PopVariable for u32 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n as u32)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl PopVariable for usize {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n as usize)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl PopVariable for f32 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n as f32)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl PopVariable for f64 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl<T: PopVariable> PopVariable for Option<T> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Option(ref s) = var {
            Ok(match *s {
                Some(ref s) => Some(try!(PopVariable::pop_var(rt, rt.resolve(s)))),
                None => None
            })
        } else {
            Err(rt.expected(var, "option"))
        }
    }
}

impl<T: PopVariable, U: PopVariable> PopVariable for Result<T, U> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Result(ref s) = var {
            Ok(match *s {
                Ok(ref s) => Ok(try!(PopVariable::pop_var(rt, rt.resolve(s)))),
                Err(ref err) => Err(try!(PopVariable::pop_var(rt, rt.resolve(&err.message))))
            })
        } else {
            Err(rt.expected(var, "result"))
        }
    }
}

impl<T: PopVariable> PopVariable for [T; 2] {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok([
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1])))
            ])
        } else {
            Err(rt.expected(var, "[_; 2]"))
        }
    }
}

impl<T: PopVariable> PopVariable for [T; 3] {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok([
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2])))
            ])
        } else {
            Err(rt.expected(var, "[_; 3]"))
        }
    }
}

impl<T: PopVariable> PopVariable for [T; 4] {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok([
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[3])))
            ])
        } else {
            Err(rt.expected(var, "[_; 4]"))
        }
    }
}

impl<T: PopVariable, U: PopVariable> PopVariable for (T, U) {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok((
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1])))
            ))
        } else {
            Err(rt.expected(var, "[_; 2]"))
        }
    }
}

impl<T: PopVariable, U: PopVariable, V: PopVariable> PopVariable for (T, U, V) {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok((
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2])))
            ))
        } else {
            Err(rt.expected(var, "[_; 3]"))
        }
    }
}

impl<T: PopVariable, U: PopVariable, V: PopVariable, W: PopVariable> PopVariable for (T, U, V, W) {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok((
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[3])))
            ))
        } else {
            Err(rt.expected(var, "[_; 4]"))
        }
    }
}

impl<T: PopVariable> PopVariable for Vec<T> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            let mut res = Vec::with_capacity(arr.len());
            for it in &**arr {
                res.push(try!(PopVariable::pop_var(rt, rt.resolve(it))))
            }
            Ok(res)
        } else {
            Err(rt.expected(var, "array"))
        }
    }
}

impl PushVariable for Variable {
    fn push_var(&self) -> Variable { self.clone() }
}

impl PushVariable for RustObject {
    fn push_var(&self) -> Variable {
        Variable::RustObject(self.clone())
    }
}

impl PushVariable for bool {
    fn push_var(&self) -> Variable { Variable::bool(*self) }
}

impl PushVariable for u32 {
    fn push_var(&self) -> Variable { Variable::f64(*self as f64) }
}

impl PushVariable for usize {
    fn push_var(&self) -> Variable { Variable::f64(*self as f64) }
}

impl PushVariable for f32 {
    fn push_var(&self) -> Variable { Variable::f64(*self as f64) }
}

impl PushVariable for f64 {
    fn push_var(&self) -> Variable { Variable::f64(*self) }
}

impl PushVariable for str {
    fn push_var(&self) -> Variable { Variable::Text(Arc::new(self.into())) }
}

impl PushVariable for String {
    fn push_var(&self) -> Variable { Variable::Text(Arc::new(self.clone())) }
}

impl PushVariable for Arc<String> {
    fn push_var(&self) -> Variable { Variable::Text(self.clone()) }
}

impl<T: PushVariable> PushVariable for Option<T> {
    fn push_var(&self) -> Variable {
        Variable::Option(self.as_ref().map(|v| Box::new(v.push_var())))
    }
}

impl<T: PushVariable, U: PushVariable> PushVariable for Result<T, U> {
    fn push_var(&self) -> Variable {
        Variable::Result(self.as_ref()
            .map(|v| Box::new(v.push_var()))
            .map_err(|e| Box::new(Error { message: e.push_var(), trace: vec![] })))
    }
}

impl<T: PushVariable> PushVariable for [T; 2] {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self[0].push_var(),
            self[1].push_var()
        ]))
    }
}

impl<T: PushVariable> PushVariable for [T; 3] {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self[0].push_var(),
            self[1].push_var(),
            self[2].push_var()
        ]))
    }
}

impl<T: PushVariable> PushVariable for [T; 4] {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self[0].push_var(),
            self[1].push_var(),
            self[2].push_var(),
            self[3].push_var()
        ]))
    }
}

impl<T: PushVariable, U: PushVariable> PushVariable for (T, U) {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self.0.push_var(),
            self.1.push_var()
        ]))
    }
}

impl<T: PushVariable, U: PushVariable, V: PushVariable> PushVariable for (T, U, V) {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self.0.push_var(),
            self.1.push_var(),
            self.2.push_var()
        ]))
    }
}

impl<T: PushVariable, U: PushVariable, V: PushVariable, W: PushVariable>
PushVariable for (T, U, V, W) {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self.0.push_var(),
            self.1.push_var(),
            self.2.push_var(),
            self.3.push_var()
        ]))
    }
}

impl<T: PushVariable> PushVariable for Vec<T> {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(self.iter().map(|it| it.push_var()).collect()))
    }
}

impl ConvertVec4 for [f32; 2] {
    fn from(val: [f32; 4]) -> Self { [val[0], val[1]] }
    fn to(&self) -> [f32; 4] { [self[0], self[1], 0.0, 0.0] }
}

impl ConvertVec4 for [f32; 3] {
    fn from(val: [f32; 4]) -> Self { [val[0], val[1], val[2]] }
    fn to(&self) -> [f32; 4] { [self[0], self[1], self[2], 0.0] }
}

impl ConvertVec4 for [f32; 4] {
    fn from(val: [f32; 4]) -> Self { val }
    fn to(&self) -> [f32; 4] { *self }
}

impl ConvertVec4 for [f64; 2] {
    fn from(val: [f32; 4]) -> Self { [val[0] as f64, val[1] as f64] }
    fn to(&self) -> [f32; 4] { [self[0] as f32, self[1] as f32, 0.0, 0.0] }
}

impl ConvertVec4 for [f64; 3] {
    fn from(val: [f32; 4]) -> Self { [val[0] as f64, val[1] as f64, val[2] as f64] }
    fn to(&self) -> [f32; 4] { [self[0] as f32, self[1] as f32, self[2] as f32, 0.0] }
}

impl ConvertVec4 for [f64; 4] {
    fn from(val: [f32; 4]) -> Self { [val[0] as f64, val[1] as f64, val[2] as f64, val[3] as f64] }
    fn to(&self) -> [f32; 4] { [self[0] as f32, self[1] as f32, self[2] as f32, self[3] as f32] }
}
<commit_msg>Implement `PopVariable` for `bool`<commit_after>use std::sync::Arc;

use Error;
use Object;
use Runtime;
use Variable;
use RustObject;

pub fn obj_field<T: PopVariable>(rt: &Runtime, obj: &Object, name: &str) -> Result<T, String> {
    let var = try!(obj.get(&Arc::new(name.into()))
        .ok_or_else(|| format!("Object has no key `{}`", name)));
    PopVariable::pop_var(rt, var)
}

/// Implemented by types that can be popped from the runtime stack.
pub trait PopVariable: Sized {
    /// Converts variable to self.
    /// The variable should be resolved before call.
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String>;
}

/// Implemented by types that can be pushed to the runtime stack.
pub trait PushVariable {
    /// Converts from self to variable.
    fn push_var(&self) -> Variable;
}

/// Implemented by types that can be converted to and from vec4.
pub trait ConvertVec4: Sized {
    /// Converts vec4 to self.
    fn from(val: [f32; 4]) -> Self;
    fn to(&self) -> [f32; 4];
}

impl PopVariable for Variable {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        Ok(var.deep_clone(&rt.stack))
    }
}

impl PopVariable for RustObject {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::RustObject(ref robj) = var {
            Ok(robj.clone())
        } else {
            Err(rt.expected(var, "rust_object"))
        }
    }
}

impl PopVariable for bool {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Bool(b, _) = var {
            Ok(b)
        } else {
            Err(rt.expected(var, "bool"))
        }
    }
}

impl PopVariable for String {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Text(ref s) = var {
            Ok((&**s).clone())
        } else {
            Err(rt.expected(var, "string"))
        }
    }
}

impl PopVariable for Arc<String> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Text(ref s) = var {
            Ok(s.clone())
        } else {
            Err(rt.expected(var, "string"))
        }
    }
}

impl PopVariable for u32 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n as u32)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl PopVariable for usize {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n as usize)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl PopVariable for f32 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n as f32)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl PopVariable for f64 {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::F64(n, _) = var {
            Ok(n)
        } else {
            Err(rt.expected(var, "number"))
        }
    }
}

impl<T: PopVariable> PopVariable for Option<T> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Option(ref s) = var {
            Ok(match *s {
                Some(ref s) => Some(try!(PopVariable::pop_var(rt, rt.resolve(s)))),
                None => None
            })
        } else {
            Err(rt.expected(var, "option"))
        }
    }
}

impl<T: PopVariable, U: PopVariable> PopVariable for Result<T, U> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Result(ref s) = var {
            Ok(match *s {
                Ok(ref s) => Ok(try!(PopVariable::pop_var(rt, rt.resolve(s)))),
                Err(ref err) => Err(try!(PopVariable::pop_var(rt, rt.resolve(&err.message))))
            })
        } else {
            Err(rt.expected(var, "result"))
        }
    }
}

impl<T: PopVariable> PopVariable for [T; 2] {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok([
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1])))
            ])
        } else {
            Err(rt.expected(var, "[_; 2]"))
        }
    }
}

impl<T: PopVariable> PopVariable for [T; 3] {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok([
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2])))
            ])
        } else {
            Err(rt.expected(var, "[_; 3]"))
        }
    }
}

impl<T: PopVariable> PopVariable for [T; 4] {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok([
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[3])))
            ])
        } else {
            Err(rt.expected(var, "[_; 4]"))
        }
    }
}

impl<T: PopVariable, U: PopVariable> PopVariable for (T, U) {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok((
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1])))
            ))
        } else {
            Err(rt.expected(var, "[_; 2]"))
        }
    }
}

impl<T: PopVariable, U: PopVariable, V: PopVariable> PopVariable for (T, U, V) {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok((
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2])))
            ))
        } else {
            Err(rt.expected(var, "[_; 3]"))
        }
    }
}

impl<T: PopVariable, U: PopVariable, V: PopVariable, W: PopVariable> PopVariable for (T, U, V, W) {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            Ok((
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[0]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[1]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[2]))),
                try!(PopVariable::pop_var(rt, rt.resolve(&arr[3])))
            ))
        } else {
            Err(rt.expected(var, "[_; 4]"))
        }
    }
}

impl<T: PopVariable> PopVariable for Vec<T> {
    fn pop_var(rt: &Runtime, var: &Variable) -> Result<Self, String> {
        if let &Variable::Array(ref arr) = var {
            let mut res = Vec::with_capacity(arr.len());
            for it in &**arr {
                res.push(try!(PopVariable::pop_var(rt, rt.resolve(it))))
            }
            Ok(res)
        } else {
            Err(rt.expected(var, "array"))
        }
    }
}

impl PushVariable for Variable {
    fn push_var(&self) -> Variable { self.clone() }
}

impl PushVariable for RustObject {
    fn push_var(&self) -> Variable {
        Variable::RustObject(self.clone())
    }
}

impl PushVariable for bool {
    fn push_var(&self) -> Variable { Variable::bool(*self) }
}

impl PushVariable for u32 {
    fn push_var(&self) -> Variable { Variable::f64(*self as f64) }
}

impl PushVariable for usize {
    fn push_var(&self) -> Variable { Variable::f64(*self as f64) }
}

impl PushVariable for f32 {
    fn push_var(&self) -> Variable { Variable::f64(*self as f64) }
}

impl PushVariable for f64 {
    fn push_var(&self) -> Variable { Variable::f64(*self) }
}

impl PushVariable for str {
    fn push_var(&self) -> Variable { Variable::Text(Arc::new(self.into())) }
}

impl PushVariable for String {
    fn push_var(&self) -> Variable { Variable::Text(Arc::new(self.clone())) }
}

impl PushVariable for Arc<String> {
    fn push_var(&self) -> Variable { Variable::Text(self.clone()) }
}

impl<T: PushVariable> PushVariable for Option<T> {
    fn push_var(&self) -> Variable {
        Variable::Option(self.as_ref().map(|v| Box::new(v.push_var())))
    }
}

impl<T: PushVariable, U: PushVariable> PushVariable for Result<T, U> {
    fn push_var(&self) -> Variable {
        Variable::Result(self.as_ref()
            .map(|v| Box::new(v.push_var()))
            .map_err(|e| Box::new(Error { message: e.push_var(), trace: vec![] })))
    }
}

impl<T: PushVariable> PushVariable for [T; 2] {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self[0].push_var(),
            self[1].push_var()
        ]))
    }
}

impl<T: PushVariable> PushVariable for [T; 3] {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self[0].push_var(),
            self[1].push_var(),
            self[2].push_var()
        ]))
    }
}

impl<T: PushVariable> PushVariable for [T; 4] {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self[0].push_var(),
            self[1].push_var(),
            self[2].push_var(),
            self[3].push_var()
        ]))
    }
}

impl<T: PushVariable, U: PushVariable> PushVariable for (T, U) {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self.0.push_var(),
            self.1.push_var()
        ]))
    }
}

impl<T: PushVariable, U: PushVariable, V: PushVariable> PushVariable for (T, U, V) {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self.0.push_var(),
            self.1.push_var(),
            self.2.push_var()
        ]))
    }
}

impl<T: PushVariable, U: PushVariable, V: PushVariable, W: PushVariable>
PushVariable for (T, U, V, W) {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(vec![
            self.0.push_var(),
            self.1.push_var(),
            self.2.push_var(),
            self.3.push_var()
        ]))
    }
}

impl<T: PushVariable> PushVariable for Vec<T> {
    fn push_var(&self) -> Variable {
        Variable::Array(Arc::new(self.iter().map(|it| it.push_var()).collect()))
    }
}

impl ConvertVec4 for [f32; 2] {
    fn from(val: [f32; 4]) -> Self { [val[0], val[1]] }
    fn to(&self) -> [f32; 4] { [self[0], self[1], 0.0, 0.0] }
}

impl ConvertVec4 for [f32; 3] {
    fn from(val: [f32; 4]) -> Self { [val[0], val[1], val[2]] }
    fn to(&self) -> [f32; 4] { [self[0], self[1], self[2], 0.0] }
}

impl ConvertVec4 for [f32; 4] {
    fn from(val: [f32; 4]) -> Self { val }
    fn to(&self) -> [f32; 4] { *self }
}

impl ConvertVec4 for [f64; 2] {
    fn from(val: [f32; 4]) -> Self { [val[0] as f64, val[1] as f64] }
    fn to(&self) -> [f32; 4] { [self[0] as f32, self[1] as f32, 0.0, 0.0] }
}

impl ConvertVec4 for [f64; 3] {
    fn from(val: [f32; 4]) -> Self { [val[0] as f64, val[1] as f64, val[2] as f64] }
    fn to(&self) -> [f32; 4] { [self[0] as f32, self[1] as f32, self[2] as f32, 0.0] }
}

impl ConvertVec4 for [f64; 4] {
    fn from(val: [f32; 4]) -> Self { [val[0] as f64, val[1] as f64, val[2] as f64, val[3] as f64] }
    fn to(&self) -> [f32; 4] { [self[0] as f32, self[1] as f32, self[2] as f32, self[3] as f32] }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::{fmt, io};

/// This type represents the possible errors that can occur while
/// sending DogstatsD metrics.
#[derive(Debug)]
pub enum DogstatsdError {
    /// Chained IO errors.
    IoError(io::Error),
}

use self::DogstatsdError::*;

impl fmt::Display for DogstatsdError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

impl Error for DogstatsdError {
    fn description(&self) -> &str {
        match *self {
            IoError(ref error) => error.description(),
        }
    }
}

impl From<io::Error> for DogstatsdError {
    fn from(e: io::Error) -> Self {
        IoError(e)
    }
}
<commit_msg>Fix Display impl for DogstatsdError.<commit_after>use std::error::Error;
use std::{fmt, io};

/// This type represents the possible errors that can occur while
/// sending DogstatsD metrics.
#[derive(Debug)]
pub enum DogstatsdError {
    /// Chained IO errors.
    IoError(io::Error),
}

use self::DogstatsdError::*;

impl fmt::Display for DogstatsdError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IoError(ref error) => write!(f, "{}", error),
        }
    }
}

impl Error for DogstatsdError {
    fn description(&self) -> &str {
        match *self {
            IoError(ref error) => error.description(),
        }
    }
}

impl From<io::Error> for DogstatsdError {
    fn from(e: io::Error) -> Self {
        IoError(e)
    }
}

#[cfg(test)]
mod tests {
    use super::DogstatsdError;
    use std::io;

    #[test]
    fn test_error_display() {
        let err = DogstatsdError::from(io::Error::new(io::ErrorKind::Other, "oh no!"));
        assert_eq!(format!("{}", err), "oh no!".to_owned());
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use std::fmt::{self, Display, Formatter};
use std::{error, result};

use crate::call::RpcStatus;
use crate::grpc_sys::grpc_call_error;

#[cfg(feature = "prost-codec")]
use prost::DecodeError;
#[cfg(feature = "protobuf-codec")]
use protobuf::ProtobufError;

/// Errors generated from this library.
#[derive(Debug)]
pub enum Error {
    /// Codec error.
    Codec(Box<dyn error::Error + Send + Sync>),
    /// Failed to start an internal async call.
    CallFailure(grpc_call_error),
    /// Rpc request fail.
    RpcFailure(RpcStatus),
    /// Try to write to a finished rpc call.
    RpcFinished(Option<RpcStatus>),
    /// Remote is stopped.
    RemoteStopped,
    /// Failed to shutdown.
    ShutdownFailed,
    /// Failed to bind.
    BindFail(String, u16),
    /// gRPC completion queue is shutdown.
    QueueShutdown,
    /// Failed to create Google default credentials.
    GoogleAuthenticationFailed,
    /// Invalid format of metadata.
    InvalidMetadata(String),
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        write!(fmt, "{:?}", self)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Codec(_) => "gRPC Codec Error",
            Error::CallFailure(_) => "gRPC Call Error",
            Error::RpcFailure(_) => "gRPC Request Error",
            Error::RpcFinished(_) => "gRPC Finish Error",
            Error::RemoteStopped => "Remote is stopped.",
            Error::ShutdownFailed => "Failed to shutdown.",
            Error::BindFail(_, _) => "gRPC Bind Error",
            Error::QueueShutdown => "gRPC completion queue shutdown",
            Error::GoogleAuthenticationFailed => "Could not create google default credentials.",
            Error::InvalidMetadata(_) => "invalid format of metadata",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            Error::Codec(ref e) => Some(e.as_ref()),
            _ => None,
        }
    }

    // TODO: impl `Error::source`, but it may break backward compatibility,
    // Eg. TiKV still uses nightly-2018-07-18, which does not compile.
}

#[cfg(feature = "protobuf-codec")]
impl From<ProtobufError> for Error {
    fn from(e: ProtobufError) -> Error {
        Error::Codec(Box::new(e))
    }
}

#[cfg(feature = "prost-codec")]
impl From<DecodeError> for Error {
    fn from(e: DecodeError) -> Error {
        Error::Codec(Box::new(e))
    }
}

/// Type alias to use this library's [`Error`] type in a `Result`.
pub type Result<T> = result::Result<T, Error>;

#[cfg(all(test, feature = "protobuf-codec"))]
mod tests {
    use std::error::Error as StdError;

    use protobuf::error::WireError;
    use protobuf::ProtobufError;

    use super::Error;

    #[allow(deprecated)]
    #[test]
    fn test_convert() {
        let error = ProtobufError::WireError(WireError::UnexpectedEof);
        let e: Error = error.into();
        assert_eq!(e.description(), "gRPC Codec Error");
        assert!(e.cause().is_some());
    }
}
<commit_msg>Remove deprecated usage of Error trait (#428)<commit_after>// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.

use std::{error, fmt, result};

use crate::call::RpcStatus;
use crate::grpc_sys::grpc_call_error;

#[cfg(feature = "prost-codec")]
use prost::DecodeError;
#[cfg(feature = "protobuf-codec")]
use protobuf::ProtobufError;

/// Errors generated from this library.
#[derive(Debug)]
pub enum Error {
    /// Codec error.
    Codec(Box<dyn error::Error + Send + Sync>),
    /// Failed to start an internal async call.
    CallFailure(grpc_call_error),
    /// Rpc request fail.
    RpcFailure(RpcStatus),
    /// Try to write to a finished rpc call.
    RpcFinished(Option<RpcStatus>),
    /// Remote is stopped.
    RemoteStopped,
    /// Failed to shutdown.
    ShutdownFailed,
    /// Failed to bind.
    BindFail(String, u16),
    /// gRPC completion queue is shutdown.
    QueueShutdown,
    /// Failed to create Google default credentials.
    GoogleAuthenticationFailed,
    /// Invalid format of metadata.
    InvalidMetadata(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match *self {
            Error::Codec(ref e) => Some(e.as_ref()),
            _ => None,
        }
    }
}

#[cfg(feature = "protobuf-codec")]
impl From<ProtobufError> for Error {
    fn from(e: ProtobufError) -> Error {
        Error::Codec(Box::new(e))
    }
}

#[cfg(feature = "prost-codec")]
impl From<DecodeError> for Error {
    fn from(e: DecodeError) -> Error {
        Error::Codec(Box::new(e))
    }
}

/// Type alias to use this library's [`Error`] type in a `Result`.
pub type Result<T> = result::Result<T, Error>;

#[cfg(all(test, feature = "protobuf-codec"))]
mod tests {
    use std::error::Error as StdError;

    use protobuf::error::WireError;
    use protobuf::ProtobufError;

    use super::Error;

    #[test]
    fn test_convert() {
        let error = ProtobufError::WireError(WireError::UnexpectedEof);
        let e: Error = error.into();
        assert_eq!(e.to_string(), "Codec(WireError(UnexpectedEof))");
        assert!(e.source().is_some());
    }
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt;
use std::io;

use {StatusCode, Url};

/// The Errors that may occur when processing a `Request`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate serde_derive;
/// extern crate reqwest;
///
/// #[derive(Deserialize)]
/// struct Simple {
///    key: String
/// }
/// # fn main() { }
///
/// fn run() {
///    match make_request() {
///        Err(e) => handler(e),
///        Ok(_)  => return,
///    }
/// }
/// // Response is not a json object conforming to the Simple struct
/// fn make_request() -> Result<Simple, reqwest::Error> {
///   reqwest::get("http://httpbin.org/ip")?.json()
/// }
///
/// fn handler(e: reqwest::Error) {
///    if e.is_http() {
///        match e.url() {
///            None => println!("No Url given"),
///            Some(url) => println!("Problem making request to: {}", url),
///        }
///    }
///    // Inspect the internal error and output it
///    if e.is_serialization() {
///       let serde_error = match e.get_ref() {
///            None => return,
///            Some(err) => err,
///        };
///        println!("problem parsing information {}", serde_error);
///    }
///    if e.is_redirect() {
///        println!("server redirecting too many times or making loop");
///    }
/// }
/// ```
#[derive(Debug)]
pub struct Error {
    kind: Kind,
    url: Option<Url>,
}

/// A `Result` alias where the `Err` case is `reqwest::Error`.
pub type Result<T> = ::std::result::Result<T, Error>;

impl Error {
    /// Returns a possible URL related to this error.
    ///
    /// # Examples
    ///
    /// ```
    /// # fn run() {
    /// // displays last stop of a redirect loop
    /// let response = reqwest::get("http://site.with.redirect.loop");
    /// if let Err(e) = response {
    ///     if e.is_redirect() {
    ///         if let Some(final_stop) = e.url() {
    ///             println!("redirect loop at {}", final_stop);
    ///         }
    ///     }
    /// }
    /// # }
    /// ```
    #[inline]
    pub fn url(&self) -> Option<&Url> {
        self.url.as_ref()
    }

    /// Returns a reference to the internal error, if available.
    ///
    /// The `'static` bounds allows using `downcast_ref` to check the
    /// details of the error.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate url;
    /// # extern crate reqwest;
    /// // retries requests with no host on localhost
    /// # fn run() {
    /// let invalid_request = "http://";
    /// let mut response = reqwest::get(invalid_request);
    /// if let Err(e) = response {
    ///     match e.get_ref().and_then(|e| e.downcast_ref::<url::ParseError>()) {
    ///         Some(&url::ParseError::EmptyHost) => {
    ///             let valid_request = format!("{}{}",invalid_request, "localhost");
    ///             response = reqwest::get(&valid_request);
    ///         },
    ///         _ => (),
    ///     }
    /// }
    /// # }
    /// # fn main() {}
    /// ```
    #[inline]
    pub fn get_ref(&self) -> Option<&(StdError + Send + Sync + 'static)> {
        match self.kind {
            Kind::Http(ref e) => Some(e),
            Kind::Url(ref e) => Some(e),
            Kind::Tls(ref e) => Some(e),
            Kind::Io(ref e) => Some(e),
            Kind::UrlEncoded(ref e) => Some(e),
            Kind::Json(ref e) => Some(e),
            Kind::TooManyRedirects |
            Kind::RedirectLoop |
            Kind::ClientError(_) |
            Kind::ServerError(_) => None,
        }
    }

    /// Returns true if the error is related to HTTP.
    #[inline]
    pub fn is_http(&self) -> bool {
        match self.kind {
            Kind::Http(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is serialization related.
    #[inline]
    pub fn is_serialization(&self) -> bool {
        match self.kind {
            Kind::Json(_) |
            Kind::UrlEncoded(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a `RedirectPolicy`.
    #[inline]
    pub fn is_redirect(&self) -> bool {
        match self.kind {
            Kind::TooManyRedirects |
            Kind::RedirectLoop => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a request returning a 4xx error.
    #[inline]
    pub fn is_client_error(&self) -> bool {
        match self.kind {
            Kind::ClientError(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a request returning a 5xx error.
    #[inline]
    pub fn is_server_error(&self) -> bool {
        match self.kind {
            Kind::ServerError(_) => true,
            _ => false,
        }
    }

    /// Returns the status code, if the error was generated from a response.
    #[inline]
    pub fn status(&self) -> Option<StatusCode> {
        match self.kind {
            Kind::ClientError(code) |
            Kind::ServerError(code) => Some(code),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref url) = self.url {
            try!(fmt::Display::fmt(url, f));
            try!(f.write_str(": "));
        }
        match self.kind {
            Kind::Http(ref e) => fmt::Display::fmt(e, f),
            Kind::Url(ref e) => fmt::Display::fmt(e, f),
            Kind::Tls(ref e) => fmt::Display::fmt(e, f),
            Kind::Io(ref e) => fmt::Display::fmt(e, f),
            Kind::UrlEncoded(ref e) => fmt::Display::fmt(e, f),
            Kind::Json(ref e) => fmt::Display::fmt(e, f),
            Kind::TooManyRedirects => f.write_str("Too many redirects"),
            Kind::RedirectLoop => f.write_str("Infinite redirect loop"),
            Kind::ClientError(ref code) => {
                f.write_str("Client Error: ")?;
                fmt::Display::fmt(code, f)
            }
            Kind::ServerError(ref code) => {
                f.write_str("Server Error: ")?;
                fmt::Display::fmt(code, f)
            }
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.kind {
            Kind::Http(ref e) => e.description(),
            Kind::Url(ref e) => e.description(),
            Kind::Tls(ref e) => e.description(),
            Kind::Io(ref e) => e.description(),
            Kind::UrlEncoded(ref e) => e.description(),
            Kind::Json(ref e) => e.description(),
            Kind::TooManyRedirects => "Too many redirects",
            Kind::RedirectLoop => "Infinite redirect loop",
            Kind::ClientError(_) => "Client Error",
            Kind::ServerError(_) => "Server Error",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Http(ref e) => e.cause(),
            Kind::Url(ref e) => e.cause(),
            Kind::Tls(ref e) => e.cause(),
            Kind::Io(ref e) => e.cause(),
            Kind::UrlEncoded(ref e) => e.cause(),
            Kind::Json(ref e) => e.cause(),
            Kind::TooManyRedirects |
            Kind::RedirectLoop |
            Kind::ClientError(_) |
            Kind::ServerError(_) => None,
        }
    }
}

// pub(crate)

#[derive(Debug)]
pub enum Kind {
    Http(::hyper::Error),
    Url(::url::ParseError),
    Tls(::native_tls::Error),
    Io(io::Error),
    UrlEncoded(::serde_urlencoded::ser::Error),
    Json(::serde_json::Error),
    TooManyRedirects,
    RedirectLoop,
    ClientError(StatusCode),
    ServerError(StatusCode),
}

impl From<::hyper::Error> for Kind {
    #[inline]
    fn from(err: ::hyper::Error) -> Kind {
        match err {
            ::hyper::Error::Io(err) => Kind::Io(err),
            /*
            ::hyper::Error::Uri(err) => Kind::Url(err),
            ::hyper::Error::Ssl(err) => {
                match err.downcast() {
                    Ok(tls) => Kind::Tls(*tls),
                    Err(ssl) => Kind::Http(::hyper::Error::Ssl(ssl)),
                }
            }
            */
            other => Kind::Http(other),
        }
    }
}

impl From<io::Error> for Kind {
    #[inline]
    fn from(err: io::Error) -> Kind {
        Kind::Io(err)
    }
}

impl From<::url::ParseError> for Kind {
    #[inline]
    fn from(err: ::url::ParseError) -> Kind {
        Kind::Url(err)
    }
}

impl From<::serde_urlencoded::ser::Error> for Kind {
    #[inline]
    fn from(err: ::serde_urlencoded::ser::Error) -> Kind {
        Kind::UrlEncoded(err)
    }
}

impl From<::serde_json::Error> for Kind {
    #[inline]
    fn from(err: ::serde_json::Error) -> Kind {
        Kind::Json(err)
    }
}

impl From<::native_tls::Error> for Kind {
    fn from(err: ::native_tls::Error) -> Kind {
        Kind::Tls(err)
    }
}

impl<T> From<::wait::Waited<T>> for Kind
where T: Into<Kind> {
    fn from(err: ::wait::Waited<T>) -> Kind {
        match err {
            ::wait::Waited::TimedOut =>  io_timeout().into(),
            ::wait::Waited::Err(e) => e.into(),
        }
    }
}

#[cfg(unix)]
fn io_timeout() -> io::Error {
    io::Error::new(io::ErrorKind::WouldBlock, "timed out")
}

#[cfg(windows)]
fn io_timeout() -> io::Error {
    io::Error::new(io::ErrorKind::TimedOut, "timed out")
}

// pub(crate)

#[allow(missing_debug_implementations)]
pub struct InternalFrom<T>(pub T, pub Option<Url>);

#[doc(hidden)] // https://github.com/rust-lang/rust/issues/42323
impl From<InternalFrom<Error>> for Error {
    #[inline]
    fn from(other: InternalFrom<Error>) -> Error {
        other.0
    }
}

#[doc(hidden)] // https://github.com/rust-lang/rust/issues/42323
impl<T> From<InternalFrom<T>> for Error
where
    T: Into<Kind>,
{
    #[inline]
    fn from(other: InternalFrom<T>) -> Error {
        Error {
            kind: other.0.into(),
            url: other.1,
        }
    }
}

#[inline]
pub fn from<T>(err: T) -> Error
where
    T: Into<Kind>,
{
    InternalFrom(err, None).into()
}

#[inline]
pub fn into_io(e: Error) -> io::Error {
    match e.kind {
        Kind::Io(io) => io,
        _ => io::Error::new(io::ErrorKind::Other, e),
    }
}

macro_rules! try_ {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(err) => {
                return Err(::error::from(err));
            }
        }
    );
    ($e:expr, $url:expr) => (
        match $e {
            Ok(v) => v,
            Err(err) => {
                return Err(::Error::from(::error::InternalFrom(err, Some($url.clone()))));
            }
        }
    )
}

#[inline]
pub fn loop_detected(url: Url) -> Error {
    Error {
        kind: Kind::RedirectLoop,
        url: Some(url),
    }
}

#[inline]
pub fn too_many_redirects(url: Url) -> Error {
    Error {
        kind: Kind::TooManyRedirects,
        url: Some(url),
    }
}

#[inline]
pub fn timedout(url: Option<Url>) -> Error {
    Error {
        kind: Kind::Io(io_timeout()),
        url: url,
    }
}

#[inline]
pub fn client_error(url: Url, status: StatusCode) -> Error {
    Error {
        kind: Kind::ClientError(status),
        url: Some(url),
    }
}

#[inline]
pub fn server_error(url: Url, status: StatusCode) -> Error {
    Error {
        kind: Kind::ServerError(status),
        url: Some(url),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_error_get_ref_downcasts() {
        let err: Error = from(::hyper::Error::Status);
        let cause = err.get_ref()
            .unwrap()
            .downcast_ref::<::hyper::Error>()
            .unwrap();

        match cause {
            &::hyper::Error::Status => (),
            _ => panic!("unexpected downcast: {:?}", cause),
        }
    }

    #[test]
    fn test_cause_chain() {
        #[derive(Debug)]
        struct Chain<T>(Option<T>);

        impl<T: fmt::Display> fmt::Display  for Chain<T> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                if let Some(ref link) = self.0 {
                    write!(f, "chain: {}", link)
                } else {
                    f.write_str("root")
                }
            }
        }

        impl<T: StdError> StdError for Chain<T> {
            fn description(&self) -> &str {
                if self.0.is_some() {
                    "chain"
                } else {
                    "root"
                }
            }
            fn cause(&self) -> Option<&StdError> {
                if let Some(ref e) = self.0 {
                    Some(e)
                } else {
                    None
                }
            }
        }

        let err = from(::hyper::Error::Status);
        assert!(err.cause().is_none());

        let root = Chain(None::<Error>);
        let io = ::std::io::Error::new(::std::io::ErrorKind::Other, root);
        let err = Error { kind: Kind::Io(io), url: None };
        assert!(err.cause().is_none());
        assert_eq!(err.to_string(), "root");

        let root = ::std::io::Error::new(::std::io::ErrorKind::Other, Chain(None::<Error>));
        let link = Chain(Some(root));
        let io = ::std::io::Error::new(::std::io::ErrorKind::Other, link);
        let err = Error { kind: Kind::Io(io), url: None };
        assert!(err.cause().is_some());
        assert_eq!(err.to_string(), "chain: root");
    }
}
<commit_msg>remove hyper::Error::Ssl<commit_after>use std::error::Error as StdError;
use std::fmt;
use std::io;

use {StatusCode, Url};

/// The Errors that may occur when processing a `Request`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate serde_derive;
/// extern crate reqwest;
///
/// #[derive(Deserialize)]
/// struct Simple {
///    key: String
/// }
/// # fn main() { }
///
/// fn run() {
///    match make_request() {
///        Err(e) => handler(e),
///        Ok(_)  => return,
///    }
/// }
/// // Response is not a json object conforming to the Simple struct
/// fn make_request() -> Result<Simple, reqwest::Error> {
///   reqwest::get("http://httpbin.org/ip")?.json()
/// }
///
/// fn handler(e: reqwest::Error) {
///    if e.is_http() {
///        match e.url() {
///            None => println!("No Url given"),
///            Some(url) => println!("Problem making request to: {}", url),
///        }
///    }
///    // Inspect the internal error and output it
///    if e.is_serialization() {
///       let serde_error = match e.get_ref() {
///            None => return,
///            Some(err) => err,
///        };
///        println!("problem parsing information {}", serde_error);
///    }
///    if e.is_redirect() {
///        println!("server redirecting too many times or making loop");
///    }
/// }
/// ```
#[derive(Debug)]
pub struct Error {
    kind: Kind,
    url: Option<Url>,
}

/// A `Result` alias where the `Err` case is `reqwest::Error`.
pub type Result<T> = ::std::result::Result<T, Error>;

impl Error {
    /// Returns a possible URL related to this error.
    ///
    /// # Examples
    ///
    /// ```
    /// # fn run() {
    /// // displays last stop of a redirect loop
    /// let response = reqwest::get("http://site.with.redirect.loop");
    /// if let Err(e) = response {
    ///     if e.is_redirect() {
    ///         if let Some(final_stop) = e.url() {
    ///             println!("redirect loop at {}", final_stop);
    ///         }
    ///     }
    /// }
    /// # }
    /// ```
    #[inline]
    pub fn url(&self) -> Option<&Url> {
        self.url.as_ref()
    }

    /// Returns a reference to the internal error, if available.
    ///
    /// The `'static` bounds allows using `downcast_ref` to check the
    /// details of the error.
    ///
    /// # Examples
    ///
    /// ```
    /// extern crate url;
    /// # extern crate reqwest;
    /// // retries requests with no host on localhost
    /// # fn run() {
    /// let invalid_request = "http://";
    /// let mut response = reqwest::get(invalid_request);
    /// if let Err(e) = response {
    ///     match e.get_ref().and_then(|e| e.downcast_ref::<url::ParseError>()) {
    ///         Some(&url::ParseError::EmptyHost) => {
    ///             let valid_request = format!("{}{}",invalid_request, "localhost");
    ///             response = reqwest::get(&valid_request);
    ///         },
    ///         _ => (),
    ///     }
    /// }
    /// # }
    /// # fn main() {}
    /// ```
    #[inline]
    pub fn get_ref(&self) -> Option<&(StdError + Send + Sync + 'static)> {
        match self.kind {
            Kind::Http(ref e) => Some(e),
            Kind::Url(ref e) => Some(e),
            Kind::Tls(ref e) => Some(e),
            Kind::Io(ref e) => Some(e),
            Kind::UrlEncoded(ref e) => Some(e),
            Kind::Json(ref e) => Some(e),
            Kind::TooManyRedirects |
            Kind::RedirectLoop |
            Kind::ClientError(_) |
            Kind::ServerError(_) => None,
        }
    }

    /// Returns true if the error is related to HTTP.
    #[inline]
    pub fn is_http(&self) -> bool {
        match self.kind {
            Kind::Http(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is serialization related.
    #[inline]
    pub fn is_serialization(&self) -> bool {
        match self.kind {
            Kind::Json(_) |
            Kind::UrlEncoded(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a `RedirectPolicy`.
    #[inline]
    pub fn is_redirect(&self) -> bool {
        match self.kind {
            Kind::TooManyRedirects |
            Kind::RedirectLoop => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a request returning a 4xx error.
    #[inline]
    pub fn is_client_error(&self) -> bool {
        match self.kind {
            Kind::ClientError(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a request returning a 5xx error.
    #[inline]
    pub fn is_server_error(&self) -> bool {
        match self.kind {
            Kind::ServerError(_) => true,
            _ => false,
        }
    }

    /// Returns the status code, if the error was generated from a response.
    #[inline]
    pub fn status(&self) -> Option<StatusCode> {
        match self.kind {
            Kind::ClientError(code) |
            Kind::ServerError(code) => Some(code),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref url) = self.url {
            try!(fmt::Display::fmt(url, f));
            try!(f.write_str(": "));
        }
        match self.kind {
            Kind::Http(ref e) => fmt::Display::fmt(e, f),
            Kind::Url(ref e) => fmt::Display::fmt(e, f),
            Kind::Tls(ref e) => fmt::Display::fmt(e, f),
            Kind::Io(ref e) => fmt::Display::fmt(e, f),
            Kind::UrlEncoded(ref e) => fmt::Display::fmt(e, f),
            Kind::Json(ref e) => fmt::Display::fmt(e, f),
            Kind::TooManyRedirects => f.write_str("Too many redirects"),
            Kind::RedirectLoop => f.write_str("Infinite redirect loop"),
            Kind::ClientError(ref code) => {
                f.write_str("Client Error: ")?;
                fmt::Display::fmt(code, f)
            }
            Kind::ServerError(ref code) => {
                f.write_str("Server Error: ")?;
                fmt::Display::fmt(code, f)
            }
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.kind {
            Kind::Http(ref e) => e.description(),
            Kind::Url(ref e) => e.description(),
            Kind::Tls(ref e) => e.description(),
            Kind::Io(ref e) => e.description(),
            Kind::UrlEncoded(ref e) => e.description(),
            Kind::Json(ref e) => e.description(),
            Kind::TooManyRedirects => "Too many redirects",
            Kind::RedirectLoop => "Infinite redirect loop",
            Kind::ClientError(_) => "Client Error",
            Kind::ServerError(_) => "Server Error",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Http(ref e) => e.cause(),
            Kind::Url(ref e) => e.cause(),
            Kind::Tls(ref e) => e.cause(),
            Kind::Io(ref e) => e.cause(),
            Kind::UrlEncoded(ref e) => e.cause(),
            Kind::Json(ref e) => e.cause(),
            Kind::TooManyRedirects |
            Kind::RedirectLoop |
            Kind::ClientError(_) |
            Kind::ServerError(_) => None,
        }
    }
}

// pub(crate)

#[derive(Debug)]
pub enum Kind {
    Http(::hyper::Error),
    Url(::url::ParseError),
    Tls(::native_tls::Error),
    Io(io::Error),
    UrlEncoded(::serde_urlencoded::ser::Error),
    Json(::serde_json::Error),
    TooManyRedirects,
    RedirectLoop,
    ClientError(StatusCode),
    ServerError(StatusCode),
}

impl From<::hyper::Error> for Kind {
    #[inline]
    fn from(err: ::hyper::Error) -> Kind {
        match err {
            ::hyper::Error::Io(err) => Kind::Io(err),
            //::hyper::Error::Uri(err) => Kind::Url(err),
            other => Kind::Http(other),
        }
    }
}

impl From<io::Error> for Kind {
    #[inline]
    fn from(err: io::Error) -> Kind {
        Kind::Io(err)
    }
}

impl From<::url::ParseError> for Kind {
    #[inline]
    fn from(err: ::url::ParseError) -> Kind {
        Kind::Url(err)
    }
}

impl From<::serde_urlencoded::ser::Error> for Kind {
    #[inline]
    fn from(err: ::serde_urlencoded::ser::Error) -> Kind {
        Kind::UrlEncoded(err)
    }
}

impl From<::serde_json::Error> for Kind {
    #[inline]
    fn from(err: ::serde_json::Error) -> Kind {
        Kind::Json(err)
    }
}

impl From<::native_tls::Error> for Kind {
    fn from(err: ::native_tls::Error) -> Kind {
        Kind::Tls(err)
    }
}

impl<T> From<::wait::Waited<T>> for Kind
where T: Into<Kind> {
    fn from(err: ::wait::Waited<T>) -> Kind {
        match err {
            ::wait::Waited::TimedOut =>  io_timeout().into(),
            ::wait::Waited::Err(e) => e.into(),
        }
    }
}

#[cfg(unix)]
fn io_timeout() -> io::Error {
    io::Error::new(io::ErrorKind::WouldBlock, "timed out")
}

#[cfg(windows)]
fn io_timeout() -> io::Error {
    io::Error::new(io::ErrorKind::TimedOut, "timed out")
}

// pub(crate)

#[allow(missing_debug_implementations)]
pub struct InternalFrom<T>(pub T, pub Option<Url>);

#[doc(hidden)] // https://github.com/rust-lang/rust/issues/42323
impl From<InternalFrom<Error>> for Error {
    #[inline]
    fn from(other: InternalFrom<Error>) -> Error {
        other.0
    }
}

#[doc(hidden)] // https://github.com/rust-lang/rust/issues/42323
impl<T> From<InternalFrom<T>> for Error
where
    T: Into<Kind>,
{
    #[inline]
    fn from(other: InternalFrom<T>) -> Error {
        Error {
            kind: other.0.into(),
            url: other.1,
        }
    }
}

#[inline]
pub fn from<T>(err: T) -> Error
where
    T: Into<Kind>,
{
    InternalFrom(err, None).into()
}

#[inline]
pub fn into_io(e: Error) -> io::Error {
    match e.kind {
        Kind::Io(io) => io,
        _ => io::Error::new(io::ErrorKind::Other, e),
    }
}

macro_rules! try_ {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(err) => {
                return Err(::error::from(err));
            }
        }
    );
    ($e:expr, $url:expr) => (
        match $e {
            Ok(v) => v,
            Err(err) => {
                return Err(::Error::from(::error::InternalFrom(err, Some($url.clone()))));
            }
        }
    )
}

#[inline]
pub fn loop_detected(url: Url) -> Error {
    Error {
        kind: Kind::RedirectLoop,
        url: Some(url),
    }
}

#[inline]
pub fn too_many_redirects(url: Url) -> Error {
    Error {
        kind: Kind::TooManyRedirects,
        url: Some(url),
    }
}

#[inline]
pub fn timedout(url: Option<Url>) -> Error {
    Error {
        kind: Kind::Io(io_timeout()),
        url: url,
    }
}

#[inline]
pub fn client_error(url: Url, status: StatusCode) -> Error {
    Error {
        kind: Kind::ClientError(status),
        url: Some(url),
    }
}

#[inline]
pub fn server_error(url: Url, status: StatusCode) -> Error {
    Error {
        kind: Kind::ServerError(status),
        url: Some(url),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_error_get_ref_downcasts() {
        let err: Error = from(::hyper::Error::Status);
        let cause = err.get_ref()
            .unwrap()
            .downcast_ref::<::hyper::Error>()
            .unwrap();

        match cause {
            &::hyper::Error::Status => (),
            _ => panic!("unexpected downcast: {:?}", cause),
        }
    }

    #[test]
    fn test_cause_chain() {
        #[derive(Debug)]
        struct Chain<T>(Option<T>);

        impl<T: fmt::Display> fmt::Display  for Chain<T> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                if let Some(ref link) = self.0 {
                    write!(f, "chain: {}", link)
                } else {
                    f.write_str("root")
                }
            }
        }

        impl<T: StdError> StdError for Chain<T> {
            fn description(&self) -> &str {
                if self.0.is_some() {
                    "chain"
                } else {
                    "root"
                }
            }
            fn cause(&self) -> Option<&StdError> {
                if let Some(ref e) = self.0 {
                    Some(e)
                } else {
                    None
                }
            }
        }

        let err = from(::hyper::Error::Status);
        assert!(err.cause().is_none());

        let root = Chain(None::<Error>);
        let io = ::std::io::Error::new(::std::io::ErrorKind::Other, root);
        let err = Error { kind: Kind::Io(io), url: None };
        assert!(err.cause().is_none());
        assert_eq!(err.to_string(), "root");

        let root = ::std::io::Error::new(::std::io::ErrorKind::Other, Chain(None::<Error>));
        let link = Chain(Some(root));
        let io = ::std::io::Error::new(::std::io::ErrorKind::Other, link);
        let err = Error { kind: Kind::Io(io), url: None };
        assert!(err.cause().is_some());
        assert_eq!(err.to_string(), "chain: root");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io;

#[derive(Debug)]
pub enum IndentexError {
    Io(io::Error),
    InvalidExtension,
    WalkError(ignore::Error),
}

impl From<ignore::Error> for IndentexError {
    fn from(e: ignore::Error) -> IndentexError {
        IndentexError::WalkError(e)
    }
}

impl From<io::Error> for IndentexError {
    fn from(e: io::Error) -> IndentexError {
        IndentexError::Io(e)
    }
}

impl fmt::Display for IndentexError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        match *self {
            IndentexError::Io(ref e) => write!(f, "{}", e.description()),
            IndentexError::InvalidExtension => write!(f, "not a valid indentex file"),
            IndentexError::WalkError(ref e) => write!(f, "{}", e.description()),
        }
    }
}
<commit_msg>Add simple unit tests for the error type<commit_after>#[derive(Debug)]
pub enum IndentexError {
    Io(std::io::Error),
    InvalidExtension,
    WalkError(ignore::Error),
}

impl From<ignore::Error> for IndentexError {
    fn from(e: ignore::Error) -> IndentexError {
        IndentexError::WalkError(e)
    }
}

impl From<std::io::Error> for IndentexError {
    fn from(e: std::io::Error) -> IndentexError {
        IndentexError::Io(e)
    }
}

impl std::fmt::Display for IndentexError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        match *self {
            IndentexError::Io(ref e) => write!(f, "{}", e.description()),
            IndentexError::InvalidExtension => write!(f, "not a valid indentex file"),
            IndentexError::WalkError(ref e) => write!(f, "{}", e.description()),
        }
    }
}

// LCOV_EXCL_START
#[cfg(test)]
mod tests {
    use super::IndentexError;

    #[test]
    fn from_io_error() {
        let io_error = std::io::Error::new(std::io::ErrorKind::Other, "foo");
        assert_eq!(format!("{}", IndentexError::from(io_error)), "foo");
    }

    #[test]
    fn from_ignore_error() {
        let io_error = std::io::Error::new(std::io::ErrorKind::Other, "bar");
        let ignore_error = ignore::Error::Io(io_error);
        assert_eq!(format!("{}", IndentexError::from(ignore_error)), "bar");
    }

    #[test]
    fn invalid_extension() {
        assert_eq!(
            format!("{}", IndentexError::InvalidExtension),
            "not a valid indentex file"
        );
    }
}
// LCOV_EXCL_STOP
<|endoftext|>


<commit_before>use hyper;
use hyper_tls;
use serde_json;
use std;
use toml;

#[derive(Debug)]
pub enum Error {
    Serde(serde_json::Error),
    Io(std::io::Error),
    Toml(toml::de::Error),
    Http(hyper::http::Error),
    Hyper(hyper::Error),
    HyperTls(hyper_tls::Error),
    ParseMessageError(ParseMessageError),
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error { Error::Serde(err) }
}
impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error { Error::Io(err) }
}
impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Error { Error::Toml(err) }
}
impl From<hyper::Error> for Error {
    fn from(err: hyper::Error) -> Error { Error::Hyper(err) }
}
impl From<hyper::http::Error> for Error {
    fn from(err: hyper::http::Error) -> Error { Error::Http(err) }
}
impl From<hyper_tls::Error> for Error {
    fn from(err: hyper_tls::Error) -> Error { Error::HyperTls(err) }
}

#[derive(Debug)]
pub enum ParseSectorTypeError {
    UnknownType,
}

#[derive(Debug)]
pub enum ParseSectorError {
    Id(std::num::ParseIntError),
    Type(ParseSectorTypeError),
    BadFormat,
}

#[derive(Debug)]
pub enum ParseSectorGroupError {
    Sector(ParseSectorError),
    Gid(std::num::ParseIntError),
    Member(std::num::ParseIntError),
}

#[derive(Debug)]
pub enum ParseMessageError {
    ParseClientMessageError,
    ParseDaemonMessageError,
}

impl From<ParseMessageError> for Error {
    fn from(err: ParseMessageError) -> Error { Error::ParseMessageError(err) }
}
<commit_msg>Remove an unused variant<commit_after>use hyper;
use serde_json;
use std;
use toml;

#[derive(Debug)]
pub enum Error {
    Serde(serde_json::Error),
    Io(std::io::Error),
    Toml(toml::de::Error),
    Http(hyper::http::Error),
    Hyper(hyper::Error),
    ParseMessageError(ParseMessageError),
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error { Error::Serde(err) }
}
impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error { Error::Io(err) }
}
impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Error { Error::Toml(err) }
}
impl From<hyper::Error> for Error {
    fn from(err: hyper::Error) -> Error { Error::Hyper(err) }
}
impl From<hyper::http::Error> for Error {
    fn from(err: hyper::http::Error) -> Error { Error::Http(err) }
}

#[derive(Debug)]
pub enum ParseSectorTypeError {
    UnknownType,
}

#[derive(Debug)]
pub enum ParseSectorError {
    Id(std::num::ParseIntError),
    Type(ParseSectorTypeError),
    BadFormat,
}

#[derive(Debug)]
pub enum ParseSectorGroupError {
    Sector(ParseSectorError),
    Gid(std::num::ParseIntError),
    Member(std::num::ParseIntError),
}

#[derive(Debug)]
pub enum ParseMessageError {
    ParseClientMessageError,
    ParseDaemonMessageError,
}

impl From<ParseMessageError> for Error {
    fn from(err: ParseMessageError) -> Error { Error::ParseMessageError(err) }
}
<|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>>),
}

#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Key {
    /// Both Enter and numpad Enter
    Enter,
    /// Tabulation key
    Tab,
    ShiftTab,
    Left,
    Right,
    Up,
    Down,
    PageUp,
    PageDown,
    Backspace,
    Home,
    End,
    /// Delete key
    Del,
    ShiftDel,
    CtrlDel,
    /// Insert key
    Ins,
    /// Escape key. Often buffered by the terminal,
    /// may appear with a delay or along with the next key.
    Esc,
    // Left arrow while shift is pressed
    CtrlPageUp,
    CtrlPageDown,
    ShiftLeft,
    ShiftRight,
    CtrlShiftLeft,
    CtrlShiftRight,
    CtrlLeft,
    CtrlRight,
    CtrlUp,
    CtrlDown,
    F(u8),
    CtrlF(u8),
    ShiftF(u8),
    CtrlShiftF(u8),
    CtrlChar(char),
    Unknown(i32),
}

impl Key {
    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,
            // Del and Ins currently use a bad value in ncurses-rs
            330 => Key::Del,
            331 => Key::Ins,
            // Those keys don't seem to be documented...
            515 => Key::CtrlDel,
            521 => Key::CtrlDown,
            541 => Key::CtrlLeft,
            542 => Key::CtrlShiftLeft,
            546 => Key::CtrlPageDown,
            551 => Key::CtrlPageUp,
            556 => Key::CtrlRight,
            557 => Key::CtrlShiftRight,
            562 => Key::CtrlUp,
            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_PPAGE => Key::PageUp,
            ncurses::KEY_NPAGE => Key::PageDown,
            ncurses::KEY_HOME => Key::Home,
            ncurses::KEY_END => Key::End,
            ncurses::KEY_SDC => Key::ShiftDel,
            // All Fn keys use the same enum with associated number
            f @ ncurses::KEY_F1 ... ncurses::KEY_F15 => Key::F((f - ncurses::KEY_F0) as u8),
            f @ 281 ... 291 => Key::ShiftF((f - 281 + 5) as u8),
            f @ 293 ... 303 => Key::CtrlF((f - 293 + 5) as u8),
            f @ 305 ... 315 => 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::Left => "Left",
                Key::Right => "Right",
                Key::Down => "Down",
                Key::Up => "Up",
                Key::CtrlShiftLeft => "Ctrl-Shift-Left",
                Key::CtrlShiftRight => "Ctrl-Shift-Right",
                Key::ShiftLeft => "Shift-Left",
                Key::ShiftRight => "Shift-Right",
                Key::ShiftDel => "Shift-Del",
                Key::CtrlDel => "Ctrl-Del",
                Key::CtrlLeft => "Ctrl-Left",
                Key::CtrlRight => "Ctrl-Right",
                Key::CtrlUp => "Ctrl-Up",
                Key::CtrlDown => "Ctrl-Down",
                Key::CtrlPageUp => "Ctrl-PageUp",
                Key::CtrlPageDown => "Ctrl-PageDown",
                Key::PageUp => "PageUp",
                Key::PageDown => "PageDown",
                Key::Home => "Home",
                Key::End => "End",
                Key::Backspace => "Backspace",
                Key::Del => "Del",
                Key::Enter => "Enter",
                Key::ShiftTab => "Shift-Tab",
                Key::Tab => "Tab",
                Key::Ins => "Ins",
                Key::Esc => "Esc",
                _ => "Missing key label",
            }),
        }
    }
}

#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Event {
    CharEvent(char),
    KeyEvent(Key),
}

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>Update for latest ncurses-rs fix<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>>),
}

#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Key {
    /// Both Enter and numpad Enter
    Enter,
    /// Tabulation key
    Tab,
    ShiftTab,
    Left,
    Right,
    Up,
    Down,
    PageUp,
    PageDown,
    Backspace,
    Home,
    End,
    /// Delete key
    Del,
    ShiftDel,
    CtrlDel,
    /// Insert key
    Ins,
    /// Escape key. Often buffered by the terminal,
    /// may appear with a delay or along with the next key.
    Esc,
    // Left arrow while shift is pressed
    CtrlPageUp,
    CtrlPageDown,
    ShiftLeft,
    ShiftRight,
    CtrlShiftLeft,
    CtrlShiftRight,
    CtrlLeft,
    CtrlRight,
    CtrlUp,
    CtrlDown,
    F(u8),
    CtrlF(u8),
    ShiftF(u8),
    CtrlShiftF(u8),
    CtrlChar(char),
    Unknown(i32),
}

impl Key {
    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,
            // Those keys don't seem to be documented...
            515 => Key::CtrlDel,
            521 => Key::CtrlDown,
            541 => Key::CtrlLeft,
            542 => Key::CtrlShiftLeft,
            546 => Key::CtrlPageDown,
            551 => Key::CtrlPageUp,
            556 => Key::CtrlRight,
            557 => Key::CtrlShiftRight,
            562 => Key::CtrlUp,
            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_PPAGE => Key::PageUp,
            ncurses::KEY_NPAGE => Key::PageDown,
            ncurses::KEY_HOME => Key::Home,
            ncurses::KEY_END => Key::End,
            ncurses::KEY_SDC => Key::ShiftDel,
            // All Fn keys use the same enum with associated number
            f @ ncurses::KEY_F1 ... ncurses::KEY_F15 => Key::F((f - ncurses::KEY_F0) as u8),
            f @ 281 ... 291 => Key::ShiftF((f - 281 + 5) as u8),
            f @ 293 ... 303 => Key::CtrlF((f - 293 + 5) as u8),
            f @ 305 ... 315 => 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::Left => "Left",
                Key::Right => "Right",
                Key::Down => "Down",
                Key::Up => "Up",
                Key::CtrlShiftLeft => "Ctrl-Shift-Left",
                Key::CtrlShiftRight => "Ctrl-Shift-Right",
                Key::ShiftLeft => "Shift-Left",
                Key::ShiftRight => "Shift-Right",
                Key::ShiftDel => "Shift-Del",
                Key::CtrlDel => "Ctrl-Del",
                Key::CtrlLeft => "Ctrl-Left",
                Key::CtrlRight => "Ctrl-Right",
                Key::CtrlUp => "Ctrl-Up",
                Key::CtrlDown => "Ctrl-Down",
                Key::CtrlPageUp => "Ctrl-PageUp",
                Key::CtrlPageDown => "Ctrl-PageDown",
                Key::PageUp => "PageUp",
                Key::PageDown => "PageDown",
                Key::Home => "Home",
                Key::End => "End",
                Key::Backspace => "Backspace",
                Key::Del => "Del",
                Key::Enter => "Enter",
                Key::ShiftTab => "Shift-Tab",
                Key::Tab => "Tab",
                Key::Ins => "Ins",
                Key::Esc => "Esc",
                _ => "Missing key label",
            }),
        }
    }
}

#[derive(PartialEq,Eq,Clone,Copy,Hash)]
pub enum Event {
    CharEvent(char),
    KeyEvent(Key),
}

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|>