<commit_before>//! The editor

use std::collections::LinkedList;
use std::old_io::IoResult;
use cmd::Cmd;
use error::Result;

#[derive(Debug)]
pub struct Ed<D, W>
    where D: FnMut(&str) -> IoResult<()>,
          W: FnMut(&str) -> IoResult<Box<Writer>> {
    display: D,
    write: W,
    lines: LinkedList<String>,
    appending: bool,
}

impl<D, W> Ed<D, W>
    where D: FnMut(&str) -> IoResult<()>,
          W: FnMut(&str) -> IoResult<Box<Writer>> {
    pub fn new(display: D, write: W) -> Ed<D, W> {
        Ed {
            display: display,
            write: write,
            lines: LinkedList::new(),
            appending: false,
        }
    }

    pub fn run_line(&mut self, s: &str) -> Result<()> {
        if self.appending {
            if s == "." {
                self.appending = false;
            } else {
                self.lines.push_back(s.to_string());
            }
        } else {
            let cmd: Cmd = try!(s.parse());
            match cmd {
                Cmd::Append(..) => self.appending = true,
                Cmd::Print(..) => {
                    for line in &self.lines {
                        try!(self.display.call_mut((&line[..],)));
                    }
                },
                Cmd::Write(..) => {
                    let mut writer = try!(self.write.call_mut(("test.txt",)));
                    for line in &self.lines {
                        try!(writeln!(&mut writer, "{}", line));
                    }
                    try!(writer.flush());
                },
                Cmd::Quit => {},
            }
        }
        Ok(())
    }
}
<commit_msg>Simplify parsing of input command<commit_after>//! The editor

use std::collections::LinkedList;
use std::old_io::IoResult;
use cmd::Cmd;
use error::Result;

#[derive(Debug)]
pub struct Ed<D, W>
    where D: FnMut(&str) -> IoResult<()>,
          W: FnMut(&str) -> IoResult<Box<Writer>> {
    display: D,
    write: W,
    lines: LinkedList<String>,
    appending: bool,
}

impl<D, W> Ed<D, W>
    where D: FnMut(&str) -> IoResult<()>,
          W: FnMut(&str) -> IoResult<Box<Writer>> {
    pub fn new(display: D, write: W) -> Ed<D, W> {
        Ed {
            display: display,
            write: write,
            lines: LinkedList::new(),
            appending: false,
        }
    }

    pub fn run_line(&mut self, s: &str) -> Result<()> {
        if self.appending {
            if s == "." {
                self.appending = false;
            } else {
                self.lines.push_back(s.to_string());
            }
        } else {
            match try!(s.parse()) {
                Cmd::Append(..) => self.appending = true,
                Cmd::Print(..) => {
                    for line in &self.lines {
                        try!(self.display.call_mut((&line[..],)));
                    }
                },
                Cmd::Write(..) => {
                    let mut writer = try!(self.write.call_mut(("test.txt",)));
                    for line in &self.lines {
                        try!(writeln!(&mut writer, "{}", line));
                    }
                    try!(writer.flush());
                },
                Cmd::Quit => {},
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crossbeam::channel::{unbounded, Sender};
use fnv::FnvHashMap;
use ignore::{overrides, WalkBuilder, WalkState};
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, PathBuf};

use crate::cli;
use crate::lang;

pub fn visit_path_parallel(path: &PathBuf, globs: Vec<&str>) -> Vec<cli::LangOut> {
    let (ch_s, ch_r) = unbounded();
    let overrides = parse_overrides(path, globs);

    WalkBuilder::new(path)
        .threads(num_cpus::get() + 1)
        .overrides(overrides)
        .build_parallel()
        .run(|| {
            let mut buf = [0u8; 1 << 14];
            let mut map = Map {
                s: ch_s.clone(),
                map: FnvHashMap::default(),
            };
            Box::new(move |result| {
                let entry = match result {
                    Err(err) => {
                        println!("Error: {}", err);
                        return WalkState::Continue;
                    }
                    Ok(entry) => entry,
                };
                let path = entry.into_path();
                if path.is_dir() {
                    return WalkState::Continue;
                }
                let ext = match path.extension() {
                    None => return WalkState::Continue,
                    Some(ext) => ext,
                };
                let ext_str = match ext.to_str() {
                    None => return WalkState::Continue,
                    Some(ext_str) => ext_str,
                };
                let language = match lang::get_language(&ext_str.to_ascii_lowercase()) {
                    None => return WalkState::Continue,
                    Some(lang) => lang,
                };
                match lines_in_file(&path, &mut buf) {
                    Ok(lines) => {
                        let counter = map.map.entry(language).or_insert_with(LangResult::new);
                        counter.file_cnt += 1;
                        counter.line_cnt += lines;
                    }
                    Err(err) => {
                        println!("Error in {:?}: {}", &path, err);
                    }
                }
                WalkState::Continue
            })
        });
    drop(ch_s);

    let mut langs = FnvHashMap::default();
    for m in ch_r.iter() {
        for (&key, val) in m.iter() {
            let l = langs.entry(key).or_insert_with(LangResult::new);
            l.file_cnt += val.file_cnt;
            l.line_cnt += val.line_cnt;
        }
    }
    map_to_vec(langs)
}

fn lines_in_file(path: &Path, buf: &mut [u8]) -> io::Result<u64> {
    let mut file = File::open(path)?;
    let mut cnt = 1;
    loop {
        let n = file.read(buf)?;
        if n == 0 {
            return Ok(cnt as u64);
        }
        cnt += bytecount::count(&buf[0..n], b'\n');
    }
}

fn parse_overrides(path: &PathBuf, globs: Vec<&str>) -> overrides::Override {
    let mut override_builder = overrides::OverrideBuilder::new(path);
    for glob in globs.iter() {
        override_builder.add(glob).unwrap();
    }
    override_builder.build().unwrap()
}

fn map_to_vec(map: FnvHashMap<lang::Language, LangResult>) -> Vec<cli::LangOut> {
    let mut langs = Vec::with_capacity(map.len());
    for (key, val) in map.iter() {
        langs.push(cli::LangOut {
            language: *key,
            num_files: val.file_cnt,
            num_lines: val.line_cnt,
        });
    }
    langs.sort_by(|a, b| a.num_lines.cmp(&b.num_lines).reverse());
    langs
}

struct Map {
    s: Sender<FnvHashMap<lang::Language, LangResult>>,
    map: FnvHashMap<lang::Language, LangResult>,
}

impl Drop for Map {
    fn drop(&mut self) {
        self.s.send(self.map.clone()).unwrap();
    }
}

#[derive(Clone, Copy, Debug)]
struct LangResult {
    file_cnt: u64,
    line_cnt: u64,
}

impl LangResult {
    fn new() -> Self {
        LangResult {
            file_cnt: 0,
            line_cnt: 0,
        }
    }
}
<commit_msg>Print errors to stderr<commit_after>use crossbeam::channel::{unbounded, Sender};
use fnv::FnvHashMap;
use ignore::{overrides, WalkBuilder, WalkState};
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, PathBuf};

use crate::cli;
use crate::lang;

pub fn visit_path_parallel(path: &PathBuf, globs: Vec<&str>) -> Vec<cli::LangOut> {
    let (ch_s, ch_r) = unbounded();
    let overrides = parse_overrides(path, globs);

    WalkBuilder::new(path)
        .threads(num_cpus::get() + 1)
        .overrides(overrides)
        .build_parallel()
        .run(|| {
            let mut buf = [0u8; 1 << 14];
            let mut map = Map {
                s: ch_s.clone(),
                map: FnvHashMap::default(),
            };
            Box::new(move |result| {
                let entry = match result {
                    Err(err) => {
                        eprintln!("Error: {}", err);
                        return WalkState::Continue;
                    }
                    Ok(entry) => entry,
                };
                let path = entry.into_path();
                if path.is_dir() {
                    return WalkState::Continue;
                }
                let ext = match path.extension() {
                    None => return WalkState::Continue,
                    Some(ext) => ext,
                };
                let ext_str = match ext.to_str() {
                    None => return WalkState::Continue,
                    Some(ext_str) => ext_str,
                };
                let language = match lang::get_language(&ext_str.to_ascii_lowercase()) {
                    None => return WalkState::Continue,
                    Some(lang) => lang,
                };
                match lines_in_file(&path, &mut buf) {
                    Ok(lines) => {
                        let counter = map.map.entry(language).or_insert_with(LangResult::new);
                        counter.file_cnt += 1;
                        counter.line_cnt += lines;
                    }
                    Err(err) => {
                        eprintln!("Error: {:?}: {}", &path, err);
                    }
                }
                WalkState::Continue
            })
        });
    drop(ch_s);

    let mut langs = FnvHashMap::default();
    for m in ch_r.iter() {
        for (&key, val) in m.iter() {
            let l = langs.entry(key).or_insert_with(LangResult::new);
            l.file_cnt += val.file_cnt;
            l.line_cnt += val.line_cnt;
        }
    }
    map_to_vec(langs)
}

fn lines_in_file(path: &Path, buf: &mut [u8]) -> io::Result<u64> {
    let mut file = File::open(path)?;
    let mut cnt = 1;
    loop {
        let n = file.read(buf)?;
        if n == 0 {
            return Ok(cnt as u64);
        }
        cnt += bytecount::count(&buf[0..n], b'\n');
    }
}

fn parse_overrides(path: &PathBuf, globs: Vec<&str>) -> overrides::Override {
    let mut override_builder = overrides::OverrideBuilder::new(path);
    for glob in globs.iter() {
        override_builder.add(glob).unwrap();
    }
    override_builder.build().unwrap()
}

fn map_to_vec(map: FnvHashMap<lang::Language, LangResult>) -> Vec<cli::LangOut> {
    let mut langs = Vec::with_capacity(map.len());
    for (key, val) in map.iter() {
        langs.push(cli::LangOut {
            language: *key,
            num_files: val.file_cnt,
            num_lines: val.line_cnt,
        });
    }
    langs.sort_by(|a, b| a.num_lines.cmp(&b.num_lines).reverse());
    langs
}

struct Map {
    s: Sender<FnvHashMap<lang::Language, LangResult>>,
    map: FnvHashMap<lang::Language, LangResult>,
}

impl Drop for Map {
    fn drop(&mut self) {
        self.s.send(self.map.clone()).unwrap();
    }
}

#[derive(Clone, Copy, Debug)]
struct LangResult {
    file_cnt: u64,
    line_cnt: u64,
}

impl LangResult {
    fn new() -> Self {
        LangResult {
            file_cnt: 0,
            line_cnt: 0,
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(unix)]
use libc::*;
use net2::{TcpBuilder, TcpStreamExt};
#[cfg(unix)]
use nix::errno::Errno;
#[cfg(unix)]
use nix::sys::select;
#[cfg(unix)]
use nix::sys::socket;
#[cfg(unix)]
use nix::sys::time::{TimeVal, TimeValLike};
use std::io;
use std::mem;
use std::net::{TcpStream, SocketAddr, ToSocketAddrs};
use std::os::raw::*;
#[cfg(unix)]
use std::os::unix::prelude::*;
#[cfg(target_os = "windows")]
use std::os::windows::prelude::*;
use std::ptr;
use std::time::Duration;
#[cfg(target_os = "windows")]
use winapi::*;
#[cfg(target_os = "windows")]
use ws2_32::*;

pub struct MyTcpBuilder<T> {
    address: T,
    bind_address: Option<SocketAddr>,
    connect_timeout: Option<Duration>,
    read_timeout: Option<Duration>,
    write_timeout: Option<Duration>,
    keepalive_time_ms: Option<u32>,
}

impl<T: ToSocketAddrs> MyTcpBuilder<T> {
    pub fn keepalive_time_ms(&mut self, keepalive_time_ms: Option<u32>) -> &mut Self {
        self.keepalive_time_ms = keepalive_time_ms;
        self
    }

    pub fn write_timeout(&mut self, write_timeout: Option<Duration>) -> &mut Self {
        self.write_timeout = write_timeout;
        self
    }

    pub fn read_timeout(&mut self, read_timeout: Option<Duration>) -> &mut Self {
        self.read_timeout = read_timeout;
        self
    }

    pub fn bind_address<U>(&mut self, bind_address: Option<U>) -> &mut Self
        where U: Into<SocketAddr>
    {
        self.bind_address = bind_address.map(Into::into);
        self
    }

    pub fn connect_timeout(&mut self, timeout: Option<Duration>) -> &mut Self {
        self.connect_timeout = timeout;
        self
    }

    pub fn new(address: T) -> MyTcpBuilder<T> {
        MyTcpBuilder {
            address,
            bind_address: None,
            connect_timeout: None,
            read_timeout: None,
            write_timeout: None,
            keepalive_time_ms: None,
        }
    }

    pub fn connect(self) -> io::Result<TcpStream> {
        let MyTcpBuilder {
            address,
            bind_address,
            connect_timeout,
            read_timeout,
            write_timeout,
            keepalive_time_ms,
        } = self;
        let err_msg = if bind_address.is_none() {
            "could not connect to any address"
        } else {
            "could not connect to any address with specified bind address"
        };
        let err = io::Error::new(io::ErrorKind::Other, err_msg);
        address.to_socket_addrs()?
            .fold(Err(err), |prev, sock_addr| {
                prev.or_else(|_| {
                    let builder = if sock_addr.is_ipv4() {
                        TcpBuilder::new_v4()?
                    } else {
                        TcpBuilder::new_v6()?
                    };
                    if let Some(bind_address) = bind_address {
                        if bind_address.is_ipv4() == sock_addr.is_ipv4() {
                            builder.bind(bind_address)?;
                        }
                    }
                    if let Some(connect_timeout) = connect_timeout {
                        #[cfg(unix)]
                        connect_fd_timeout(builder.as_raw_fd(), &sock_addr, connect_timeout)?;
                        #[cfg(target_os = "windows")]
                        connect_fd_timeout(builder.as_raw_socket(), &sock_addr, connect_timeout)?;
                        builder.to_tcp_stream()
                    } else {
                        builder.connect(sock_addr)
                    }
                })
            })
            .and_then(|stream| {
                stream.set_read_timeout(read_timeout)?;
                stream.set_write_timeout(write_timeout)?;
                stream.set_keepalive_ms(keepalive_time_ms)?;
                Ok(stream)
            })
    }
}

#[cfg(unix)]
fn set_non_blocking(fd: RawFd, non_blocking: bool) -> io::Result<()> {
    let stream = unsafe { TcpStream::from_raw_fd(fd) };
    let result = stream.set_nonblocking(non_blocking);
    mem::forget(stream);
    result
}

#[cfg(not(unix))]
fn set_non_blocking(socket: RawSocket, non_blocking: bool) -> io::Result<()> {
    let stream = unsafe { TcpStream::from_raw_socket(socket) };
    let result = stream.set_nonblocking(non_blocking);
    mem::forget(stream);
    result
}

#[cfg(unix)]
fn connect_fd_timeout(fd: RawFd, sock_addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
    set_non_blocking(fd, true)?;

    let inet_addr = socket::InetAddr::from_std(sock_addr);
    let sock_addr = socket::SockAddr::Inet(inet_addr);
    match socket::connect(fd, &sock_addr) {
        Ok(_) => (),
        Err(err) => {
            match err.errno() {
                Errno::EALREADY |
                Errno::EINPROGRESS => (),
                errno => {
                    return Err(io::Error::from_raw_os_error(errno as i32));
                },
            }
        }
    }

    let mut fd_set = select::FdSet::new();
    let socket_fd = fd;
    fd_set.insert(socket_fd);
    let mut timeout_timeval = TimeVal::microseconds(timeout.as_secs() as i64 * 1000 * 1000);

    let select_res = select::select(
        socket_fd + 1,
        None,
        Some(&mut fd_set),
        None,
        Some(&mut timeout_timeval),
    )?;

    if select_res == -1 {
        return Err(io::Error::last_os_error());
    }

    if select_res != 1 {
        return Err(io::ErrorKind::TimedOut.into());
    }

    let socket_error_code = socket::getsockopt(
        socket_fd,
        socket::sockopt::SocketError,
    )?;

    if socket_error_code != 0 {
        return Err(io::Error::from_raw_os_error(socket_error_code));
    }

    set_non_blocking(fd, false)
}

#[cfg(not(unix))]
fn connect_fd_timeout(socket: RawSocket,
                      sock_addr: &SocketAddr,
                      timeout: Duration) -> io::Result<()> {
    set_non_blocking(socket, true)?;
    let (name, name_len) = match *sock_addr {
        SocketAddr::V4(ref a) => {
            (a as *const _ as *const _, mem::size_of_val(a) as c_int)
        },
        SocketAddr::V6(ref a) => {
            (a as *const _ as *const _, mem::size_of_val(a) as c_int)
        }
    };
    let result = unsafe { connect(socket, name, name_len) };
    if result == SOCKET_ERROR {
        let err = io::Error::last_os_error();
        match err.raw_os_error().map(|x| x as u32) {
            Some(WSAEWOULDBLOCK) => {
                let mut write_fds = fd_set {
                    fd_count: 1,
                    fd_array: [0; FD_SETSIZE]
                };
                write_fds.fd_array[0] = socket;
                let mut err_fds = write_fds.clone();
                let timeout = timeval {
                    tv_sec: timeout.as_secs() as c_long,
                    tv_usec: 0,
                };

                let result = unsafe {
                    select(0, ptr::null_mut(), &mut write_fds, &mut err_fds, &timeout)
                };

                if result == 0 {
                    return Err(io::ErrorKind::TimedOut.into());
                } else if result == SOCKET_ERROR {
                    return Err(io::Error::last_os_error());
                } else {
                    let mut error = None;
                    for i in 0..(err_fds.fd_count as usize) {
                        if err_fds.fd_array[i] == socket {
                            error = Some(true);
                        }
                    }
                    for i in 0..(write_fds.fd_count as usize) {
                        if write_fds.fd_array[i] == socket {
                            error = Some(false);
                        }
                    }
                    match error {
                        Some(false) => (),
                        Some(true) => {
                            let mut opt_val = 0i32;
                            let mut opt_len = mem::size_of::<i32>() as c_int;
                            let result = unsafe {
                                getsockopt(socket,
                                           SOL_SOCKET,
                                           SO_ERROR,
                                           &mut opt_val as *mut _ as *mut _,
                                           &mut opt_len)
                            };
                            return Err(io::Error::from_raw_os_error(result));
                        },
                        None => unreachable!(),
                    }
                }
            },
            _ => return Err(err),
        }
    }
    set_non_blocking(socket, false)
}
<commit_msg>Remove warnings<commit_after>use net2::{TcpBuilder, TcpStreamExt};
#[cfg(unix)]
use nix::errno::Errno;
#[cfg(unix)]
use nix::sys::select;
#[cfg(unix)]
use nix::sys::socket;
#[cfg(unix)]
use nix::sys::time::{TimeVal, TimeValLike};
use std::io;
use std::mem;
use std::net::{TcpStream, SocketAddr, ToSocketAddrs};
#[cfg(target_os = "windows")]
use std::os::raw::*;
#[cfg(unix)]
use std::os::unix::prelude::*;
#[cfg(target_os = "windows")]
use std::os::windows::prelude::*;
#[cfg(target_os = "windows")]
use std::ptr;
use std::time::Duration;
#[cfg(target_os = "windows")]
use winapi::*;
#[cfg(target_os = "windows")]
use ws2_32::*;

pub struct MyTcpBuilder<T> {
    address: T,
    bind_address: Option<SocketAddr>,
    connect_timeout: Option<Duration>,
    read_timeout: Option<Duration>,
    write_timeout: Option<Duration>,
    keepalive_time_ms: Option<u32>,
}

impl<T: ToSocketAddrs> MyTcpBuilder<T> {
    pub fn keepalive_time_ms(&mut self, keepalive_time_ms: Option<u32>) -> &mut Self {
        self.keepalive_time_ms = keepalive_time_ms;
        self
    }

    pub fn write_timeout(&mut self, write_timeout: Option<Duration>) -> &mut Self {
        self.write_timeout = write_timeout;
        self
    }

    pub fn read_timeout(&mut self, read_timeout: Option<Duration>) -> &mut Self {
        self.read_timeout = read_timeout;
        self
    }

    pub fn bind_address<U>(&mut self, bind_address: Option<U>) -> &mut Self
        where U: Into<SocketAddr>
    {
        self.bind_address = bind_address.map(Into::into);
        self
    }

    pub fn connect_timeout(&mut self, timeout: Option<Duration>) -> &mut Self {
        self.connect_timeout = timeout;
        self
    }

    pub fn new(address: T) -> MyTcpBuilder<T> {
        MyTcpBuilder {
            address,
            bind_address: None,
            connect_timeout: None,
            read_timeout: None,
            write_timeout: None,
            keepalive_time_ms: None,
        }
    }

    pub fn connect(self) -> io::Result<TcpStream> {
        let MyTcpBuilder {
            address,
            bind_address,
            connect_timeout,
            read_timeout,
            write_timeout,
            keepalive_time_ms,
        } = self;
        let err_msg = if bind_address.is_none() {
            "could not connect to any address"
        } else {
            "could not connect to any address with specified bind address"
        };
        let err = io::Error::new(io::ErrorKind::Other, err_msg);
        address.to_socket_addrs()?
            .fold(Err(err), |prev, sock_addr| {
                prev.or_else(|_| {
                    let builder = if sock_addr.is_ipv4() {
                        TcpBuilder::new_v4()?
                    } else {
                        TcpBuilder::new_v6()?
                    };
                    if let Some(bind_address) = bind_address {
                        if bind_address.is_ipv4() == sock_addr.is_ipv4() {
                            builder.bind(bind_address)?;
                        }
                    }
                    if let Some(connect_timeout) = connect_timeout {
                        #[cfg(unix)]
                        connect_fd_timeout(builder.as_raw_fd(), &sock_addr, connect_timeout)?;
                        #[cfg(target_os = "windows")]
                        connect_fd_timeout(builder.as_raw_socket(), &sock_addr, connect_timeout)?;
                        builder.to_tcp_stream()
                    } else {
                        builder.connect(sock_addr)
                    }
                })
            })
            .and_then(|stream| {
                stream.set_read_timeout(read_timeout)?;
                stream.set_write_timeout(write_timeout)?;
                stream.set_keepalive_ms(keepalive_time_ms)?;
                Ok(stream)
            })
    }
}

#[cfg(unix)]
fn set_non_blocking(fd: RawFd, non_blocking: bool) -> io::Result<()> {
    let stream = unsafe { TcpStream::from_raw_fd(fd) };
    let result = stream.set_nonblocking(non_blocking);
    mem::forget(stream);
    result
}

#[cfg(target_os = "windows")]
fn set_non_blocking(socket: RawSocket, non_blocking: bool) -> io::Result<()> {
    let stream = unsafe { TcpStream::from_raw_socket(socket) };
    let result = stream.set_nonblocking(non_blocking);
    mem::forget(stream);
    result
}

#[cfg(unix)]
fn connect_fd_timeout(fd: RawFd, sock_addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
    set_non_blocking(fd, true)?;

    let inet_addr = socket::InetAddr::from_std(sock_addr);
    let sock_addr = socket::SockAddr::Inet(inet_addr);
    match socket::connect(fd, &sock_addr) {
        Ok(_) => (),
        Err(err) => {
            match err.errno() {
                Errno::EALREADY |
                Errno::EINPROGRESS => (),
                errno => {
                    return Err(io::Error::from_raw_os_error(errno as i32));
                },
            }
        }
    }

    let mut fd_set = select::FdSet::new();
    let socket_fd = fd;
    fd_set.insert(socket_fd);
    let mut timeout_timeval = TimeVal::microseconds(timeout.as_secs() as i64 * 1000 * 1000);

    let select_res = select::select(
        socket_fd + 1,
        None,
        Some(&mut fd_set),
        None,
        Some(&mut timeout_timeval),
    )?;

    if select_res == -1 {
        return Err(io::Error::last_os_error());
    }

    if select_res != 1 {
        return Err(io::ErrorKind::TimedOut.into());
    }

    let socket_error_code = socket::getsockopt(
        socket_fd,
        socket::sockopt::SocketError,
    )?;

    if socket_error_code != 0 {
        return Err(io::Error::from_raw_os_error(socket_error_code));
    }

    set_non_blocking(fd, false)
}

#[cfg(target_os = "windows")]
fn connect_fd_timeout(socket: RawSocket,
                      sock_addr: &SocketAddr,
                      timeout: Duration) -> io::Result<()> {
    set_non_blocking(socket, true)?;
    let (name, name_len) = match *sock_addr {
        SocketAddr::V4(ref a) => {
            (a as *const _ as *const _, mem::size_of_val(a) as c_int)
        },
        SocketAddr::V6(ref a) => {
            (a as *const _ as *const _, mem::size_of_val(a) as c_int)
        }
    };
    let result = unsafe { connect(socket, name, name_len) };
    if result == SOCKET_ERROR {
        let err = io::Error::last_os_error();
        match err.raw_os_error().map(|x| x as u32) {
            Some(WSAEWOULDBLOCK) => {
                let mut write_fds = fd_set {
                    fd_count: 1,
                    fd_array: [0; FD_SETSIZE]
                };
                write_fds.fd_array[0] = socket;
                let mut err_fds = write_fds.clone();
                let timeout = timeval {
                    tv_sec: timeout.as_secs() as c_long,
                    tv_usec: 0,
                };

                let result = unsafe {
                    select(0, ptr::null_mut(), &mut write_fds, &mut err_fds, &timeout)
                };

                if result == 0 {
                    return Err(io::ErrorKind::TimedOut.into());
                } else if result == SOCKET_ERROR {
                    return Err(io::Error::last_os_error());
                } else {
                    let mut error = None;
                    for i in 0..(err_fds.fd_count as usize) {
                        if err_fds.fd_array[i] == socket {
                            error = Some(true);
                        }
                    }
                    for i in 0..(write_fds.fd_count as usize) {
                        if write_fds.fd_array[i] == socket {
                            error = Some(false);
                        }
                    }
                    match error {
                        Some(false) => (),
                        Some(true) => {
                            let mut opt_val = 0i32;
                            let mut opt_len = mem::size_of::<i32>() as c_int;
                            let result = unsafe {
                                getsockopt(socket,
                                           SOL_SOCKET,
                                           SO_ERROR,
                                           &mut opt_val as *mut _ as *mut _,
                                           &mut opt_len)
                            };
                            return Err(io::Error::from_raw_os_error(result));
                        },
                        None => unreachable!(),
                    }
                }
            },
            _ => return Err(err),
        }
    }
    set_non_blocking(socket, false)
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

// Finds the absolute path to the root of the repository.
fn find_git_repo_root() -> PathBuf {
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let mut path = Path::new(&manifest_dir);
    while !path.join(".git").exists() {
        path = path.parent().unwrap();
    }
    return path.to_owned();
}

// Opens a file, calls 'func' with its contents and writes the new content back.
fn inplace_modify_file<F: FnOnce(String) -> String>(path: &Path, func: F) {
    let mut contents = String::new();
    File::open(&path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();
    let new_contents = func(contents);
    File::create(&path)
        .unwrap()
        .write_all(new_contents.as_bytes())
        .unwrap();
}

fn wrap_in_module(contents: String, mod_name: &str) -> String {
    // TODO(sirver): Replicated from root crate. Pull out a build-proto crate?
    // Work around
    // https://github.com/stepancheg/rust-protobuf/issues/117
    // https://github.com/rust-lang/rust/issues/18810.
    // We open the file, add 'mod proto { }' around the contents and write it back. This allows us
    // to include! the file in lib.rs and have a proper proto module.
    format!("pub mod {} {{\n{}\n}}", mod_name, contents)
}

// This is a workaround for https://github.com/stepancheg/rust-protobuf/issues/331
fn replace_clippy(contents: String) -> String {
    contents.replace("#![allow(clippy)]", "#![allow(clippy::all)]")
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    println!("cargo:rerun-if-changed=point_viewer_grpc_proto_rust/src/proto.proto");

    let git_repo_root = find_git_repo_root();
    protoc_grpcio::compile_grpc_protos(
        &["point_viewer_grpc_proto_rust/src/proto.proto"],
        &[git_repo_root.clone()],
        &out_dir,
    )
    .expect("Failed to compile gRPC definitions!");

    inplace_modify_file(&Path::new(&out_dir).join("proto.rs"), |c| {
        // Work around https://github.com/stepancheg/rust-protobuf/issues/260. The protobuf plugin
        // apparently gets confused that there is point_viewer::octree::proto and
        // point_viewer_grpc::proto and believes the two proto namespaces are the same. We fully
        // qualify the paths to avoid this issue.
        let new_content = c.replace("super::proto", "::point_viewer::proto");
        wrap_in_module(replace_clippy(new_content), "proto")
    });
    inplace_modify_file(&Path::new(&out_dir).join("proto_grpc.rs"), |c| {
        wrap_in_module(replace_clippy(c), "proto_grpc")
    });
}
<commit_msg>x (#261)<commit_after>use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

// Finds the absolute path to the root of the repository.
fn find_git_repo_root() -> PathBuf {
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let mut path = Path::new(&manifest_dir);
    while !path.join(".git").exists() {
        path = path.parent().unwrap();
    }
    return path.to_owned();
}

// Opens a file, calls 'func' with its contents and writes the new content back.
fn inplace_modify_file<F: FnOnce(String) -> String>(path: &Path, func: F) {
    let mut contents = String::new();
    File::open(&path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();
    let new_contents = func(contents);
    File::create(&path)
        .unwrap()
        .write_all(new_contents.as_bytes())
        .unwrap();
}

fn wrap_in_module(contents: String, mod_name: &str) -> String {
    // TODO(sirver): Replicated from root crate. Pull out a build-proto crate?
    // Work around
    // https://github.com/stepancheg/rust-protobuf/issues/117
    // https://github.com/rust-lang/rust/issues/18810.
    // We open the file, add 'mod proto { }' around the contents and write it back. This allows us
    // to include! the file in lib.rs and have a proper proto module.
    format!("pub mod {} {{\n{}\n}}", mod_name, contents)
}

// This is a workaround for https://github.com/stepancheg/rust-protobuf/issues/331
fn replace_clippy(contents: String) -> String {
    contents.replace("#![allow(clippy)]", "#![allow(clippy::all)]")
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    println!("cargo:rerun-if-changed=src/proto.proto");

    let git_repo_root = find_git_repo_root();
    protoc_grpcio::compile_grpc_protos(
        &["point_viewer_grpc_proto_rust/src/proto.proto"],
        &[git_repo_root.clone()],
        &out_dir,
    )
    .expect("Failed to compile gRPC definitions!");

    inplace_modify_file(&Path::new(&out_dir).join("proto.rs"), |c| {
        // Work around https://github.com/stepancheg/rust-protobuf/issues/260. The protobuf plugin
        // apparently gets confused that there is point_viewer::octree::proto and
        // point_viewer_grpc::proto and believes the two proto namespaces are the same. We fully
        // qualify the paths to avoid this issue.
        let new_content = c.replace("super::proto", "::point_viewer::proto");
        wrap_in_module(replace_clippy(new_content), "proto")
    });
    inplace_modify_file(&Path::new(&out_dir).join("proto_grpc.rs"), |c| {
        wrap_in_module(replace_clippy(c), "proto_grpc")
    });
}
<|endoftext|>


<commit_before>use std::io::Result as IoResult;
use std::io::Write;
use nom::IError;

#[derive(Debug)]
enum Frequency {
    Optional,
    Repeated,
    Required,
}

#[derive(Debug)]
struct Field<'a> {
    name: &'a str,
    frequency: Frequency,
    typ: &'a str,
    number: i32,
    default: Option<&'a str>,
}

impl<'a> Field<'a> {

    fn rust_type(&self) -> &str {
        match self.typ {
            "int32" | "sint32" | "sfixed32" => "i32",
            "int64" | "sint64" | "sfixed64" => "i64",
            "uint32" | "fixed32" => "u32",
            "uint64" | "fixed64" => "u64",
            "float" => "f32",
            "double" => "f64",
            "string" => "String",
            "bytes" => "Vec<u8>",
            t => t,
        }
    }

    fn wire_type(&self, enums: &[&str]) -> &str {
        match self.typ {
            "int32" | "sint32" | "int64" | "sint64" |
                "uint32" | "uint64" | "bool" | "enum" => "WireType::Varint",
            "fixed64" | "sfixed64" | "double" => "WireType::Fixed64",
            "fixed32" | "sfixed32" | "float" => "WireType::Fixed32",
            t if enums.contains(&t) => "WireType::Varint",
            _ => "WireType::LengthDelimited",
        }
    }

    fn read_fn(&self, enums: &[&str]) -> &str {
        match self.typ {
            "int32" | "sint32" | "int64" | "sint64" |
                "uint32" | "uint64" | "bool" | "fixed64" |
                "sfixed64" | "double" | "fixed32" | "sfixed32" |
                "float" | "string" | "bytes" => self.typ,
            t if enums.contains(&t) => "enum",
            _ => "message",
        }
    }

    fn write_definition<W: Write>(&self, w: &mut W) -> IoResult<()> {
        match self.frequency {
            Frequency::Optional => writeln!(w, "    pub {}: Option<{}>,", self.name, self.rust_type()),
            Frequency::Repeated => writeln!(w, "    pub {}: Vec<{}>,", self.name, self.rust_type()),
            Frequency::Required => writeln!(w, "    pub {}: {},", self.name, self.rust_type()),
        }
    }

    fn write_match_tag<W: Write>(&self, w: &mut W, enums: &[&str]) -> IoResult<()> {
        match self.frequency {
            Frequency::Optional => {
                writeln!(w, "({}, {}) => msg.{} = Some(r.read_{}()?),",
                    self.number, self.wire_type(enums), self.name, self.read_fn(enums))
            }
            Frequency::Repeated => {
                writeln!(w, "({}, {}) => msg.{}.push(r.read_{}()?),",
                    self.number, self.wire_type(enums), self.name, self.read_fn(enums))
            }
            Frequency::Required => {
                writeln!(w, "({}, {}) => msg.{} = r.read_{}()?,",
                    self.number, self.wire_type(enums), self.name, self.read_fn(enums))
            }
        }
    }

    fn write_match_not_tag<W: Write>(&self, w: &mut W, name: &str) -> IoResult<()> {
        writeln!(w, "({}, _) => return Err(ErrorKind::InvalidMessage(tag, \"{} {}\").into()),",
            self.number, name, self.typ)
    }
}

#[derive(Debug)]
pub struct Message<'a> {
    name: &'a str,
    fields: Vec<Field<'a>>,
}

impl<'a> Message<'a> {
    fn write_definition<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "#[derive(Debug, Default, PartialEq, Clone)]")?;
        writeln!(w, "pub struct {} {{", self.name)?;
        for f in &self.fields {
            f.write_definition(w)?;
        }
        writeln!(w, "}}")
    }

    fn write_impl_message<W: Write>(&self, w: &mut W, enums: &[&str]) -> IoResult<()> {
        writeln!(w, "impl Message for {} {{", self.name)?;
        writeln!(w, "    fn from_reader<R: BufRead>(mut r: &mut Reader<R>) -> Result<Self> {{")?;
        writeln!(w, "        let mut msg = Self::default();")?;
        writeln!(w, "        loop {{")?;
        writeln!(w, "            let tag = match r.next_tag() {{")?;
        writeln!(w, "                None => break,")?;
        writeln!(w, "                Some(Err(e)) => return Err(e),")?;
        writeln!(w, "                Some(Ok(tag)) => tag,")?;
        writeln!(w, "            }};")?;
        writeln!(w, "            match tag.unpack() {{")?;
        for f in &self.fields {
            write!(w, "                 ")?;
            f.write_match_tag(w, enums)?;
        }
        for f in &self.fields {
            write!(w, "                 ")?;
            f.write_match_not_tag(w, self.name)?;
        }
        writeln!(w, "                (_, wire_type) => r.read_unknown(wire_type)?,")?;
        writeln!(w, "            }}")?;
        writeln!(w, "        }}")?;
        writeln!(w, "        Ok(msg)")?;
        writeln!(w, "    }}")?;
        writeln!(w, "}}")
    }
}

#[derive(Debug)]
pub struct Enumerator<'a> {
    name: &'a str,
    fields: Vec<(&'a str, i32)>,
}

impl<'a> Enumerator<'a> {
    fn write_definition<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "#[derive(Debug, PartialEq, Eq, Clone)]")?;
        writeln!(w, "pub enum {} {{", self.name)?;
        for &(f, _) in &self.fields {
            writeln!(w, "    {},", f)?;
        }
        writeln!(w, "}}")
    }

    fn write_impl_default<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "impl Default for {} {{", self.name)?;
        writeln!(w, "    fn default() -> Self {{")?;
        // TODO: check with default field and return error if there is no field
        writeln!(w, "        {}::{}", self.name, self.fields[0].0)?;
        writeln!(w, "    }}")?;
        writeln!(w, "}}")
    }

    fn write_from_u64<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "impl From<u64> for {} {{", self.name)?;
        writeln!(w, "    fn from(i: u64) -> Self {{")?;
        writeln!(w, "        match i {{")?;
        for &(f, number) in &self.fields {
            writeln!(w, "            {} => {}::{},", number, self.name, f)?;
        }
        writeln!(w, "            _ => Self::default(),")?;
        writeln!(w, "        }}")?;
        writeln!(w, "    }}")?;
        writeln!(w, "}}")
    }
}

#[derive(Debug)]
pub enum MessageOrEnum<'a> {
    Msg(Message<'a>),
    Enum(Enumerator<'a>),
    Ignore,
}

#[derive(Debug)]
pub struct FileDescriptor<'a> {
    message_and_enums: Vec<MessageOrEnum<'a>>,
}

impl<'a> FileDescriptor<'a> {
    pub fn from_str(f: &'a str) -> Result<FileDescriptor<'a>, IError<u32>> {
        FileDescriptor::from_bytes(f.as_bytes())

    }
    pub fn from_bytes(b: &'a [u8]) -> Result<FileDescriptor<'a>, IError<u32>> {
        self::parser::file_descriptor(b).to_full_result()
    }

    pub fn write<W: Write>(&self, w: &mut W, filename: &str) -> IoResult<()> {

        writeln!(w, "//! Automatically generated rust module for '{}' file", filename)?;
        writeln!(w, "")?;
        writeln!(w, "#![allow(non_snake_case)]")?;
        writeln!(w, "#![allow(non_upper_case_globals)]")?;
        writeln!(w, "")?;
        writeln!(w, "use std::io::BufRead;")?;
        writeln!(w, "use quick_protobuf::errors::{{Result, ErrorKind}};")?;
        writeln!(w, "use quick_protobuf::message::Message;")?;
        writeln!(w, "use quick_protobuf::reader::Reader;")?;
        writeln!(w, "use quick_protobuf::types::WireType;")?;

        let enums = self.message_and_enums.iter().filter_map(|m| {
            if let &MessageOrEnum::Enum(ref e) = m {
                Some(e.name)
            } else {
                None
            }
        }).collect::<Vec<_>>();
        for m in &self.message_and_enums {
            match m {
                &MessageOrEnum::Msg(ref m) => {
                    writeln!(w, "")?;
                    m.write_definition(w)?;
                    writeln!(w, "")?;
                    m.write_impl_message(w, &enums)?;
                },
                &MessageOrEnum::Enum(ref m) => {
                    writeln!(w, "")?;
                    m.write_definition(w)?;
                    writeln!(w, "")?;
                    m.write_impl_default(w)?;
                    writeln!(w, "")?;
                    m.write_from_u64(w)?;
                },
                &MessageOrEnum::Ignore => continue,
            }
        }
        Ok(())
    }
}

mod parser {

    use super::*;
    use std::str;
    use nom::{alphanumeric, multispace, digit};

    named!(comment<()>, do_parse!(tag!("//") >> take_until_and_consume!("\n") >> ()));

    /// word break: multispace or comment
    named!(br<()>, alt!(map!(multispace, |_| ()) | comment));

    named!(default_value<&str>, do_parse!(
        tag!("[") >> many0!(br) >> tag!("default") >> many0!(br) >> tag!("=") >> many0!(br) >>
        default: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >> tag!("]") >>
        (default)));

    named!(message_field<Field>, do_parse!(
        frequency: alt!(map!(tag!("optional"), |_| Frequency::Optional) |
                        map!(tag!("repeated"), |_| Frequency::Repeated) |
                        map!(tag!("required"), |_| Frequency::Required)) >> many1!(br) >>
        typ: map_res!(alphanumeric, str::from_utf8) >> many1!(br) >>
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("=") >> many0!(br) >>
        number: map_res!(map_res!(digit, str::from_utf8), str::FromStr::from_str) >> many0!(br) >>
        default: opt!(default_value) >> many0!(br) >> tag!(";") >> many0!(br) >>
        (Field {
           name: name,
           frequency: frequency,
           typ: typ,
           number: number,
           default: default,
        })));

    named!(message<Message>, do_parse!(
        tag!("message") >> many0!(br) >>
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("{") >> many0!(br) >>
        fields: many0!(message_field) >>
        tag!("}") >> many0!(br) >>
        (Message { name: name, fields: fields })));

    named!(enum_field<(&str, i32)>, do_parse!(
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("=") >> many0!(br) >>
        number: map_res!(map_res!(digit, str::from_utf8), str::FromStr::from_str) >> many0!(br) >>
        tag!(";") >> many0!(br) >>
        ((name, number))));

    named!(enumerator<Enumerator>, do_parse!(
        tag!("enum") >> many1!(br) >>
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("{") >> many0!(br) >>
        fields: many0!(enum_field) >>
        tag!("}") >> many0!(br) >>
        (Enumerator { name: name, fields: fields })));

    named!(ignore<()>, do_parse!(
        alt!(tag!("package") | tag!("option")) >> many1!(br) >>
        take_until_and_consume!(";") >> many0!(br) >> ()));

    named!(message_or_enum<MessageOrEnum>, alt!(
             message => { |m| MessageOrEnum::Msg(m) } |
             enumerator => { |e| MessageOrEnum::Enum(e) } |
             ignore => { |_| MessageOrEnum::Ignore } ));

    named!(pub file_descriptor<FileDescriptor>, do_parse!(
        many0!(br) >>
        message_and_enums: many0!(message_or_enum) >>
        (FileDescriptor {
            message_and_enums: message_and_enums
        })));

    #[test]
    fn test_message() {
        let msg = r#"message ReferenceData
    {
        repeated ScenarioInfo  scenarioSet = 1;
        repeated CalculatedObjectInfo calculatedObjectSet = 2;
        repeated RiskFactorList riskFactorListSet = 3;
        repeated RiskMaturityInfo riskMaturitySet = 4;
        repeated IndicatorInfo indicatorSet = 5;
        repeated RiskStrikeInfo riskStrikeSet = 6;
        repeated FreeProjectionList freeProjectionListSet = 7;
        repeated ValidationProperty ValidationSet = 8;
        repeated CalcProperties calcPropertiesSet = 9;
        repeated MaturityInfo maturitySet = 10;
    }"#;

        let mess = message(msg.as_bytes());
        if let ::nom::IResult::Done(_, mess) = mess {
            assert_eq!(10, mess.fields.len());
        }
    }

    #[test]
    fn test_enum() {
        let msg = r#"enum PairingStatus {
                DEALPAIRED        = 0;
                INVENTORYORPHAN   = 1;
                CALCULATEDORPHAN  = 2;
                CANCELED          = 3;
    }"#;

        let mess = enumerator(msg.as_bytes());
        if let ::nom::IResult::Done(_, mess) = mess {
            assert_eq!(4, mess.fields.len());
        }
    }

    #[test]
    fn test_ignore() {
        let msg = r#"package com.test.v0;

    option optimize_for = SPEED;
    "#;

        match ignore(msg.as_bytes()) {
            ::nom::IResult::Done(_, _) => (),
            e => panic!("Expecting done {:?}", e),
        }
    }
}
<commit_msg>match on coded tag instead of (value, wiretype)<commit_after>use std::io::Result as IoResult;
use std::io::Write;
use nom::IError;

#[derive(Debug)]
enum Frequency {
    Optional,
    Repeated,
    Required,
}

#[derive(Debug)]
struct Field<'a> {
    name: &'a str,
    frequency: Frequency,
    typ: &'a str,
    number: i32,
    default: Option<&'a str>,
}

impl<'a> Field<'a> {

    fn rust_type(&self) -> &str {
        match self.typ {
            "int32" | "sint32" | "sfixed32" => "i32",
            "int64" | "sint64" | "sfixed64" => "i64",
            "uint32" | "fixed32" => "u32",
            "uint64" | "fixed64" => "u64",
            "float" => "f32",
            "double" => "f64",
            "string" => "String",
            "bytes" => "Vec<u8>",
            t => t,
        }
    }

    fn wire_type_num(&self, enums: &[&str]) -> u32 {
        match self.typ {
            "int32" | "sint32" | "int64" | "sint64" |
                "uint32" | "uint64" | "bool" | "enum" => 0,
            "fixed64" | "sfixed64" | "double" => 1,
            "fixed32" | "sfixed32" | "float" => 5,
            t if enums.contains(&t) => 0,
            _ => 2,
        }
    }

    fn read_fn(&self, enums: &[&str]) -> &str {
        match self.typ {
            "int32" | "sint32" | "int64" | "sint64" |
                "uint32" | "uint64" | "bool" | "fixed64" |
                "sfixed64" | "double" | "fixed32" | "sfixed32" |
                "float" | "string" | "bytes" => self.typ,
            t if enums.contains(&t) => "enum",
            _ => "message",
        }
    }

    fn tag(&self, enums: &[&str]) -> u32 {
        (self.number as u32) << 3 | self.wire_type_num(enums)
    }

    fn write_definition<W: Write>(&self, w: &mut W) -> IoResult<()> {
        match self.frequency {
            Frequency::Optional => writeln!(w, "    pub {}: Option<{}>,", self.name, self.rust_type()),
            Frequency::Repeated => writeln!(w, "    pub {}: Vec<{}>,", self.name, self.rust_type()),
            Frequency::Required => writeln!(w, "    pub {}: {},", self.name, self.rust_type()),
        }
    }

    fn write_match_tag<W: Write>(&self, w: &mut W, enums: &[&str]) -> IoResult<()> {
        match self.frequency {
            Frequency::Optional => writeln!(w, "{} => msg.{} = Some(r.read_{}()?),",
                                            self.tag(enums), self.name, self.read_fn(enums)),
            Frequency::Repeated => writeln!(w, "{} => msg.{}.push(r.read_{}()?),",
                                            self.tag(enums), self.name, self.read_fn(enums)),
            Frequency::Required => writeln!(w, "{} => msg.{} = r.read_{}()?,",
                                            self.tag(enums), self.name, self.read_fn(enums)),
        }
    }

//     fn write_match_not_tag<W: Write>(&self, w: &mut W, name: &str) -> IoResult<()> {
//         writeln!(w, "({}, _) => return Err(ErrorKind::InvalidMessage(tag, \"{} {}\").into()),",
//             self.number, name, self.typ)
//     }
}

#[derive(Debug)]
pub struct Message<'a> {
    name: &'a str,
    fields: Vec<Field<'a>>,
}

impl<'a> Message<'a> {
    fn write_definition<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "#[derive(Debug, Default, PartialEq, Clone)]")?;
        writeln!(w, "pub struct {} {{", self.name)?;
        for f in &self.fields {
            f.write_definition(w)?;
        }
        writeln!(w, "}}")
    }

    fn write_impl_message<W: Write>(&self, w: &mut W, enums: &[&str]) -> IoResult<()> {
        writeln!(w, "impl Message for {} {{", self.name)?;
        writeln!(w, "    fn from_reader<R: Read>(mut r: &mut Reader<R>) -> Result<Self> {{")?;
        writeln!(w, "        let mut msg = Self::default();")?;
        writeln!(w, "        loop {{")?;
        writeln!(w, "            let tag = match r.next_tag_value() {{")?;
        writeln!(w, "                None => break,")?;
        writeln!(w, "                Some(Err(e)) => return Err(e),")?;
        writeln!(w, "                Some(Ok(tag)) => tag,")?;
        writeln!(w, "            }};")?;
        writeln!(w, "            match tag {{")?;
        for f in &self.fields {
            write!(w, "                ")?;
            f.write_match_tag(w, enums)?;
        }
        writeln!(w, "                t => {{")?;
        writeln!(w, "                    let t: Tag = t.into();")?;
        writeln!(w, "                    r.read_unknown(t.wire_type())?;")?;
        writeln!(w, "                }},")?;
        writeln!(w, "            }}")?;
        writeln!(w, "        }}")?;
        writeln!(w, "        Ok(msg)")?;
        writeln!(w, "    }}")?;
        writeln!(w, "}}")
    }
}

#[derive(Debug)]
pub struct Enumerator<'a> {
    name: &'a str,
    fields: Vec<(&'a str, i32)>,
}

impl<'a> Enumerator<'a> {
    fn write_definition<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "#[derive(Debug, PartialEq, Eq, Clone)]")?;
        writeln!(w, "pub enum {} {{", self.name)?;
        for &(f, _) in &self.fields {
            writeln!(w, "    {},", f)?;
        }
        writeln!(w, "}}")
    }

    fn write_impl_default<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "impl Default for {} {{", self.name)?;
        writeln!(w, "    fn default() -> Self {{")?;
        // TODO: check with default field and return error if there is no field
        writeln!(w, "        {}::{}", self.name, self.fields[0].0)?;
        writeln!(w, "    }}")?;
        writeln!(w, "}}")
    }

    fn write_from_u64<W: Write>(&self, w: &mut W) -> IoResult<()> {
        writeln!(w, "impl From<u64> for {} {{", self.name)?;
        writeln!(w, "    fn from(i: u64) -> Self {{")?;
        writeln!(w, "        match i {{")?;
        for &(f, number) in &self.fields {
            writeln!(w, "            {} => {}::{},", number, self.name, f)?;
        }
        writeln!(w, "            _ => Self::default(),")?;
        writeln!(w, "        }}")?;
        writeln!(w, "    }}")?;
        writeln!(w, "}}")
    }
}

#[derive(Debug)]
pub enum MessageOrEnum<'a> {
    Msg(Message<'a>),
    Enum(Enumerator<'a>),
    Ignore,
}

#[derive(Debug)]
pub struct FileDescriptor<'a> {
    message_and_enums: Vec<MessageOrEnum<'a>>,
}

impl<'a> FileDescriptor<'a> {
    pub fn from_str(f: &'a str) -> Result<FileDescriptor<'a>, IError<u32>> {
        FileDescriptor::from_bytes(f.as_bytes())

    }
    pub fn from_bytes(b: &'a [u8]) -> Result<FileDescriptor<'a>, IError<u32>> {
        self::parser::file_descriptor(b).to_full_result()
    }

    pub fn write<W: Write>(&self, w: &mut W, filename: &str) -> IoResult<()> {

        writeln!(w, "//! Automatically generated rust module for '{}' file", filename)?;
        writeln!(w, "")?;
        writeln!(w, "#![allow(non_snake_case)]")?;
        writeln!(w, "#![allow(non_upper_case_globals)]")?;
        writeln!(w, "")?;
        writeln!(w, "use std::io::Read;")?;
        writeln!(w, "use quick_protobuf::errors::Result;")?;
        writeln!(w, "use quick_protobuf::message::Message;")?;
        writeln!(w, "use quick_protobuf::reader::Reader;")?;
        writeln!(w, "use quick_protobuf::types::Tag;")?;

        let enums = self.message_and_enums.iter().filter_map(|m| {
            if let &MessageOrEnum::Enum(ref e) = m {
                Some(e.name)
            } else {
                None
            }
        }).collect::<Vec<_>>();
        for m in &self.message_and_enums {
            match m {
                &MessageOrEnum::Msg(ref m) => {
                    writeln!(w, "")?;
                    m.write_definition(w)?;
                    writeln!(w, "")?;
                    m.write_impl_message(w, &enums)?;
                },
                &MessageOrEnum::Enum(ref m) => {
                    writeln!(w, "")?;
                    m.write_definition(w)?;
                    writeln!(w, "")?;
                    m.write_impl_default(w)?;
                    writeln!(w, "")?;
                    m.write_from_u64(w)?;
                },
                &MessageOrEnum::Ignore => continue,
            }
        }
        Ok(())
    }
}

mod parser {

    use std::str;
    use parser::{Frequency, Field, Message, Enumerator, MessageOrEnum, FileDescriptor};
    use nom::{alphanumeric, multispace, digit};

    named!(comment<()>, do_parse!(tag!("//") >> take_until_and_consume!("\n") >> ()));

    /// word break: multispace or comment
    named!(br<()>, alt!(map!(multispace, |_| ()) | comment));

    named!(default_value<&str>, do_parse!(
        tag!("[") >> many0!(br) >> tag!("default") >> many0!(br) >> tag!("=") >> many0!(br) >>
        default: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >> tag!("]") >>
        (default)));

    named!(frequency<Frequency>,
           alt!(tag!("optional") => { |_| Frequency::Optional } |
                tag!("repeated") => { |_| Frequency::Repeated } |
                tag!("required") => { |_| Frequency::Required } ));

    named!(message_field<Field>, do_parse!(
        frequency: frequency >> many1!(br) >>
        typ: map_res!(alphanumeric, str::from_utf8) >> many1!(br) >>
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("=") >> many0!(br) >>
        number: map_res!(map_res!(digit, str::from_utf8), str::FromStr::from_str) >> many0!(br) >>
        default: opt!(default_value) >> many0!(br) >> tag!(";") >> many0!(br) >>
        (Field {
           name: name,
           frequency: frequency,
           typ: typ,
           number: number,
           default: default,
        })));

    named!(message<Message>, do_parse!(
        tag!("message") >> many0!(br) >>
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("{") >> many0!(br) >>
        fields: many0!(message_field) >>
        tag!("}") >> many0!(br) >>
        (Message { name: name, fields: fields })));

    named!(enum_field<(&str, i32)>, do_parse!(
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("=") >> many0!(br) >>
        number: map_res!(map_res!(digit, str::from_utf8), str::FromStr::from_str) >> many0!(br) >>
        tag!(";") >> many0!(br) >>
        ((name, number))));

    named!(enumerator<Enumerator>, do_parse!(
        tag!("enum") >> many1!(br) >>
        name: map_res!(alphanumeric, str::from_utf8) >> many0!(br) >>
        tag!("{") >> many0!(br) >>
        fields: many0!(enum_field) >>
        tag!("}") >> many0!(br) >>
        (Enumerator { name: name, fields: fields })));

    named!(ignore<()>, do_parse!(
        alt!(tag!("package") | tag!("option")) >> many1!(br) >>
        take_until_and_consume!(";") >> many0!(br) >> ()));

    named!(message_or_enum<MessageOrEnum>, alt!(
             message => { |m| MessageOrEnum::Msg(m) } |
             enumerator => { |e| MessageOrEnum::Enum(e) } |
             ignore => { |_| MessageOrEnum::Ignore } ));

    named!(pub file_descriptor<FileDescriptor>, do_parse!(
        many0!(br) >>
        message_and_enums: many0!(message_or_enum) >>
        (FileDescriptor {
            message_and_enums: message_and_enums
        })));

    #[test]
    fn test_message() {
        let msg = r#"message ReferenceData
    {
        repeated ScenarioInfo  scenarioSet = 1;
        repeated CalculatedObjectInfo calculatedObjectSet = 2;
        repeated RiskFactorList riskFactorListSet = 3;
        repeated RiskMaturityInfo riskMaturitySet = 4;
        repeated IndicatorInfo indicatorSet = 5;
        repeated RiskStrikeInfo riskStrikeSet = 6;
        repeated FreeProjectionList freeProjectionListSet = 7;
        repeated ValidationProperty ValidationSet = 8;
        repeated CalcProperties calcPropertiesSet = 9;
        repeated MaturityInfo maturitySet = 10;
    }"#;

        let mess = message(msg.as_bytes());
        if let ::nom::IResult::Done(_, mess) = mess {
            assert_eq!(10, mess.fields.len());
        }
    }

    #[test]
    fn test_enum() {
        let msg = r#"enum PairingStatus {
                DEALPAIRED        = 0;
                INVENTORYORPHAN   = 1;
                CALCULATEDORPHAN  = 2;
                CANCELED          = 3;
    }"#;

        let mess = enumerator(msg.as_bytes());
        if let ::nom::IResult::Done(_, mess) = mess {
            assert_eq!(4, mess.fields.len());
        }
    }

    #[test]
    fn test_ignore() {
        let msg = r#"package com.test.v0;

    option optimize_for = SPEED;
    "#;

        match ignore(msg.as_bytes()) {
            ::nom::IResult::Done(_, _) => (),
            e => panic!("Expecting done {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>use super::{publish_response, ActionServerOnRequest, ServerGoalHandle, StatusList, StatusTracker};
use crate::static_messages::MUTEX_LOCK_FAIL;
use crate::{Action, GoalBody, GoalID, GoalState, GoalType};
use rosrust::error::Result;
use std::sync::{Arc, Mutex};

pub struct GoalCoordinator<T: Action> {
    last_cancel_ns: Arc<Mutex<i64>>,
    result_pub: rosrust::Publisher<T::Result>,
    feedback_pub: rosrust::Publisher<T::Feedback>,
    status_list: Arc<Mutex<StatusList<T>>>,
    on_goal: ActionServerOnRequest<T>,
    on_cancel: ActionServerOnRequest<T>,
}

impl<T: Action> GoalCoordinator<T> {
    pub fn new(
        result_pub: rosrust::Publisher<T::Result>,
        feedback_pub: rosrust::Publisher<T::Feedback>,
        on_goal: ActionServerOnRequest<T>,
        on_cancel: ActionServerOnRequest<T>,
        status_list: Arc<Mutex<StatusList<T>>>,
    ) -> Self {
        Self {
            last_cancel_ns: Arc::new(Mutex::new(0)),
            result_pub,
            feedback_pub,
            status_list,
            on_goal,
            on_cancel,
        }
    }

    pub fn handle_on_goal(&self, goal: GoalType<T>) -> Result<()> {
        rosrust::ros_debug!("The action server has received a new goal request");

        let goal_id = goal.id.id.clone();

        if let Some(tracker) = self
            .status_list
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .get(&goal_id)
        {
            let mut tracker = tracker.lock().expect(MUTEX_LOCK_FAIL);

            rosrust::ros_debug!(
                "Goal {} was already in the status list with status {:?}",
                goal.id.id,
                tracker.state()
            );

            tracker.mark_for_destruction(false);

            if tracker.state() == GoalState::Recalling {
                tracker.set_state(GoalState::Recalled);
                let status = tracker.to_status();

                publish_response(&self.result_pub, status, Default::default())?;
            }

            return Ok(());
        }

        let tracker = StatusTracker::new_goal(goal);
        let goal_timestamp = tracker.goal_id().stamp.nanos();

        let key = tracker.goal_id().id.clone();
        // This is guaranteed to return Some because it's not a cancelation status tracker
        let goal = tracker.goal().unwrap();
        let tracker = Arc::new(Mutex::new(tracker));
        self.add_status_tracker(key, Arc::clone(&tracker));

        let goal_handle = ServerGoalHandle::new(
            self.result_pub.clone(),
            self.feedback_pub.clone(),
            goal,
            self.status_list.clone(),
            tracker,
        )?;

        if goal_timestamp != 0
            && goal_timestamp <= *self.last_cancel_ns.lock().expect(MUTEX_LOCK_FAIL)
        {
            goal_handle
                .response()
                .text("This goal handle was canceled by the action server because its timestamp is before the timestamp of the last cancel request")
                .send_canceled();
            return Ok(());
        };

        (*self.on_goal)(goal_handle)
    }

    pub fn handle_on_cancel(&self, goal_id: GoalID) -> Result<()> {
        rosrust::ros_debug!("The action server has received a new cancel request");

        let filter_id = &goal_id.id;
        let filter_stamp = goal_id.stamp.nanos();

        let cancel_everything = filter_id == "" && filter_stamp == 0;

        let mut goal_id_found = false;

        for tracker in self.status_list.lock().expect(MUTEX_LOCK_FAIL).values() {
            let tracker_ref = Arc::clone(&tracker);
            let mut tracker = tracker.lock().expect(MUTEX_LOCK_FAIL);
            let cancel_this = filter_id == &tracker.goal_id().id;
            let cancel_before_stamp =
                filter_stamp != 0 && tracker.goal_id().stamp.nanos() <= filter_stamp;
            if !cancel_everything && !cancel_this && !cancel_before_stamp {
                continue;
            }
            goal_id_found = goal_id_found || filter_id == &tracker.goal_id().id;
            tracker.mark_for_destruction(false);
            let goal = tracker.goal();
            drop(tracker);

            if let Some(goal) = goal {
                let goal_handle = ServerGoalHandle::new(
                    self.result_pub.clone(),
                    self.feedback_pub.clone(),
                    goal,
                    self.status_list.clone(),
                    tracker_ref,
                )?;

                if goal_handle.set_cancel_requested() {
                    (*self.on_cancel)(goal_handle)?;
                }
            }
        }

        if filter_id != "" && !goal_id_found {
            let tracker = StatusTracker::new_cancelation(goal_id, GoalState::Recalling);
            let key = tracker.goal_id().id.clone();
            self.add_status_tracker(key, Arc::new(Mutex::new(tracker)));
        }

        let mut last_cancel_ns = self.last_cancel_ns.lock().expect(MUTEX_LOCK_FAIL);
        if filter_stamp > *last_cancel_ns {
            *last_cancel_ns = filter_stamp;
        }
        Ok(())
    }

    fn add_status_tracker(&self, key: String, tracker: Arc<Mutex<StatusTracker<GoalBody<T>>>>) {
        self.status_list
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .insert(key, tracker);
    }
}
<commit_msg>Remove potential deadlock in goal coordinator<commit_after>use super::{publish_response, ActionServerOnRequest, ServerGoalHandle, StatusList, StatusTracker};
use crate::static_messages::MUTEX_LOCK_FAIL;
use crate::{Action, GoalBody, GoalID, GoalState, GoalType};
use rosrust::error::Result;
use std::sync::{Arc, Mutex};

pub struct GoalCoordinator<T: Action> {
    last_cancel_ns: Arc<Mutex<i64>>,
    result_pub: rosrust::Publisher<T::Result>,
    feedback_pub: rosrust::Publisher<T::Feedback>,
    status_list: Arc<Mutex<StatusList<T>>>,
    on_goal: ActionServerOnRequest<T>,
    on_cancel: ActionServerOnRequest<T>,
}

impl<T: Action> GoalCoordinator<T> {
    pub fn new(
        result_pub: rosrust::Publisher<T::Result>,
        feedback_pub: rosrust::Publisher<T::Feedback>,
        on_goal: ActionServerOnRequest<T>,
        on_cancel: ActionServerOnRequest<T>,
        status_list: Arc<Mutex<StatusList<T>>>,
    ) -> Self {
        Self {
            last_cancel_ns: Arc::new(Mutex::new(0)),
            result_pub,
            feedback_pub,
            status_list,
            on_goal,
            on_cancel,
        }
    }

    pub fn handle_on_goal(&self, goal: GoalType<T>) -> Result<()> {
        rosrust::ros_debug!("The action server has received a new goal request");

        let goal_id = goal.id.id.clone();

        if let Some(tracker) = self
            .status_list
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .get(&goal_id)
        {
            let mut tracker = tracker.lock().expect(MUTEX_LOCK_FAIL);

            rosrust::ros_debug!(
                "Goal {} was already in the status list with status {:?}",
                goal.id.id,
                tracker.state()
            );

            tracker.mark_for_destruction(false);

            if tracker.state() == GoalState::Recalling {
                tracker.set_state(GoalState::Recalled);
                let status = tracker.to_status();

                publish_response(&self.result_pub, status, Default::default())?;
            }

            return Ok(());
        }

        let tracker = StatusTracker::new_goal(goal);
        let goal_timestamp = tracker.goal_id().stamp.nanos();

        let key = tracker.goal_id().id.clone();
        // This is guaranteed to return Some because it's not a cancelation status tracker
        let goal = tracker.goal().unwrap();
        let tracker = Arc::new(Mutex::new(tracker));
        self.add_status_tracker(key, Arc::clone(&tracker));

        let goal_handle = ServerGoalHandle::new(
            self.result_pub.clone(),
            self.feedback_pub.clone(),
            goal,
            self.status_list.clone(),
            tracker,
        )?;

        if goal_timestamp != 0
            && goal_timestamp <= *self.last_cancel_ns.lock().expect(MUTEX_LOCK_FAIL)
        {
            goal_handle
                .response()
                .text("This goal handle was canceled by the action server because its timestamp is before the timestamp of the last cancel request")
                .send_canceled();
            return Ok(());
        };

        (*self.on_goal)(goal_handle)
    }

    pub fn handle_on_cancel(&self, goal_id: GoalID) -> Result<()> {
        rosrust::ros_debug!("The action server has received a new cancel request");

        let goal_filter: GoalFilter = goal_id.clone().into();

        let cancel_everything = goal_filter.matches_everything();

        let mut goal_id_found = goal_filter.id().is_none();

        let canceled_trackers: Vec<Arc<_>> = {
            let status_list = self.status_list.lock().expect(MUTEX_LOCK_FAIL);
            status_list
                .values()
                .filter(|tracker| {
                    if cancel_everything {
                        return true;
                    }

                    let tracker = tracker.lock().expect(MUTEX_LOCK_FAIL);
                    goal_filter.matches(&tracker.goal_id())
                })
                .cloned()
                .collect::<Vec<_>>()
        };

        for tracker_ref in canceled_trackers {
            let mut tracker = tracker_ref.lock().expect(MUTEX_LOCK_FAIL);
            if goal_filter.matches_id(&tracker.goal_id().id) {
                goal_id_found = true;
            }
            tracker.mark_for_destruction(false);
            let goal = tracker.goal();
            drop(tracker);

            if let Some(goal) = goal {
                let goal_handle = ServerGoalHandle::new(
                    self.result_pub.clone(),
                    self.feedback_pub.clone(),
                    goal,
                    self.status_list.clone(),
                    tracker_ref,
                )?;

                if goal_handle.set_cancel_requested() {
                    (*self.on_cancel)(goal_handle)?;
                }
            }
        }

        if !goal_id_found {
            let tracker = StatusTracker::new_cancelation(goal_id, GoalState::Recalling);
            let key = tracker.goal_id().id.clone();
            self.add_status_tracker(key, Arc::new(Mutex::new(tracker)));
        }

        if let Some(ref stamp) = goal_filter.stamp() {
            let mut last_cancel_ns = self.last_cancel_ns.lock().expect(MUTEX_LOCK_FAIL);
            if *stamp > *last_cancel_ns {
                *last_cancel_ns = *stamp;
            }
        }

        Ok(())
    }

    fn add_status_tracker(&self, key: String, tracker: Arc<Mutex<StatusTracker<GoalBody<T>>>>) {
        self.status_list
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .insert(key, tracker);
    }
}

struct GoalFilter {
    id: Option<String>,
    stamp_nanos: Option<i64>,
}

impl From<GoalID> for GoalFilter {
    fn from(goal_id: GoalID) -> Self {
        let id = if goal_id.id == "" {
            None
        } else {
            Some(goal_id.id)
        };
        let nanos = goal_id.stamp.nanos();
        let stamp_nanos = if nanos == 0 { None } else { Some(nanos) };
        Self { id, stamp_nanos }
    }
}

impl GoalFilter {
    fn matches_everything(&self) -> bool {
        self.id.is_none() && self.stamp_nanos.is_none()
    }

    fn matches(&self, goal_id: &GoalID) -> bool {
        self.matches_id(&goal_id.id) || self.matches_stamp(&goal_id.stamp)
    }

    fn matches_id(&self, other_id: &str) -> bool {
        self.id.as_ref().map(|id| id == other_id).unwrap_or(false)
    }

    fn id(&self) -> &Option<String> {
        &self.id
    }

    fn matches_stamp(&self, other_stamp: &rosrust::Time) -> bool {
        self.stamp_nanos
            .map(|stamp| other_stamp.nanos() <= stamp)
            .unwrap_or(false)
    }

    fn stamp(&self) -> &Option<i64> {
        &self.stamp_nanos
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use syntax::visit::FnKind;

use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_external_macro};

/// **What it does:** This lint checks for return statements at the end of a block.
///
/// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty.
///
/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed.
///
/// **Example:** `fn foo(x: usize) { return x; }`
declare_lint! {
    pub NEEDLESS_RETURN, Warn,
    "using a return statement like `return expr;` where an expression would suffice"
}

/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned.
///
/// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty.
///
/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed.
///
/// **Example:** `{ let x = ..; x }`
declare_lint! {
    pub LET_AND_RETURN, Warn,
    "creating a let-binding and then immediately returning it like `let x = expr; x` at \
     the end of a block"
}

#[derive(Copy, Clone)]
pub struct ReturnPass;

impl ReturnPass {
    // Check the final stmt or expr in a block for unnecessary return.
    fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) {
        if let Some(ref expr) = block.expr {
            self.check_final_expr(cx, expr);
        } else if let Some(stmt) = block.stmts.last() {
            if let StmtKind::Semi(ref expr, _) = stmt.node {
                if let ExprKind::Ret(Some(ref inner)) = expr.node {
                    self.emit_return_lint(cx, (stmt.span, inner.span));
                }
            }
        }
    }

    // Check a the final expression in a block if it's a return.
    fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        match expr.node {
            // simple return is always "bad"
            ExprKind::Ret(Some(ref inner)) => {
                self.emit_return_lint(cx, (expr.span, inner.span));
            }
            // a whole block? check it!
            ExprKind::Block(ref block) => {
                self.check_block_return(cx, block);
            }
            // an if/if let expr, check both exprs
            // note, if without else is going to be a type checking error anyways
            // (except for unit type functions) so we don't match it
            ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
                self.check_block_return(cx, ifblock);
                self.check_final_expr(cx, elsexpr);
            }
            // a match expr, check all arms
            ExprKind::Match(_, ref arms) => {
                for arm in arms {
                    self.check_final_expr(cx, &arm.body);
                }
            }
            _ => (),
        }
    }

    fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) {
        if in_external_macro(cx, spans.1) {
            return;
        }
        span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, "unneeded return statement", |db| {
            if let Some(snippet) = snippet_opt(cx, spans.1) {
                db.span_suggestion(spans.0, "remove `return` as shown:", snippet);
            }
        });
    }

    // Check for "let x = EXPR; x"
    fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) {
        // we need both a let-binding stmt and an expr
        if_let_chain! {
            [
                let Some(stmt) = block.stmts.last(),
                let Some(ref retexpr) = block.expr,
                let StmtKind::Decl(ref decl, _) = stmt.node,
                let DeclKind::Local(ref local) = decl.node,
                let Some(ref initexpr) = local.init,
                let PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node,
                let ExprKind::Path(_, ref path) = retexpr.node,
                match_path_ast(path, &[&id.name.as_str()])
            ], {
                self.emit_let_lint(cx, retexpr.span, initexpr.span);
            }
        }
    }

    fn emit_let_lint(&mut self, cx: &EarlyContext, lint_span: Span, note_span: Span) {
        if in_external_macro(cx, note_span) {
            return;
        }
        let mut db = span_lint(cx,
                               LET_AND_RETURN,
                               lint_span,
                               "returning the result of a let binding from a block. Consider returning the \
                                expression directly.");
        if cx.current_level(LET_AND_RETURN) != Level::Allow {
            db.span_note(note_span, "this expression can be directly returned");
        }
    }
}

impl LintPass for ReturnPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_RETURN, LET_AND_RETURN)
    }
}

impl EarlyLintPass for ReturnPass {
    fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) {
        self.check_block_return(cx, block);
    }

    fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
        self.check_let_return(cx, block);
    }
}
<commit_msg>Fix false-positive in `LET_AND_RETURN`<commit_after>use rustc::lint::*;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use syntax::visit::FnKind;

use utils::{span_note_and_lint, span_lint_and_then, snippet_opt, match_path_ast, in_external_macro};

/// **What it does:** This lint checks for return statements at the end of a block.
///
/// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty.
///
/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed.
///
/// **Example:** `fn foo(x: usize) { return x; }`
declare_lint! {
    pub NEEDLESS_RETURN, Warn,
    "using a return statement like `return expr;` where an expression would suffice"
}

/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned.
///
/// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty.
///
/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed.
///
/// **Example:** `{ let x = ..; x }`
declare_lint! {
    pub LET_AND_RETURN, Warn,
    "creating a let-binding and then immediately returning it like `let x = expr; x` at \
     the end of a block"
}

#[derive(Copy, Clone)]
pub struct ReturnPass;

impl ReturnPass {
    // Check the final stmt or expr in a block for unnecessary return.
    fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) {
        if let Some(ref expr) = block.expr {
            self.check_final_expr(cx, expr);
        } else if let Some(stmt) = block.stmts.last() {
            if let StmtKind::Semi(ref expr, _) = stmt.node {
                if let ExprKind::Ret(Some(ref inner)) = expr.node {
                    self.emit_return_lint(cx, (stmt.span, inner.span));
                }
            }
        }
    }

    // Check a the final expression in a block if it's a return.
    fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        match expr.node {
            // simple return is always "bad"
            ExprKind::Ret(Some(ref inner)) => {
                self.emit_return_lint(cx, (expr.span, inner.span));
            }
            // a whole block? check it!
            ExprKind::Block(ref block) => {
                self.check_block_return(cx, block);
            }
            // an if/if let expr, check both exprs
            // note, if without else is going to be a type checking error anyways
            // (except for unit type functions) so we don't match it
            ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
                self.check_block_return(cx, ifblock);
                self.check_final_expr(cx, elsexpr);
            }
            // a match expr, check all arms
            ExprKind::Match(_, ref arms) => {
                for arm in arms {
                    self.check_final_expr(cx, &arm.body);
                }
            }
            _ => (),
        }
    }

    fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) {
        if in_external_macro(cx, spans.1) {
            return;
        }
        span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, "unneeded return statement", |db| {
            if let Some(snippet) = snippet_opt(cx, spans.1) {
                db.span_suggestion(spans.0, "remove `return` as shown:", snippet);
            }
        });
    }

    // Check for "let x = EXPR; x"
    fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) {
        // we need both a let-binding stmt and an expr
        if_let_chain! {
            [
                let Some(stmt) = block.stmts.last(),
                let Some(ref retexpr) = block.expr,
                let StmtKind::Decl(ref decl, _) = stmt.node,
                let DeclKind::Local(ref local) = decl.node,
                local.ty.is_none(),
                let Some(ref initexpr) = local.init,
                let PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node,
                let ExprKind::Path(_, ref path) = retexpr.node,
                match_path_ast(path, &[&id.name.as_str()]),
                !in_external_macro(cx, initexpr.span),
            ], {
                span_note_and_lint(cx,
                                   LET_AND_RETURN,
                                   retexpr.span,
                                   "returning the result of a let binding from a block. \
                                   Consider returning the expression directly.",
                                   initexpr.span,
                                   "this expression can be directly returned");
            }
        }
    }
}

impl LintPass for ReturnPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_RETURN, LET_AND_RETURN)
    }
}

impl EarlyLintPass for ReturnPass {
    fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) {
        self.check_block_return(cx, block);
    }

    fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
        self.check_let_return(cx, block);
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate sync;

#[cfg(test)]
extern crate test;

use std::{cmp, str, fmt, rt, option, io};
use std::rand::{task_rng, Rng};
use sync::{Arc, Future};

#[cfg(test)]
use test::Bencher;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

fn main() {
  let mut brd = Board::new(65, 248).random();
  let mut timer = io::Timer::new().unwrap();

  let periodic = timer.periodic(64);
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation();
  }
}

#[deriving(Eq, Clone)]
struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

impl Board {
  fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  fn random(&self) -> Board {
    let board = task_rng().gen_iter::<bool>().take(self.len()).collect();

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  fn parallel_next_generation(&self) -> Board {
    let length = self.len();
    let num_tasks = cmp::min(rt::default_sched_threads(), length);
    let shared_brd = Arc::new(self.clone());
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks(length / num_tasks).collect();

    fn future_batch(task_brd: Arc<Board>, task: ~[uint]) -> Future<Vec<bool>> {
      Future::spawn(proc()
        task.iter().map(|&idx| task_brd.successor_cell(idx)).collect()
      )
    }

    let future_batches: Vec<Future<Vec<bool>>> = tasks.move_iter().map(|task| {
      future_batch(shared_brd.clone(), task.to_owned())
    }).collect();

    let mut new_brd: Vec<bool> = Vec::with_capacity(length);

    for b in future_batches.move_iter() {
      new_brd.push_all_move(b.unwrap());
    }

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && *self.board.get(y * self.cols + x)
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().count(|&x| x)
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows.get(0).len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd = option::collect(
      rows.concat().into_bytes().move_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      })
    );

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      str::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
static test_boards: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(test_boards[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_str(), test_boards[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  assert_eq!(testing_board(1).parallel_next_generation(), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.next_generation() }
  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.parallel_next_generation() }
  );
}
<commit_msg>Work with the new changes to Eq<commit_after>extern crate rand;
extern crate sync;

#[cfg(test)]
extern crate test;

use std::{cmp, str, fmt, rt, option, io};
use std::rand::{task_rng, Rng};
use sync::{Arc, Future};

#[cfg(test)]
use test::Bencher;

static LIVE_CELL: char = '@';
static DEAD_CELL: char = '.';

fn main() {
  let mut brd = Board::new(65, 248).random();
  let mut timer = io::Timer::new().unwrap();

  let periodic = timer.periodic(64);
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation();
  }
}

#[deriving(PartialEq, Eq, Clone)]
struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

impl Board {
  fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  fn random(&self) -> Board {
    let board = task_rng().gen_iter::<bool>().take(self.len()).collect();

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  fn parallel_next_generation(&self) -> Board {
    let length = self.len();
    let num_tasks = cmp::min(rt::default_sched_threads(), length);
    let shared_brd = Arc::new(self.clone());
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks(length / num_tasks).collect();

    fn future_batch(task_brd: Arc<Board>, task: ~[uint]) -> Future<Vec<bool>> {
      Future::spawn(proc()
        task.iter().map(|&idx| task_brd.successor_cell(idx)).collect()
      )
    }

    let future_batches: Vec<Future<Vec<bool>>> = tasks.move_iter().map(|task| {
      future_batch(shared_brd.clone(), task.to_owned())
    }).collect();

    let mut new_brd: Vec<bool> = Vec::with_capacity(length);

    for b in future_batches.move_iter() {
      new_brd.push_all_move(b.unwrap());
    }

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && *self.board.get(y * self.cols + x)
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().count(|&x| x)
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows.get(0).len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd = option::collect(
      rows.concat().into_bytes().move_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      })
    );

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      str::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
static test_boards: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(test_boards[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_str(), test_boards[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  assert_eq!(testing_board(1).parallel_next_generation(), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.next_generation() }
  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10) { brd = brd.parallel_next_generation() }
  );
}
<|endoftext|>