<commit_before>use super::{WebsocatConfiguration2, SpecifierStack, SpecifierClass};
use std::rc::Rc;

#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
pub enum StdioUsageStatus {
    /// Does not use standard input or output at all
    None,
    /// Uses a reuser for connecting multiple peers at stdio, not distinguishing between IsItself and Indirectly
    WithReuser,
    /// Stdio wrapped into something (but not the reuser)
    Indirectly,
    /// Is the `-` or `stdio:` or `threadedstdio:` itself.
    IsItself,
}

trait ClassExt {
    fn is_stdio(&self) -> bool;
    fn is_reuser(&self) -> bool;
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl ClassExt for Rc<SpecifierClass> {
    fn is_stdio(&self) -> bool {
        [
            "StdioClass",
            "ThreadedStdioClass",
            "ThreadedStdioSubstituteClass",
        ].contains(&self.get_name())
    }
    fn is_reuser(&self) -> bool {
        [
            "ReuserClass",
            "BroadcastReuserClass",
        ].contains(&self.get_name())
    }
}

pub trait SpecifierStackExt {
    fn stdio_usage_status(&self) -> StdioUsageStatus;
    fn reuser_count(&self) -> usize;
    fn contains(&self, t: &'static str) -> bool;
    fn is_multiconnect(&self) -> bool;
    fn is_stream_oriented(&self) -> bool;
}
impl SpecifierStackExt for SpecifierStack {
    fn stdio_usage_status(&self) -> StdioUsageStatus {
        use self::StdioUsageStatus::*;

        if ! self.addrtype.is_stdio() {
            return None;
        }

        let mut sus: StdioUsageStatus = IsItself;

        for overlay in self.overlays.iter().rev() {
            if overlay.is_reuser() {
                sus = WithReuser;
            } else if sus == IsItself {
                sus = Indirectly;
            }
        }
        sus
    }
    fn reuser_count(&self) -> usize {
        let mut c = 0;
        for overlay in self.overlays.iter() {
            if overlay.is_reuser() {
                c += 1;
            }
        }
        c
    }
    fn contains(&self, t: &'static str) -> bool {
        for overlay in self.overlays.iter() {
            if overlay.get_name() == t {
                return true;
            }
        }
        self.addrtype.get_name() == t
    }
    fn is_multiconnect(&self) -> bool {
        use super::ClassMulticonnectStatus::*;
        match self.addrtype.multiconnect_status() {
            MultiConnect => (),
            SingleConnect => return false,
            MulticonnectnessDependsOnInnerType => unreachable!(),
        }
        for overlay in self.overlays.iter().rev() {
            match overlay.multiconnect_status() {
                MultiConnect => (),
                SingleConnect => return false,
                MulticonnectnessDependsOnInnerType => (),
            }
        }
        return true;
    }
    fn is_stream_oriented(&self) -> bool {
        use super::ClassMessageBoundaryStatus::*;
        let mut q = match self.addrtype.message_boundary_status() {
            StreamOriented => true,
            MessageOriented => false,
            MessageBoundaryStatusDependsOnInnerType => unreachable!(),
        };
        for overlay in self.overlays.iter().rev() {
            match overlay.message_boundary_status() {
                StreamOriented => q=true,
                MessageOriented => q=false,
                MessageBoundaryStatusDependsOnInnerType => (),
            }
        }
        return q;
    }
}

impl WebsocatConfiguration2 {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn websocket_used(&self) -> bool {
        false
        || self.contains_class("WsConnectClass")
        || self.contains_class("WsClientClass")
        || self.contains_class("WsClientSecureClass")
        || self.contains_class("WsServerClass")
    }

    pub fn contains_class(&self, x:&'static str) -> bool {
        self.s1.contains(x) || self.s2.contains(x)
    }

    pub fn get_exec_parameter(&self) -> Option<&str> {
        if self.s1.addrtype.get_name() == "ExecClass" {
            return Some(self.s1.addr.as_str());
        }
        if self.s2.addrtype.get_name() == "ExecClass" {
            return Some(self.s2.addr.as_str());
        }
        None
    }

    pub fn lint_and_fixup<F>(&mut self, on_warning: Rc<F>) -> super::Result<()>
        where F: for<'a> Fn(&'a str) -> () + 'static
    {
        let mut reuser_has_been_inserted = false;
        let multiconnect = !self.opts.oneshot && self.s1.is_multiconnect();
        use self::StdioUsageStatus::{IsItself, WithReuser, Indirectly, None};
        match (self.s1.stdio_usage_status(), self.s2.stdio_usage_status()) {
            (_, None) => (),
            (None, WithReuser) => (),
            (None, IsItself) | (None, Indirectly) => {
                if multiconnect {
                    self.s2.overlays.insert(0,
                        Rc::new(super::broadcast_reuse_peer::BroadcastReuserClass));
                    reuser_has_been_inserted = true;
                }
            },
            (IsItself, IsItself) => {
                info!("Special mode, expection from usual one-stdio rule. Acting like `cat(1)`");
                self.s2 = SpecifierStack::from_str("mirror:")?;
                if self.opts.unidirectional ^ self.opts.unidirectional_reverse {
                    self.opts.unidirectional = false;
                    self.opts.unidirectional_reverse = false;
                }
                return Ok(());
            },
            (_, _) => {
                Err("Too many usages of stdin/stdout. Specify it either on left or right address, not on both.")?;
            }
        }

        if self.s1.reuser_count() + self.s2.reuser_count() > 1 {
            if reuser_has_been_inserted {
                error!("The reuser you specified conflicts with automatically inserted reuser based on usage of stdin/stdout in multiconnect mode.");
            }
            Err("Too many usages of connection reuser. Please limit to only one instance.")?;
        }

        if !self.opts.no_auto_linemode && self.opts.websocket_text_mode {
            match (self.s1.is_stream_oriented(), self.s2.is_stream_oriented()) {
                (false,false) => {},
                (true,true) => {},
                (true,false) => {
                    info!("Auto-inserting the line mode");
                    self.s1.overlays.insert(0,
                        Rc::new(super::line_peer::Line2MessageClass));
                    self.s2.overlays.insert(0,
                        Rc::new(super::line_peer::Message2LineClass));
                },
                (false, true) => {
                    info!("Auto-inserting the line mode");
                    self.s2.overlays.insert(0,
                        Rc::new(super::line_peer::Line2MessageClass));
                    self.s1.overlays.insert(0,
                        Rc::new(super::line_peer::Message2LineClass));
                }
            }
        }

        if !self.opts.oneshot && self.s2.is_multiconnect() && !self.s1.is_multiconnect() {
            on_warning("You have specified a listener on the right (as the second positional argument) instead of on the left. It will only serve one connection.\nChange arguments order to enable multiple parallel connections or use --oneshot argument to make single connection explicit.");
        }

        if multiconnect && (self.s2.addrtype.get_name() == "WriteFileClass" || self.s2.addrtype.get_name() == "AppendFileClass") && self.s2.reuser_count() == 0 {
            info!("Auto-inserting the reuser");
            self.s2.overlays.push(Rc::new(super::primitive_reuse_peer::ReuserClass));
        }

        if self.s1.addrtype.get_name() == "ExecClass" && self.s2.addrtype.get_name() == "ExecClass" {
            Err("Can't use exec: more than one time. Replace one of them with sh-c: or cmd:.")?;
        }

        if let Some(x) = self.get_exec_parameter() {
            if self.opts.exec_args.is_empty() && x.contains(' ') {
                on_warning("Warning: you specified exec: without the corresponding --exec-args at the end of command line. Unlike in cmd: or sh-c:, spaces inside exec:'s direct parameter are interpreted as part of program name, not as separator.");
            }
        }

        // TODO: UDP connect oneshot mode

        // TODO: tests for the linter
        Ok(())
    }
}

<commit_msg>A todo.<commit_after>use super::{WebsocatConfiguration2, SpecifierStack, SpecifierClass};
use std::rc::Rc;

#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
pub enum StdioUsageStatus {
    /// Does not use standard input or output at all
    None,
    /// Uses a reuser for connecting multiple peers at stdio, not distinguishing between IsItself and Indirectly
    WithReuser,
    /// Stdio wrapped into something (but not the reuser)
    Indirectly,
    /// Is the `-` or `stdio:` or `threadedstdio:` itself.
    IsItself,
}

trait ClassExt {
    fn is_stdio(&self) -> bool;
    fn is_reuser(&self) -> bool;
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl ClassExt for Rc<SpecifierClass> {
    fn is_stdio(&self) -> bool {
        [
            "StdioClass",
            "ThreadedStdioClass",
            "ThreadedStdioSubstituteClass",
        ].contains(&self.get_name())
    }
    fn is_reuser(&self) -> bool {
        [
            "ReuserClass",
            "BroadcastReuserClass",
        ].contains(&self.get_name())
    }
}

pub trait SpecifierStackExt {
    fn stdio_usage_status(&self) -> StdioUsageStatus;
    fn reuser_count(&self) -> usize;
    fn contains(&self, t: &'static str) -> bool;
    fn is_multiconnect(&self) -> bool;
    fn is_stream_oriented(&self) -> bool;
}
impl SpecifierStackExt for SpecifierStack {
    fn stdio_usage_status(&self) -> StdioUsageStatus {
        use self::StdioUsageStatus::*;

        if ! self.addrtype.is_stdio() {
            return None;
        }

        let mut sus: StdioUsageStatus = IsItself;

        for overlay in self.overlays.iter().rev() {
            if overlay.is_reuser() {
                sus = WithReuser;
            } else if sus == IsItself {
                sus = Indirectly;
            }
        }
        sus
    }
    fn reuser_count(&self) -> usize {
        let mut c = 0;
        for overlay in self.overlays.iter() {
            if overlay.is_reuser() {
                c += 1;
            }
        }
        c
    }
    fn contains(&self, t: &'static str) -> bool {
        for overlay in self.overlays.iter() {
            if overlay.get_name() == t {
                return true;
            }
        }
        self.addrtype.get_name() == t
    }
    fn is_multiconnect(&self) -> bool {
        use super::ClassMulticonnectStatus::*;
        match self.addrtype.multiconnect_status() {
            MultiConnect => (),
            SingleConnect => return false,
            MulticonnectnessDependsOnInnerType => unreachable!(),
        }
        for overlay in self.overlays.iter().rev() {
            match overlay.multiconnect_status() {
                MultiConnect => (),
                SingleConnect => return false,
                MulticonnectnessDependsOnInnerType => (),
            }
        }
        return true;
    }
    fn is_stream_oriented(&self) -> bool {
        use super::ClassMessageBoundaryStatus::*;
        let mut q = match self.addrtype.message_boundary_status() {
            StreamOriented => true,
            MessageOriented => false,
            MessageBoundaryStatusDependsOnInnerType => unreachable!(),
        };
        for overlay in self.overlays.iter().rev() {
            match overlay.message_boundary_status() {
                StreamOriented => q=true,
                MessageOriented => q=false,
                MessageBoundaryStatusDependsOnInnerType => (),
            }
        }
        return q;
    }
}

impl WebsocatConfiguration2 {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn websocket_used(&self) -> bool {
        false
        || self.contains_class("WsConnectClass")
        || self.contains_class("WsClientClass")
        || self.contains_class("WsClientSecureClass")
        || self.contains_class("WsServerClass")
    }

    pub fn contains_class(&self, x:&'static str) -> bool {
        self.s1.contains(x) || self.s2.contains(x)
    }

    pub fn get_exec_parameter(&self) -> Option<&str> {
        if self.s1.addrtype.get_name() == "ExecClass" {
            return Some(self.s1.addr.as_str());
        }
        if self.s2.addrtype.get_name() == "ExecClass" {
            return Some(self.s2.addr.as_str());
        }
        None
    }

    pub fn lint_and_fixup<F>(&mut self, on_warning: Rc<F>) -> super::Result<()>
        where F: for<'a> Fn(&'a str) -> () + 'static
    {
        let mut reuser_has_been_inserted = false;
        let multiconnect = !self.opts.oneshot && self.s1.is_multiconnect();
        use self::StdioUsageStatus::{IsItself, WithReuser, Indirectly, None};
        match (self.s1.stdio_usage_status(), self.s2.stdio_usage_status()) {
            (_, None) => (),
            (None, WithReuser) => (),
            (None, IsItself) | (None, Indirectly) => {
                if multiconnect {
                    self.s2.overlays.insert(0,
                        Rc::new(super::broadcast_reuse_peer::BroadcastReuserClass));
                    reuser_has_been_inserted = true;
                }
            },
            (IsItself, IsItself) => {
                info!("Special mode, expection from usual one-stdio rule. Acting like `cat(1)`");
                self.s2 = SpecifierStack::from_str("mirror:")?;
                if self.opts.unidirectional ^ self.opts.unidirectional_reverse {
                    self.opts.unidirectional = false;
                    self.opts.unidirectional_reverse = false;
                }
                return Ok(());
            },
            (_, _) => {
                Err("Too many usages of stdin/stdout. Specify it either on left or right address, not on both.")?;
            }
        }

        if self.s1.reuser_count() + self.s2.reuser_count() > 1 {
            if reuser_has_been_inserted {
                error!("The reuser you specified conflicts with automatically inserted reuser based on usage of stdin/stdout in multiconnect mode.");
            }
            Err("Too many usages of connection reuser. Please limit to only one instance.")?;
        }

        if !self.opts.no_auto_linemode && self.opts.websocket_text_mode {
            match (self.s1.is_stream_oriented(), self.s2.is_stream_oriented()) {
                (false,false) => {},
                (true,true) => {},
                (true,false) => {
                    info!("Auto-inserting the line mode");
                    // TODO: insert after reuser, not before
                    self.s1.overlays.insert(0,
                        Rc::new(super::line_peer::Line2MessageClass));
                    self.s2.overlays.insert(0,
                        Rc::new(super::line_peer::Message2LineClass));
                },
                (false, true) => {
                    info!("Auto-inserting the line mode");
                    self.s2.overlays.insert(0,
                        Rc::new(super::line_peer::Line2MessageClass));
                    self.s1.overlays.insert(0,
                        Rc::new(super::line_peer::Message2LineClass));
                }
            }
        }

        if !self.opts.oneshot && self.s2.is_multiconnect() && !self.s1.is_multiconnect() {
            on_warning("You have specified a listener on the right (as the second positional argument) instead of on the left. It will only serve one connection.\nChange arguments order to enable multiple parallel connections or use --oneshot argument to make single connection explicit.");
        }

        if multiconnect && (self.s2.addrtype.get_name() == "WriteFileClass" || self.s2.addrtype.get_name() == "AppendFileClass") && self.s2.reuser_count() == 0 {
            info!("Auto-inserting the reuser");
            self.s2.overlays.push(Rc::new(super::primitive_reuse_peer::ReuserClass));
        }

        if self.s1.addrtype.get_name() == "ExecClass" && self.s2.addrtype.get_name() == "ExecClass" {
            Err("Can't use exec: more than one time. Replace one of them with sh-c: or cmd:.")?;
        }

        if let Some(x) = self.get_exec_parameter() {
            if self.opts.exec_args.is_empty() && x.contains(' ') {
                on_warning("Warning: you specified exec: without the corresponding --exec-args at the end of command line. Unlike in cmd: or sh-c:, spaces inside exec:'s direct parameter are interpreted as part of program name, not as separator.");
            }
        }

        // TODO: UDP connect oneshot mode

        // TODO: tests for the linter
        Ok(())
    }
}

<|endoftext|>


<commit_before>use std::io::{self, Error};
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::mem;

use libc::{socket, recvfrom, sendto, close, AF_PACKET, SOCK_RAW, AF_AX25,
    sockaddr, socklen_t, sockaddr_ll, c_void, c_int, c_char, c_ulong};

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

pub struct NetDev {
    pub name: String,
    pub ifindex: i32
}

pub struct Ax25RawSocket {
    fd: i32
}

impl Ax25RawSocket {
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket {
                fd: fd
            })
        }
    }

    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(())
        }
    }

    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            match l {
                Ok(line) => {
                    let device_name = line.trim().split(":").next().unwrap();
                    if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                        devices.push(net_dev);
                    }
                },
                Err(_) => ()
            }
        }
        Ok(devices)
    }

    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8]
        };

        match unsafe {
            let sa_ptr = mem::transmute::<*const sockaddr_ll, *const sockaddr>(&sa);
            sendto(self.fd, prefixed_frame.as_ptr() as *const c_void, prefixed_frame.len(),
                0, sa_ptr, mem::size_of_val(&sa) as socklen_t)
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(())
        }
    }

    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = mem::transmute::<*mut sockaddr_ll, *mut sockaddr>(&mut addr_struct);
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len(), 0, sa_ptr, &mut sa_in_sz) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize
            };
        }
        let ref valid_buf = buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.into_iter()
            .skip_while(|&c| *c == 0)
            .cloned()
            .collect();
        Ok(filtered)
    }
}

fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as i8;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex: ifindex
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default()
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24]
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union {
            data: [0; 24]
        }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(((self.data[0] as c_int) << 24) + ((self.data[1] as c_int) << 16)
                       + ((self.data[2] as c_int) << 8) + ((self.data[3] as c_int)))
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + ((self.data[1] as u16)))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8].iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Some(addr) = String::from_utf8(addr_utf8).ok() {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}<commit_msg>Add doc comments to linux module<commit_after>use std::io::{self, Error};
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::mem;

use libc::{socket, recvfrom, sendto, close, AF_PACKET, SOCK_RAW, AF_AX25,
    sockaddr, socklen_t, sockaddr_ll, c_void, c_int, c_char, c_ulong};

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket {
                fd: fd
            })
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(())
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            match l {
                Ok(line) => {
                    let device_name = line.trim().split(":").next().unwrap();
                    if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                        devices.push(net_dev);
                    }
                },
                Err(_) => ()
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8]
        };

        match unsafe {
            let sa_ptr = mem::transmute::<*const sockaddr_ll, *const sockaddr>(&sa);
            sendto(self.fd, prefixed_frame.as_ptr() as *const c_void, prefixed_frame.len(),
                0, sa_ptr, mem::size_of_val(&sa) as socklen_t)
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(())
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = mem::transmute::<*mut sockaddr_ll, *mut sockaddr>(&mut addr_struct);
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len(), 0, sa_ptr, &mut sa_in_sz) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize
            };
        }
        let ref valid_buf = buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.into_iter()
            .skip_while(|&c| *c == 0)
            .cloned()
            .collect();
        Ok(filtered)
    }
}

fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as i8;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex: ifindex
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default()
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24]
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union {
            data: [0; 24]
        }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(((self.data[0] as c_int) << 24) + ((self.data[1] as c_int) << 16)
                       + ((self.data[2] as c_int) << 8) + ((self.data[3] as c_int)))
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + ((self.data[1] as u16)))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8].iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Some(addr) = String::from_utf8(addr_utf8).ok() {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}<|endoftext|>


<commit_before>use std::ffi::CString;
use std::path::PathBuf;
use libc::readlink;

pub fn get_executable_path() -> Option<PathBuf> {
    fn get_executable_path(len: usize) -> Option<CString> {
        let mut buf = Vec::with_capacity(len);
        let proc_path = CString::new("/proc/self/exe").expect("path is hardcoded so this should never fail");

        unsafe {
            let ret = readlink(proc_path.as_ptr(), buf.as_mut_ptr(), len);
            if ret < 0 {
                None
            } else if (ret as usize) < len {
                buf.set_len(ret as usize);
                CString::new(buf.iter().map(|c| *c as u8).collect::<Vec<_>>()).ok()
            } else {
                //the buffer wasn't big enough, try again with a larger buffer
                get_executable_path(len * 2)
            }
        }
    }

    get_executable_path(256)
        .and_then(|p| p.into_string().ok())
        .map(|p| p.into())
}<commit_msg>Cleanup the linux implementation<commit_after>use std::fs::read_link;
use std::path::PathBuf;

pub fn get_executable_path() -> Option<PathBuf> {
    read_link("/proc/self/exe").ok()
}<|endoftext|>


<commit_before>use std::{
    env,
    path::{Path, PathBuf},
};

#[cfg(feature = "snappy")]
const SNAPPY_VERSION: &'static str = "1.1.7";
const LEVELDB_VERSION: &'static str = "1.22";
/// Directory name within `$OUT_DIR` where the static libraries should be built.
const LIBDIR: &'static str = "lib";

#[cfg(feature = "snappy")]
fn build_snappy() -> PathBuf {
    println!("[snappy] Building");

    let outdir = env::var("OUT_DIR").unwrap();
    let libdir = Path::new(&outdir).join(LIBDIR);

    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let dest_prefix =
        cmake::Config::new(Path::new("deps").join(format!("snappy-{}", SNAPPY_VERSION)))
            .define("BUILD_SHARED_LIBS", "OFF")
            .define("SNAPPY_BUILD_TESTS", "OFF")
            .define("HAVE_LIBZ", "OFF")
            .define("CMAKE_INSTALL_LIBDIR", &libdir)
            .build();

    assert_eq!(
        dest_prefix.join(LIBDIR),
        libdir,
        "CMake should build Snappy in provided LIBDIR"
    );
    println!("cargo:rustc-link-search=native={}", libdir.display());
    println!("cargo:rustc-link-lib=static=snappy");

    dest_prefix
}

fn build_leveldb(snappy_prefix: Option<PathBuf>) {
    println!("[leveldb] Building");

    let outdir = env::var("OUT_DIR").unwrap();
    let libdir = Path::new(&outdir).join(LIBDIR);

    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let mut config =
        cmake::Config::new(Path::new("deps").join(format!("leveldb-{}", LEVELDB_VERSION)));
    config
        .define("LEVELDB_BUILD_TESTS", "OFF")
        .define("LEVELDB_BUILD_BENCHMARKS", "OFF")
        .define("CMAKE_INSTALL_LIBDIR", &libdir);
    if let Some(snappy_prefix) = snappy_prefix {
        env::set_var(
            "LDFLAGS",
            format!("-L{}", snappy_prefix.join(LIBDIR).display()),
        );
        config
            .define("HAVE_SNAPPY", "ON")
            .cflag(format!("-I{}", snappy_prefix.join("include").display()))
            .cxxflag(format!("-I{}", snappy_prefix.join("include").display()));
    } else {
        config.define("HAVE_SNAPPY", "OFF");
    }
    let dest_prefix = config.build();

    assert_eq!(
        dest_prefix.join(LIBDIR),
        libdir,
        "CMake should build LevelDB in provided LIBDIR"
    );
    println!("cargo:rustc-link-search=native={}", libdir.display());
    println!("cargo:rustc-link-lib=static=leveldb");
}

fn main() {
    println!("[build] Started");

    // If we have the appropriate feature, then we build snappy.
    #[cfg(feature = "snappy")]
    let snappy_prefix = Some(build_snappy());
    #[cfg(not(feature = "snappy"))]
    let snappy_prefix: Option<PathBuf> = None;

    // Build LevelDB
    build_leveldb(snappy_prefix);

    // Link to the standard C++ library
    let target = env::var("TARGET").unwrap();
    if target.contains("apple") || target.contains("freebsd") {
        println!("cargo:rustc-link-lib=c++");
    } else if target.contains("gnu") || target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=stdc++");
    }

    println!("[build] Finished");
}
<commit_msg>Manually merge #18 (by @hoverbear)<commit_after>use std::{
    env,
    path::{Path, PathBuf},
};

#[cfg(feature = "snappy")]
const SNAPPY_VERSION: &'static str = "1.1.7";
const LEVELDB_VERSION: &'static str = "1.22";
/// Directory name within `$OUT_DIR` where the static libraries should be built.
const LIBDIR: &'static str = "lib";

#[cfg(feature = "snappy")]
fn build_snappy() -> PathBuf {
    println!("[snappy] Building");

    let outdir = env::var("OUT_DIR").unwrap();
    let libdir = Path::new(&outdir).join(LIBDIR);

    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let dest_prefix =
        cmake::Config::new(Path::new("deps").join(format!("snappy-{}", SNAPPY_VERSION)))
            .define("BUILD_SHARED_LIBS", "OFF")
            .define("SNAPPY_BUILD_TESTS", "OFF")
            .define("HAVE_LIBZ", "OFF")
            .define("CMAKE_INSTALL_LIBDIR", &libdir)
            .build();

    assert_eq!(
        dest_prefix.join(LIBDIR),
        libdir,
        "CMake should build Snappy in provided LIBDIR"
    );
    println!("cargo:rustc-link-search=native={}", libdir.display());
    println!("cargo:rustc-link-lib=static=snappy");

    dest_prefix
}

fn build_leveldb(snappy_prefix: Option<PathBuf>) {
    println!("[leveldb] Building");

    let outdir = env::var("OUT_DIR").unwrap();
    let libdir = Path::new(&outdir).join(LIBDIR);

    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let mut config =
        cmake::Config::new(Path::new("deps").join(format!("leveldb-{}", LEVELDB_VERSION)));
    config
        .define("LEVELDB_BUILD_TESTS", "OFF")
        .define("LEVELDB_BUILD_BENCHMARKS", "OFF")
        .define("CMAKE_INSTALL_LIBDIR", &libdir);
    if let Some(snappy_prefix) = snappy_prefix {
        #[cfg(target_env = "msvc")]
        let ldflags = format!("/LIBPATH:{}", snappy_prefix.join(LIBDIR).display());
        #[cfg(not(target_env = "msvc"))]
        let ldflags = format!("-L{}", snappy_prefix.join(LIBDIR).display());

        env::set_var(
            "LDFLAGS",
            ldflags
        );

        config
            .define("HAVE_SNAPPY", "ON")
            .cflag(format!("-I{}", snappy_prefix.join("include").display()))
            .cxxflag(format!("-I{}", snappy_prefix.join("include").display()));
    } else {
        config.define("HAVE_SNAPPY", "OFF");
    }
    let dest_prefix = config.build();

    assert_eq!(
        dest_prefix.join(LIBDIR),
        libdir,
        "CMake should build LevelDB in provided LIBDIR"
    );
    println!("cargo:rustc-link-search=native={}", libdir.display());
    println!("cargo:rustc-link-lib=static=leveldb");
}

fn main() {
    println!("[build] Started");

    // If we have the appropriate feature, then we build snappy.
    #[cfg(feature = "snappy")]
    let snappy_prefix = Some(build_snappy());
    #[cfg(not(feature = "snappy"))]
    let snappy_prefix: Option<PathBuf> = None;

    // Build LevelDB
    build_leveldb(snappy_prefix);

    // Link to the standard C++ library
    let target = env::var("TARGET").unwrap();
    if target.contains("apple") || target.contains("freebsd") {
        println!("cargo:rustc-link-lib=c++");
    } else if target.contains("gnu") || target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=stdc++");
    }

    println!("[build] Finished");
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::iter::Iterator;

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

fn parse_ingredient(s: &str) -> Option<([i32; 4], i32)> {
    if let (Some(capacity),
            Some(durability),
            Some(flavor),
            Some(texture),
            Some(calories)) = scan_fmt!(s,
                                        "{*}: capacity {d}, durability {d}, flavor {d}, texture \
                                         {d}, calories {d}",
                                        i32,
                                        i32,
                                        i32,
                                        i32,
                                        i32) {
        Some(([capacity, durability, flavor, texture], calories))
    } else {
        None
    }
}

fn parse_input(input: &str) -> Option<(Vec<[i32; 4]>, Vec<i32>)> {
    input.lines()
         .map(parse_ingredient)
         .collect::<Option<Vec<_>>>()
         .map(|v| v.iter().cloned().unzip())
}

pub fn main() -> Vec<String> {
    let budget: i32 = 100;
    if let Some((ingredients, calories)) = parse_input(DATA) {

        // generate all possible recipes
        let recipes = (0..budget + 1).flat_map(move |a| {
            (0..budget + 1 - a).flat_map(move |b| {
                (0..budget + 1 - a - b).map(move |c| {
                    let d = budget - a - b - c;
                    [a, b, c, d]
                })
            })
        });

        // score all the cookies
        let cookies = recipes.map(|r| {
                                 // a recipe is a list of 4 amounts
                                 // for each amount pair with the ingredient data
                                 let scores =
                                 Iterator::zip(r.iter(), ingredients.iter())
                                     .map(|(i, w)| {
                                         // and multiply the ingredient properties by the amount
                                         [i * w[0], i * w[1], i * w[2], i * w[3]]
                                     })
                                     .fold([0; 4], |acc, i| {
                                         // now add up the weighted properties of each ingredient
                                         [acc[0] + i[0],
                                          acc[1] + i[1],
                                          acc[2] + i[2],
                                          acc[3] + i[3]]
                                     })
                                     .iter()
                                     .fold(1, |acc, &i| {
                                         // now we've reduced each recipe to scores for 4 properties
                                         // drop any negative scores, and multiply them together for
                                         // a total cookie score
                                         acc * max(0, i)
                                     });

                                 // for calories, multiply amount by ingredient info and sum
                                 let calories = Iterator::zip(r.iter(), calories.iter())
                                                    .map(|(i, c)| i * c)
                                                    .sum::<i32>();
                                 (scores, calories)
                             })
                             .collect::<Vec<(i32, i32)>>();

        vec![cookies.iter().map(|c| c.0).max().unwrap_or(0).to_string(),
             cookies.iter().filter(|c| c.1 == 500).map(|c| c.0).max().unwrap_or(0).to_string()]
    } else {
        vec![]
    }
}

#[cfg(test)]
mod test {
}
<commit_msg>day 15: functions are good, handle varying input sizes<commit_after>use std::cmp::max;
use std::iter;
use std::iter::Iterator;

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

pub fn main() -> Vec<String> {
    let budget: i32 = 100;
    if let Some((ingredients, calories)) = parse_input(DATA) {

        // generate all possible recipes
        let recipes = cookie_recipes(budget, ingredients.len());

        // score all the cookies
        let cookies = recipes.map(|r| {
                                 // a recipe is a list of 4 amounts
                                 // for each amount pair with the ingredient data
                                 let score = score_recipe(&r, &ingredients);
                                 let calories = get_calories(&r, &calories);
                                 (score, calories)
                             })
                             .collect::<Vec<(i32, i32)>>();

        vec![cookies.iter().map(|c| c.0).max().unwrap_or(0).to_string(),
             cookies.iter().filter(|c| c.1 == 500).map(|c| c.0).max().unwrap_or(0).to_string()]
    } else {
        vec![]
    }
}

fn parse_ingredient(s: &str) -> Option<([i32; 4], i32)> {
    if let (Some(capacity),
            Some(durability),
            Some(flavor),
            Some(texture),
            Some(calories)) = scan_fmt!(s,
                                        "{*}: capacity {d}, durability {d}, flavor {d}, texture \
                                         {d}, calories {d}",
                                        i32,
                                        i32,
                                        i32,
                                        i32,
                                        i32) {
        Some(([capacity, durability, flavor, texture], calories))
    } else {
        None
    }
}

fn parse_input(input: &str) -> Option<(Vec<[i32; 4]>, Vec<i32>)> {
    input.lines()
         .map(parse_ingredient)
         .collect::<Option<Vec<_>>>()
         .map(|v| v.iter().cloned().unzip())
}

// return an iterator over all "recipes"
// which are just 'count' numbers that add up to the total ingredient budget
fn cookie_recipes(budget: i32, count: usize) -> Box<Iterator<Item = Vec<i32>>> {
    if count == 1 {
        box iter::once(vec![budget])
    } else {
        box (0..budget + 1).flat_map(move |n| {
            cookie_recipes(budget - n, count - 1).map(move |mut v| {
                v.push(n);
                v
            })
        })
    }
}

fn score_recipe(r: &[i32], ingredients: &[[i32; 4]]) -> i32 {
    Iterator::zip(r.iter(), ingredients.iter())
        .map(|(i, w)| {
            // multiply the ingredient properties by the amount
            [i * w[0], i * w[1], i * w[2], i * w[3]]
        })
        .fold([0; 4], |acc, i| {
            // add up the weighted properties of each ingredient
            [acc[0] + i[0], acc[1] + i[1], acc[2] + i[2], acc[3] + i[3]]
        })
        .iter()
        .fold(1, |acc, &i| {
            // each recipe has been reduced to scores for 4 properties
            // drop any negative scores, and multiply the rest together for
            // a total cookie score
            acc * max(0, i)
        })
}

fn get_calories(r: &[i32], calories: &[i32]) -> i32 {
    // multiply amount by ingredient calorie info and sum
    Iterator::zip(r.iter(), calories.iter())
        .map(|(i, c)| i * c)
        .sum::<i32>()
}

#[cfg(test)]
mod test {
    use super::{parse_input, cookie_recipes, score_recipe, get_calories};

    const EXAMPLE_DATA: [&'static str; 2] = ["Butterscotch: capacity -1, durability -2, flavor \
                                              6, texture 3, calories 8",
                                             "Cinnamon: capacity 2, durability 3, flavor -2, \
                                              texture -1, calories 3"];

    #[test]
    fn examples_1() {
        if let Some((ingredients, _)) = parse_input(&EXAMPLE_DATA.join("\n")) {
            let recipes = cookie_recipes(100, ingredients.len());
            let cookies = recipes.map(|r| score_recipe(&r, &ingredients));
            assert_eq!(cookies.max(), Some(62842880));
        } else {
            panic!("EXAMPLE_DATA failed to parse");
        }
    }

    #[test]
    fn examples_2() {
        if let Some((ingredients, calories)) = parse_input(&EXAMPLE_DATA.join("\n")) {
            let recipes = cookie_recipes(100, ingredients.len());
            let cookies = recipes.map(|r| {
                (score_recipe(&r, &ingredients), get_calories(&r, &calories))
            });
            let soln = cookies.filter(|c| c.1 == 500)
                              .map(|c| c.0)
                              .max();
            assert_eq!(soln, Some(57600000));
        } else {
            panic!("EXAMPLE_DATA failed to parse");
        }
    }
}
<|endoftext|>


<commit_before>//! jsonrpc errors
use serde::de::{Deserialize, Deserializer, SeqVisitor, MapVisitor, Error as DeError};
use serde::ser::{Serialize, Serializer};
use serde_json::value;
use super::Value;

#[derive(Debug, PartialEq)]
pub enum ErrorCode {
	/// Invalid JSON was received by the server.
	/// An error occurred on the server while parsing the JSON text.
	ParseError,
	/// The JSON sent is not a valid Request object.
	InvalidRequest,
	/// The method does not exist / is not available.
	MethodNotFound,
	/// Invalid method parameter(s).
	InvalidParams,
	/// Internal JSON-RPC error.
	InternalError,
	/// Reserved for implementation-defined server-errors.
	ServerError(i64)
}

impl ErrorCode {
	pub fn code(&self) -> i64 {
		match *self {
			ErrorCode::ParseError => -32700,
			ErrorCode::InvalidRequest => -32600,
			ErrorCode::MethodNotFound => -32601,
			ErrorCode::InvalidParams => -32602,
			ErrorCode::InternalError => -32603,
			ErrorCode::ServerError(code) => code
		}
	}

	pub fn description(&self) -> String {
		let desc = match *self {
			ErrorCode::ParseError => "Parse error.",
			ErrorCode::InvalidRequest => "Invalid request.",
			ErrorCode::MethodNotFound => "Method not found.",
			ErrorCode::InvalidParams => "Invalid params.",
			ErrorCode::InternalError => "Internal error.",
			ErrorCode::ServerError(_) => "Server error.",
		};
		desc.to_string()
	}
}

impl Deserialize for ErrorCode {
	fn deserialize<D>(deserializer: &mut D) -> Result<ErrorCode, D::Error>
	where D: Deserializer {
		let v = try!(Value::deserialize(deserializer));
		match v.as_i64() {
			Some(-32700) => Ok(ErrorCode::ParseError),
			Some(-32600) => Ok(ErrorCode::InvalidRequest),
			Some(-32601) => Ok(ErrorCode::MethodNotFound),
			Some(-32602) => Ok(ErrorCode::InvalidParams),
			Some(-32603) => Ok(ErrorCode::InternalError),
			Some(code) => Ok(ErrorCode::ServerError(code)),
			_ => unreachable!()
		}

	}
}

impl Serialize for ErrorCode {
	fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
	where S: Serializer {
		serializer.serialize_i64(self.code())
	}
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Error {
	pub code: ErrorCode,
	pub message: String,
	pub data: Option<Value>
}

impl Error {
	pub fn new(code: ErrorCode) -> Self {
		Error {
			message: code.description(),
			code: code,
			data: None
		}
	}

	pub fn parse_error() -> Self {
		Self::new(ErrorCode::ParseError)
	}

	pub fn invalid_request() -> Self {
		Self::new(ErrorCode::InvalidRequest)
	}

	pub fn method_not_found() -> Self {
		Self::new(ErrorCode::MethodNotFound)
	}

	pub fn invalid_params() -> Self {
		Self::new(ErrorCode::InvalidParams)
	}

	pub fn internal_error() -> Self {
		Self::new(ErrorCode::InternalError)
	}
}
<commit_msg>Remove Periods for ErrorCode Description<commit_after>//! jsonrpc errors
use serde::de::{Deserialize, Deserializer, SeqVisitor, MapVisitor, Error as DeError};
use serde::ser::{Serialize, Serializer};
use serde_json::value;
use super::Value;

#[derive(Debug, PartialEq)]
pub enum ErrorCode {
	/// Invalid JSON was received by the server.
	/// An error occurred on the server while parsing the JSON text.
	ParseError,
	/// The JSON sent is not a valid Request object.
	InvalidRequest,
	/// The method does not exist / is not available.
	MethodNotFound,
	/// Invalid method parameter(s).
	InvalidParams,
	/// Internal JSON-RPC error.
	InternalError,
	/// Reserved for implementation-defined server-errors.
	ServerError(i64)
}

impl ErrorCode {
	pub fn code(&self) -> i64 {
		match *self {
			ErrorCode::ParseError => -32700,
			ErrorCode::InvalidRequest => -32600,
			ErrorCode::MethodNotFound => -32601,
			ErrorCode::InvalidParams => -32602,
			ErrorCode::InternalError => -32603,
			ErrorCode::ServerError(code) => code
		}
	}

	pub fn description(&self) -> String {
		let desc = match *self {
			ErrorCode::ParseError => "Parse error",
			ErrorCode::InvalidRequest => "Invalid request",
			ErrorCode::MethodNotFound => "Method not found",
			ErrorCode::InvalidParams => "Invalid params",
			ErrorCode::InternalError => "Internal error",
			ErrorCode::ServerError(_) => "Server error",
		};
		desc.to_string()
	}
}

impl Deserialize for ErrorCode {
	fn deserialize<D>(deserializer: &mut D) -> Result<ErrorCode, D::Error>
	where D: Deserializer {
		let v = try!(Value::deserialize(deserializer));
		match v.as_i64() {
			Some(-32700) => Ok(ErrorCode::ParseError),
			Some(-32600) => Ok(ErrorCode::InvalidRequest),
			Some(-32601) => Ok(ErrorCode::MethodNotFound),
			Some(-32602) => Ok(ErrorCode::InvalidParams),
			Some(-32603) => Ok(ErrorCode::InternalError),
			Some(code) => Ok(ErrorCode::ServerError(code)),
			_ => unreachable!()
		}

	}
}

impl Serialize for ErrorCode {
	fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
	where S: Serializer {
		serializer.serialize_i64(self.code())
	}
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Error {
	pub code: ErrorCode,
	pub message: String,
	pub data: Option<Value>
}

impl Error {
	pub fn new(code: ErrorCode) -> Self {
		Error {
			message: code.description(),
			code: code,
			data: None
		}
	}

	pub fn parse_error() -> Self {
		Self::new(ErrorCode::ParseError)
	}

	pub fn invalid_request() -> Self {
		Self::new(ErrorCode::InvalidRequest)
	}

	pub fn method_not_found() -> Self {
		Self::new(ErrorCode::MethodNotFound)
	}

	pub fn invalid_params() -> Self {
		Self::new(ErrorCode::InvalidParams)
	}

	pub fn internal_error() -> Self {
		Self::new(ErrorCode::InternalError)
	}
}
<|endoftext|>


<commit_before>//! Our error enum.

use std::num::ParseFloatError;
use std::str::ParseBoolError;

use las;
#[cfg(feature = "rxp-source")]
use rivlib;
use sdc;
#[cfg(feature = "sdf-source")]
use sdf;

/// Our custom error handling type.
#[derive(Debug)]
pub enum Error {
    /// Invalid options to a source or sink.
    InvalidOption(String),
    /// A point is missing a dimension that is required by someone else, usually a `Sink`.
    MissingDimension(String),
    /// A wrapper around a las error.
    Las(las::Error),
    /// A wrapper around `std::str::ParseBoolError`.
    ParseBool(ParseBoolError),
    /// A wrapper around `std::num::ParseFloatError`.
    ParseFloat(ParseFloatError),
    #[cfg(feature = "rxp-source")]
    /// A wrapper around an rxp error.
    Rxp(rivlib::Error),
    /// A wrapper around an sdc error.
    Sdc(sdc::Error),
    #[cfg(feature = "sdf-source")]
    /// A wrapper around an sdf error.
    Sdf(sdf::Error),
    /// The type of sink could not be determined.
    UndefinedSink,
    /// The type of source could not be determined.
    UndefinedSource,
}

impl From<las::Error> for Error {
    fn from(err: las::Error) -> Error {
        Error::Las(err)
    }
}

impl From<ParseBoolError> for Error {
    fn from(err: ParseBoolError) -> Error {
        Error::ParseBool(err)
    }
}

impl From<ParseFloatError> for Error {
    fn from(err: ParseFloatError) -> Error {
        Error::ParseFloat(err)
    }
}

#[cfg(feature = "rxp-source")]
impl From<rivlib::Error> for Error {
    fn from(err: rivlib::Error) -> Error {
        Error::Rxp(err)
    }
}

impl From<sdc::Error> for Error {
    fn from(err: sdc::Error) -> Error {
        Error::Sdc(err)
    }
}

#[cfg(feature = "sdf-source")]
impl From<sdf::Error> for Error {
    fn from(err: sdf::Error) -> Error {
        Error::Sdf(err)
    }
}
<commit_msg>Implement error for Error<commit_after>//! Our error enum.

use std::error;
use std::fmt;
use std::num::ParseFloatError;
use std::str::ParseBoolError;

use las;
#[cfg(feature = "rxp-source")]
use rivlib;
use sdc;
#[cfg(feature = "sdf-source")]
use sdf;

/// Our custom error handling type.
#[derive(Debug)]
pub enum Error {
    /// Invalid options to a source or sink.
    InvalidOption(String),
    /// A point is missing a dimension that is required by someone else, usually a `Sink`.
    MissingDimension(String),
    /// A wrapper around a las error.
    Las(las::Error),
    /// A wrapper around `std::str::ParseBoolError`.
    ParseBool(ParseBoolError),
    /// A wrapper around `std::num::ParseFloatError`.
    ParseFloat(ParseFloatError),
    #[cfg(feature = "rxp-source")]
    /// A wrapper around an rxp error.
    Rxp(rivlib::Error),
    /// A wrapper around an sdc error.
    Sdc(sdc::Error),
    #[cfg(feature = "sdf-source")]
    /// A wrapper around an sdf error.
    Sdf(sdf::Error),
    /// The type of sink could not be determined.
    UndefinedSink,
    /// The type of source could not be determined.
    UndefinedSource,
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidOption(_) => "invalid option",
            Error::MissingDimension(_) => "missing dimension",
            Error::Las(ref err) => err.description(),
            Error::ParseBool(ref err) => err.description(),
            Error::ParseFloat(ref err) => err.description(),
            #[cfg(feature = "rxp-source")]
            Error::Rxp(ref err) => err.description(),
            Error::Sdc(ref err) => err.description(),
            #[cfg(feature = "sdf-source")]
            Error::Sdf(ref err) => err.description(),
            Error::UndefinedSink => "undefined sink",
            Error::UndefinedSource => "undefined source",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Las(ref err) => Some(err),
            Error::ParseBool(ref err) => Some(err),
            Error::ParseFloat(ref err) => Some(err),
            #[cfg(feature = "rxp-source")]
            Error::Rxp(ref err) => Some(err),
            Error::Sdc(ref err) => Some(err),
            #[cfg(feature = "sdf-source")]
            Error::Sdf(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::InvalidOption(ref s) => write!(f, "Invalid option: {}", s),
            Error::MissingDimension(ref s) => write!(f, "Missing dimension: {}", s),
            Error::Las(ref err) => write!(f, "las error: {}", err),
            Error::ParseBool(ref err) => write!(f, "Parse bool error: {}", err),
            Error::ParseFloat(ref err) => write!(f, "Parse float error: {}", err),
            #[cfg(feature = "rxp-source")]
            Error::Rxp(ref err) => write!(f, "rxp error: {}", err),
            Error::Sdc(ref err) => write!(f, "sdc error: {}", err),
            #[cfg(feature = "sdf-source")]
            Error::Sdf(ref err) => write!(f, "sdf error: {}", err),
            Error::UndefinedSink => write!(f, "Undefined sink"),
            Error::UndefinedSource => write!(f, "Undefined source"),
        }
    }
}

impl From<las::Error> for Error {
    fn from(err: las::Error) -> Error {
        Error::Las(err)
    }
}

impl From<ParseBoolError> for Error {
    fn from(err: ParseBoolError) -> Error {
        Error::ParseBool(err)
    }
}

impl From<ParseFloatError> for Error {
    fn from(err: ParseFloatError) -> Error {
        Error::ParseFloat(err)
    }
}

#[cfg(feature = "rxp-source")]
impl From<rivlib::Error> for Error {
    fn from(err: rivlib::Error) -> Error {
        Error::Rxp(err)
    }
}

impl From<sdc::Error> for Error {
    fn from(err: sdc::Error) -> Error {
        Error::Sdc(err)
    }
}

#[cfg(feature = "sdf-source")]
impl From<sdf::Error> for Error {
    fn from(err: sdf::Error) -> Error {
        Error::Sdf(err)
    }
}
<|endoftext|>


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

/// Errors that can be returned from various operations
///
pub enum Error {
    /// Returned if menu Menu function isn't supported
    MenusNotSupported,
    /// Menu already exists
    MenuExists(String),
    /// Menu already exists
    WindowCreate(String),
    /// Unable to Update
    UpdateFailed(String),
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(formatter, "Menus not supported"),
            Error::MenuExists(_) => write!(formatter, "Menu already exists"),
            Error::WindowCreate(_) => write!(formatter, "Failed to create window"),
            Error::UpdateFailed(_) => write!(formatter, "Failed to Update"),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(fmt, "{}", self),
            Error::MenuExists(ref e) => write!(fmt, "{}, {:?}", self, e),
            Error::WindowCreate(ref e) => write!(fmt, "{}, {:?}", self, e),
            Error::UpdateFailed(ref e) => write!(fmt, "{}, {:?}", self, e),
        }
    }
}

impl StdError for Error {}
<commit_msg>Minor update to error.rs (#258)<commit_after>use std::error::Error as StdError;
use std::fmt;

/// Errors that can be returned from various operations
///
pub enum Error {
    /// Returned if menu Menu function isn't supported
    MenusNotSupported,
    /// Menu already exists
    MenuExists(String),
    /// Failed to create window
    WindowCreate(String),
    /// Unable to Update
    UpdateFailed(String),
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(formatter, "Menus not supported"),
            Error::MenuExists(_) => write!(formatter, "Menu already exists"),
            Error::WindowCreate(_) => write!(formatter, "Failed to create window"),
            Error::UpdateFailed(_) => write!(formatter, "Failed to Update"),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::MenusNotSupported => write!(fmt, "{}", self),
            Error::MenuExists(ref e) => write!(fmt, "{}, {:?}", self, e),
            Error::WindowCreate(ref e) => write!(fmt, "{}, {:?}", self, e),
            Error::UpdateFailed(ref e) => write!(fmt, "{}, {:?}", self, e),
        }
    }
}

impl StdError for Error {}
<|endoftext|>


<commit_before>//! Defines error types used by this library.

use Value;

use xml::reader::Error as XmlError;
use xml::common::TextPosition;

use std::{error, io};
use std::fmt::{self, Formatter, Display};
use std::collections::BTreeMap;

/// Errors that can occur when trying to perform an XML-RPC request.
///
/// This can be a lower-level error (for example, the HTTP request failed), a problem with the
/// server (maybe it's not implementing XML-RPC correctly), or just a failure to execute the
/// operation.
#[derive(Debug)]
pub struct Error(RequestErrorKind);

impl Error {
    /// If this `Error` was caused by the server responding with a `<fault>` response,
    /// returns the `Fault` in question.
    pub fn fault(&self) -> Option<&Fault> {
        match self.0 {
            RequestErrorKind::Fault(ref fault) => Some(fault),
            _ => None,
        }
    }
}

#[doc(hidden)]  // hide internal impl
impl From<RequestErrorKind> for Error {
    fn from(kind: RequestErrorKind) -> Self {
        Error(kind)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.0.description()
    }

    fn cause(&self) -> Option<&error::Error> {
        self.0.cause()
    }
}

#[derive(Debug)]
pub enum RequestErrorKind {
    /// The response could not be parsed. This can happen when the server doesn't correctly
    /// implement the XML-RPC spec.
    ParseError(ParseError),

    /// A communication error originating from the transport used to perform the request.
    TransportError(Box<error::Error + Send + Sync>),

    /// The server returned a `<fault>` response, indicating that the execution of the call
    /// encountered a problem (for example, an invalid (number of) arguments was passed).
    Fault(Fault),
}

impl From<ParseError> for RequestErrorKind {
    fn from(e: ParseError) -> Self {
        RequestErrorKind::ParseError(e)
    }
}

impl From<Fault> for RequestErrorKind {
    fn from(f: Fault) -> Self {
        RequestErrorKind::Fault(f)
    }
}

impl Display for RequestErrorKind {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            RequestErrorKind::ParseError(ref err) => write!(fmt, "parse error: {}", err),
            RequestErrorKind::TransportError(ref err) => write!(fmt, "transport error: {}", err),
            RequestErrorKind::Fault(ref err) => write!(fmt, "{}", err),
        }
    }
}

impl error::Error for RequestErrorKind {
    fn description(&self) -> &str {
        match *self {
            RequestErrorKind::ParseError(_) => "parse error",
            RequestErrorKind::TransportError(_) => "transport error",
            RequestErrorKind::Fault(_) => "server returned a fault",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            RequestErrorKind::ParseError(ref err) => Some(err),
            RequestErrorKind::TransportError(ref err) => Some(err.as_ref()),
            RequestErrorKind::Fault(ref err) => Some(err),
        }
    }
}

/// Describes possible error that can occur when parsing a `Response`.
#[derive(Debug, PartialEq)]
pub enum ParseError {
    /// Error while parsing (malformed?) XML.
    XmlError(XmlError),

    /// Could not parse the given CDATA as XML-RPC value.
    ///
    /// For example, `<value><int>AAA</int></value>` describes an invalid value.
    InvalidValue {
        /// The type for which an invalid value was supplied (eg. `int` or `dateTime.iso8601`).
        for_type: &'static str,
        /// The value we encountered, as a string.
        found: String,
        /// The position of the invalid value inside the XML document.
        position: TextPosition,
    },

    /// Found an unexpected tag, attribute, etc.
    UnexpectedXml {
        /// A short description of the kind of data that was expected.
        expected: String,
        found: Option<String>,
        /// The position of the unexpected data inside the XML document.
        position: TextPosition,
    }
}

impl From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::XmlError(e)
    }
}

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

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::XmlError(ref err) => write!(fmt, "malformed XML: {}", err),
            ParseError::InvalidValue {
                for_type,
                ref found,
                ref position,
            } => write!(fmt, "invalid value for type '{}' at {}: {}", for_type, position, found),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: None,
            } => {
                write!(fmt, "unexpected XML at {} (expected {})", position, expected)
            }
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: Some(ref found),
            } => {
                write!(fmt, "unexpected XML at {} (expected {}, found {})", position, expected, found)
            }
        }
    }
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::XmlError(ref err) => err.description(),
            ParseError::InvalidValue { .. } => "invalid value for type",
            ParseError::UnexpectedXml { .. } => "unexpected XML content",
        }
    }
}

/// A `<fault>` response, indicating that a request failed.
///
/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
/// `<fault>` case, further describing the error.
#[derive(Debug, PartialEq, Eq)]
pub struct Fault {
    /// An application-specific error code.
    pub fault_code: i32,
    /// Human-readable error description.
    pub fault_string: String,
}

impl Fault {
    /// Creates a `Fault` from a `Value`.
    ///
    /// The `Value` must be a `Value::Struct` with a `faultCode` and `faultString` field (and no
    /// other fields).
    ///
    /// Returns `None` if the value isn't a valid `Fault`.
    pub fn from_value(value: &Value) -> Option<Self> {
        match *value {
            Value::Struct(ref map) => {
                if map.len() != 2 {
                    // incorrect field count
                    return None;
                }

                match (map.get("faultCode"), map.get("faultString")) {
                    (Some(&Value::Int(fault_code)), Some(&Value::String(ref fault_string))) => {
                        Some(Fault {
                            fault_code,
                            fault_string: fault_string.to_string(),
                        })
                    }
                    _ => None
                }
            }
            _ => None
        }
    }

    /// Turns this `Fault` into an equivalent `Value`.
    ///
    /// The returned value can be parsed back into a `Fault` using `Fault::from_value` or returned
    /// as a `<fault>` error response by serializing it into a `<fault></fault>` tag.
    pub fn to_value(&self) -> Value {
        let mut map = BTreeMap::new();
        map.insert("faultCode".to_string(), Value::from(self.fault_code));
        map.insert("faultString".to_string(), Value::from(self.fault_string.as_ref()));

        Value::Struct(map)
    }
}

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

impl error::Error for Fault {
    fn description(&self) -> &str {
        &self.fault_string
    }
}

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

    use std::error;

    #[test]
    fn fault_roundtrip() {
        let input = Fault {
            fault_code: -123456,
            fault_string: "The Bald Lazy House Jumps Over The Hyperactive Kitten".to_string()
        };

        assert_eq!(Fault::from_value(&input.to_value()), Some(input));
    }

    #[test]
    fn error_impls_error() {
        fn assert_error<T: error::Error>() {}

        assert_error::<Error>();
    }

    #[test]
    fn error_is_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}

        assert_send_sync::<Error>();
    }
}
<commit_msg>Use/impl Error::source instead of cause<commit_after>//! Defines error types used by this library.

use Value;

use xml::reader::Error as XmlError;
use xml::common::TextPosition;

use std::{error, io};
use std::fmt::{self, Formatter, Display};
use std::collections::BTreeMap;

/// Errors that can occur when trying to perform an XML-RPC request.
///
/// This can be a lower-level error (for example, the HTTP request failed), a problem with the
/// server (maybe it's not implementing XML-RPC correctly), or just a failure to execute the
/// operation.
#[derive(Debug)]
pub struct Error(RequestErrorKind);

impl Error {
    /// If this `Error` was caused by the server responding with a `<fault>` response,
    /// returns the `Fault` in question.
    pub fn fault(&self) -> Option<&Fault> {
        match self.0 {
            RequestErrorKind::Fault(ref fault) => Some(fault),
            _ => None,
        }
    }
}

#[doc(hidden)]  // hide internal impl
impl From<RequestErrorKind> for Error {
    fn from(kind: RequestErrorKind) -> Self {
        Error(kind)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.0.description()
    }

    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        self.0.source()
    }
}

#[derive(Debug)]
pub enum RequestErrorKind {
    /// The response could not be parsed. This can happen when the server doesn't correctly
    /// implement the XML-RPC spec.
    ParseError(ParseError),

    /// A communication error originating from the transport used to perform the request.
    TransportError(Box<error::Error + Send + Sync>),

    /// The server returned a `<fault>` response, indicating that the execution of the call
    /// encountered a problem (for example, an invalid (number of) arguments was passed).
    Fault(Fault),
}

impl From<ParseError> for RequestErrorKind {
    fn from(e: ParseError) -> Self {
        RequestErrorKind::ParseError(e)
    }
}

impl From<Fault> for RequestErrorKind {
    fn from(f: Fault) -> Self {
        RequestErrorKind::Fault(f)
    }
}

impl Display for RequestErrorKind {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            RequestErrorKind::ParseError(ref err) => write!(fmt, "parse error: {}", err),
            RequestErrorKind::TransportError(ref err) => write!(fmt, "transport error: {}", err),
            RequestErrorKind::Fault(ref err) => write!(fmt, "{}", err),
        }
    }
}

impl error::Error for RequestErrorKind {
    fn description(&self) -> &str {
        match *self {
            RequestErrorKind::ParseError(_) => "parse error",
            RequestErrorKind::TransportError(_) => "transport error",
            RequestErrorKind::Fault(_) => "server returned a fault",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            RequestErrorKind::ParseError(ref err) => Some(err),
            RequestErrorKind::TransportError(ref err) => Some(err.as_ref()),
            RequestErrorKind::Fault(ref err) => Some(err),
        }
    }
}

/// Describes possible error that can occur when parsing a `Response`.
#[derive(Debug, PartialEq)]
pub enum ParseError {
    /// Error while parsing (malformed?) XML.
    XmlError(XmlError),

    /// Could not parse the given CDATA as XML-RPC value.
    ///
    /// For example, `<value><int>AAA</int></value>` describes an invalid value.
    InvalidValue {
        /// The type for which an invalid value was supplied (eg. `int` or `dateTime.iso8601`).
        for_type: &'static str,
        /// The value we encountered, as a string.
        found: String,
        /// The position of the invalid value inside the XML document.
        position: TextPosition,
    },

    /// Found an unexpected tag, attribute, etc.
    UnexpectedXml {
        /// A short description of the kind of data that was expected.
        expected: String,
        found: Option<String>,
        /// The position of the unexpected data inside the XML document.
        position: TextPosition,
    }
}

impl From<XmlError> for ParseError {
    fn from(e: XmlError) -> Self {
        ParseError::XmlError(e)
    }
}

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

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::XmlError(ref err) => write!(fmt, "malformed XML: {}", err),
            ParseError::InvalidValue {
                for_type,
                ref found,
                ref position,
            } => write!(fmt, "invalid value for type '{}' at {}: {}", for_type, position, found),
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: None,
            } => {
                write!(fmt, "unexpected XML at {} (expected {})", position, expected)
            }
            ParseError::UnexpectedXml {
                ref expected,
                ref position,
                found: Some(ref found),
            } => {
                write!(fmt, "unexpected XML at {} (expected {}, found {})", position, expected, found)
            }
        }
    }
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::XmlError(ref err) => err.description(),
            ParseError::InvalidValue { .. } => "invalid value for type",
            ParseError::UnexpectedXml { .. } => "unexpected XML content",
        }
    }
}

/// A `<fault>` response, indicating that a request failed.
///
/// The XML-RPC specification requires that a `<faultCode>` and `<faultString>` is returned in the
/// `<fault>` case, further describing the error.
#[derive(Debug, PartialEq, Eq)]
pub struct Fault {
    /// An application-specific error code.
    pub fault_code: i32,
    /// Human-readable error description.
    pub fault_string: String,
}

impl Fault {
    /// Creates a `Fault` from a `Value`.
    ///
    /// The `Value` must be a `Value::Struct` with a `faultCode` and `faultString` field (and no
    /// other fields).
    ///
    /// Returns `None` if the value isn't a valid `Fault`.
    pub fn from_value(value: &Value) -> Option<Self> {
        match *value {
            Value::Struct(ref map) => {
                if map.len() != 2 {
                    // incorrect field count
                    return None;
                }

                match (map.get("faultCode"), map.get("faultString")) {
                    (Some(&Value::Int(fault_code)), Some(&Value::String(ref fault_string))) => {
                        Some(Fault {
                            fault_code,
                            fault_string: fault_string.to_string(),
                        })
                    }
                    _ => None
                }
            }
            _ => None
        }
    }

    /// Turns this `Fault` into an equivalent `Value`.
    ///
    /// The returned value can be parsed back into a `Fault` using `Fault::from_value` or returned
    /// as a `<fault>` error response by serializing it into a `<fault></fault>` tag.
    pub fn to_value(&self) -> Value {
        let mut map = BTreeMap::new();
        map.insert("faultCode".to_string(), Value::from(self.fault_code));
        map.insert("faultString".to_string(), Value::from(self.fault_string.as_ref()));

        Value::Struct(map)
    }
}

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

impl error::Error for Fault {
    fn description(&self) -> &str {
        &self.fault_string
    }
}

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

    use std::error;

    #[test]
    fn fault_roundtrip() {
        let input = Fault {
            fault_code: -123456,
            fault_string: "The Bald Lazy House Jumps Over The Hyperactive Kitten".to_string()
        };

        assert_eq!(Fault::from_value(&input.to_value()), Some(input));
    }

    #[test]
    fn error_impls_error() {
        fn assert_error<T: error::Error>() {}

        assert_error::<Error>();
    }

    #[test]
    fn error_is_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}

        assert_send_sync::<Error>();
    }
}
<|endoftext|>


<commit_before>quick_error! {
    /// Template parsing error
    #[derive(Debug, Clone)]
    pub enum TemplateError {
        UnclosedBraces {
            description("closing braces `}}` expected but eof reached")
        }
        UnexpectedClosingBraces {
            description("can't close braces `}}` at this location")
        }
        MismatchingClosedHelper(open: String, closed: String) {
            display("helper {:?} was opened, but {:?} is closing",
                open, closed)
            description("wrong name of closing helper")
        }
        UnclosedHelper(name: String) {
            display("helper {:?} was not closed on end of file", name)
            description("some helper was not closed on end of file")
        }
    }
}
<commit_msg>Fix typos in error messages<commit_after>quick_error! {
    /// Template parsing error
    #[derive(Debug, Clone)]
    pub enum TemplateError {
        UnclosedBraces {
            description("closing braces `}}` expected but EOF reached")
        }
        UnexpectedClosingBraces {
            description("can't close braces `}}` at this location")
        }
        MismatchingClosedHelper(open: String, closed: String) {
            display("helper {:?} was opened, but {:?} is closing",
                open, closed)
            description("wrong name of closing helper")
        }
        UnclosedHelper(name: String) {
            display("helper {:?} was not closed on the end of file", name)
            description("some helper was not closed on the end of file")
        }
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate unicode_segmentation;
extern crate regex;

use std::cmp::min;
use std::error::Error;
use self::unicode_segmentation::UnicodeSegmentation;
use self::walkdir::WalkDir;
use self::regex::Regex;

pub fn find_duplicates(dir: &str, expected_dist: i32, filter: Option<String>) -> Result<(), String> {
    let paths = try!(get_paths(dir, filter));
    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);
            }
        }
    }
    Ok(())
}

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 + min(
                    dp[i][j - 1],
                    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(dir: &str, filter: Option<String>) -> Result<Vec<NamePath>, String> {
    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: don't use unwrap
            let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
            let file_path = path.to_str().unwrap().to_string();
            match filter {
                Some(ref regex) => {
                    let re = match Regex::new(regex) {
                        Ok(regex) => { regex }
                        Err(err) => { return Err(err.description().to_string()) }
                    };
                    if re.is_match(&file_name) {
                        let name_path = NamePath{
                            name: file_name,
                            path: file_path,
                        };
                        name_paths.push(name_path);
                    }
                }
                None => {
                    let name_path = NamePath{
                        name: file_name,
                        path: file_path,
                    };
                    name_paths.push(name_path);
                }
            }
        }
    }
    Ok(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!(8, fdupe::get_paths(
            Path::new("src").join("testdata").to_str().unwrap(),
            Option::None).unwrap().len());

        assert_eq!(5, fdupe::get_paths(
            Path::new("src").join("testdata").to_str().unwrap(),
                Option::Some(String::from("test.*"))).unwrap().len());
    }

    #[test]
    fn test_find_duplicates() {
        fdupe::find_duplicates(
            Path::new("src").join("testdata").to_str().unwrap(), 3, Option::None);

        fdupe::find_duplicates(
            Path::new("src").join("testdata").to_str().unwrap(), 3,
                Option::Some(String::from("test.*")));
    }
}<commit_msg>Remove the unwrap and use proper error handling<commit_after>extern crate walkdir;
extern crate unicode_segmentation;
extern crate regex;

use std::cmp::min;
use std::error::Error;
use self::unicode_segmentation::UnicodeSegmentation;
use self::walkdir::WalkDir;
use self::regex::Regex;

pub fn find_duplicates(dir: &str, expected_dist: i32, filter: Option<String>) -> Result<(), String> {
    let paths = try!(get_paths(dir, filter));
    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);
            }
        }
    }
    Ok(())
}

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 + min(
                    dp[i][j - 1],
                    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(dir: &str, filter: Option<String>) -> Result<Vec<NamePath>, String> {
    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 file_name = match path.file_name() {
                Some(f1) => {
                    match f1.to_str() {
                        Some(f2) => { f2.to_string() }
                        None => { return Err(String::from("File name does not exist")) }
                    }
                }
                None => { return Err(String::from("File name does not exist")) }
            };
            let file_path = match path.to_str() {
                Some(p) => { p.to_string() }
                None => { return Err(String::from("Path does not exist")) }
            };
            match filter {
                Some(ref regex) => {
                    let re = match Regex::new(regex) {
                        Ok(regex) => { regex }
                        Err(err) => { return Err(err.description().to_string()) }
                    };
                    if re.is_match(&file_name) {
                        let name_path = NamePath{
                            name: file_name,
                            path: file_path,
                        };
                        name_paths.push(name_path);
                    }
                }
                None => {
                    let name_path = NamePath{
                        name: file_name,
                        path: file_path,
                    };
                    name_paths.push(name_path);
                }
            }
        }
    }
    Ok(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!(8, fdupe::get_paths(
            Path::new("src").join("testdata").to_str().unwrap(),
            Option::None).unwrap().len());

        assert_eq!(5, fdupe::get_paths(
            Path::new("src").join("testdata").to_str().unwrap(),
                Option::Some(String::from("test.*"))).unwrap().len());
    }

    #[test]
    fn test_find_duplicates() {
        match fdupe::find_duplicates(
            Path::new("src").join("testdata").to_str().unwrap(), 3, Option::None) {
            Ok(()) => {}
            Err(err) => { panic!(err) }
        }

        match fdupe::find_duplicates(
            Path::new("src").join("testdata").to_str().unwrap(), 3,
                Option::Some(String::from("test.*"))) {
            Ok(()) => {}
            Err(err) => { panic!(err) }
        }
    }
}<|endoftext|>