<commit_before>extern crate libc;

use libc::{c_int, size_t, c_void};
use std::mem;

#[repr(C)]
pub struct nl_msg;
#[repr(C)]
pub struct nlmsghdr;

#[link(name="nl-3")]
extern "C" {
	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);
	fn nlmsg_append(msg: *const nl_msg, data: *const c_void, len: size_t, pad: c_int) -> i32;
    fn nlmsg_put(msg: *const nl_msg, pid: u32, seq: u32, mtype: c_int, payload: c_int, flags: c_int) -> *const nlmsghdr;
    fn nlmsg_datalen(nlh: *const nlmsghdr) -> i32;
    fn nlmsg_next(nlh: *const nlmsghdr, remaining: *const i32) -> *const nlmsghdr;
    fn nlmsg_inherit(nlh: *const nlmsghdr) -> *const nl_msg;
    fn nlmsg_hdr(msg: *const nl_msg) -> *const nlmsghdr;
    fn nlmsg_ok(msg: *const nl_msg) -> u32;
}

pub struct NetlinkMessage {
	ptr: *const nl_msg,
    hdr: Option<*const nlmsghdr>,
}

pub fn alloc() -> NetlinkMessage {
    NetlinkMessage {
        ptr: unsafe { nlmsg_alloc() },
        hdr: None
    }
}

pub fn free(msg: NetlinkMessage) {
    unsafe { nlmsg_free(msg.ptr) }
}

pub fn append<T>(msg: &mut NetlinkMessage, data: &T, len: u32, pad: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(data);
        nlmsg_append(msg.ptr, vptr, len as size_t, pad as c_int) as i32
    }
}

pub fn put(msg: &mut NetlinkMessage, pid: u32, seq: u32, mtype: i32, payload: i32, flags: i32) -> bool {
    unsafe {
        let hdr = nlmsg_put(msg.ptr, pid, seq, mtype as c_int, payload as c_int, flags as c_int);

        match hdr as i32 {
            0x0 => false,
            _ => {
                msg.hdr = Some(hdr);
                true
            }
        }
    }
}

pub fn data_len(msg: &NetlinkMessage) -> i32 {

    match msg.hdr {
        None => 0,
        Some(hdr) => {
            unsafe { nlmsg_datalen(hdr) }
        }
    }
}

pub fn inherit(msg: &NetlinkMessage) -> NetlinkMessage {
    if msg.hdr == None {
        return alloc();
    }

    let mut m = NetlinkMessage {
        ptr: unsafe { nlmsg_inherit(msg.hdr.unwrap()) },
        hdr: None
    };

    m.hdr = Some( unsafe {nlmsg_hdr(msg.ptr)} );
    m
}

pub mod expose {
    pub fn nl_msg_ptr(msg: &mut ::message::NetlinkMessage) -> *const ::message::nl_msg {
        msg.ptr
    }

    pub fn nlmsghdr_ptr(msg: &mut ::message::NetlinkMessage) -> Option<*const ::message::nlmsghdr> {
        msg.hdr
    }
}
<commit_msg>Change exposure functions to have a normal borrow<commit_after>extern crate libc;

use libc::{c_int, size_t, c_void};
use std::mem;

#[repr(C)]
pub struct nl_msg;
#[repr(C)]
pub struct nlmsghdr;

#[link(name="nl-3")]
extern "C" {
	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);
	fn nlmsg_append(msg: *const nl_msg, data: *const c_void, len: size_t, pad: c_int) -> i32;
    fn nlmsg_put(msg: *const nl_msg, pid: u32, seq: u32, mtype: c_int, payload: c_int, flags: c_int) -> *const nlmsghdr;
    fn nlmsg_datalen(nlh: *const nlmsghdr) -> i32;
    fn nlmsg_next(nlh: *const nlmsghdr, remaining: *const i32) -> *const nlmsghdr;
    fn nlmsg_inherit(nlh: *const nlmsghdr) -> *const nl_msg;
    fn nlmsg_hdr(msg: *const nl_msg) -> *const nlmsghdr;
    fn nlmsg_ok(msg: *const nl_msg) -> u32;
}

pub struct NetlinkMessage {
	ptr: *const nl_msg,
    hdr: Option<*const nlmsghdr>,
}

pub fn alloc() -> NetlinkMessage {
    NetlinkMessage {
        ptr: unsafe { nlmsg_alloc() },
        hdr: None
    }
}

pub fn free(msg: NetlinkMessage) {
    unsafe { nlmsg_free(msg.ptr) }
}

pub fn append<T>(msg: &mut NetlinkMessage, data: &T, len: u32, pad: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(data);
        nlmsg_append(msg.ptr, vptr, len as size_t, pad as c_int) as i32
    }
}

pub fn put(msg: &mut NetlinkMessage, pid: u32, seq: u32, mtype: i32, payload: i32, flags: i32) -> bool {
    unsafe {
        let hdr = nlmsg_put(msg.ptr, pid, seq, mtype as c_int, payload as c_int, flags as c_int);

        match hdr as i32 {
            0x0 => false,
            _ => {
                msg.hdr = Some(hdr);
                true
            }
        }
    }
}

pub fn data_len(msg: &NetlinkMessage) -> i32 {

    match msg.hdr {
        None => 0,
        Some(hdr) => {
            unsafe { nlmsg_datalen(hdr) }
        }
    }
}

pub fn inherit(msg: &NetlinkMessage) -> NetlinkMessage {
    if msg.hdr == None {
        return alloc();
    }

    let mut m = NetlinkMessage {
        ptr: unsafe { nlmsg_inherit(msg.hdr.unwrap()) },
        hdr: None
    };

    m.hdr = Some( unsafe {nlmsg_hdr(msg.ptr)} );
    m
}

pub mod expose {
    pub fn nl_msg_ptr(msg: &::message::NetlinkMessage) -> *const ::message::nl_msg {
        msg.ptr
    }

    pub fn nlmsghdr_ptr(msg: &::message::NetlinkMessage) -> Option<*const ::message::nlmsghdr> {
        msg.hdr
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, Shutdown};

use net2::TcpBuilder;

use futures::{Future, Poll, Stream, Async};

use nio;
use io::{AsyncRead, AsyncWrite};
use reactor::PollableIo;

#[derive(Debug)]
pub struct TcpStream {
    inner: PollableIo<nio::TcpStream>,
}

enum ConnectState {
    Connecting(TcpStream),
    Finishing(TcpStream),
    Connected(TcpStream),
    Dead,
}

pub struct TcpConnector {
    state: ConnectState,
}

impl TcpStream {
    #[inline]
    fn from(sock: nio::TcpStream) -> Self {
        TcpStream { inner: PollableIo::new(sock) }
    }

    pub fn connect(addr: &SocketAddr) -> io::Result<TcpConnector> {
        let (sock, connected) = nio::TcpStream::connect(addr)?;
        let io = Self::from(sock);
        let state = match connected {
            false => ConnectState::Connecting(io),
            true => ConnectState::Connected(io),
        };
        Ok(TcpConnector { state })
    }

    #[inline]
    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().peer_addr()
    }

    #[inline]
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().local_addr()
    }

    #[inline]
    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
        self.inner.get_ref().shutdown(how)
    }

    #[inline]
    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        self.inner.get_ref().set_nodelay(nodelay)
    }

    #[inline]
    pub fn nodelay(&self) -> io::Result<bool> {
        self.inner.get_ref().nodelay()
    }

    #[inline]
    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        self.inner.get_ref().set_ttl(ttl)
    }

    #[inline]
    pub fn ttl(&self) -> io::Result<u32> {
        self.inner.get_ref().ttl()
    }

    #[inline]
    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.inner.get_ref().take_error()
    }
}

impl io::Read for TcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.get_mut().read(buf)
    }
}

impl nio::ReadV for TcpStream {
    #[inline]
    fn readv(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.inner.get_mut().readv(iovs)
    }
}

impl AsyncRead for TcpStream {
    #[inline]
    fn need_read(&mut self) -> io::Result<()> {
        self.inner.need_read()
    }

    #[inline]
    fn no_need_read(&mut self) -> io::Result<()> {
        self.inner.no_need_read()
    }

    #[inline]
    fn is_readable(&self) -> bool {
        self.inner.is_readable()
    }
}

impl io::Write for TcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.get_mut().write(buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.inner.get_mut().flush()
    }
}

impl nio::WriteV for TcpStream {
    #[inline]
    fn writev(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.inner.get_mut().writev(iovs)
    }
}

impl AsyncWrite for TcpStream {
    #[inline]
    fn need_write(&mut self) -> io::Result<()> {
        self.inner.need_write()
    }

    #[inline]
    fn no_need_write(&mut self) -> io::Result<()> {
        self.inner.no_need_write()
    }

    #[inline]
    fn is_writable(&self) -> bool {
        self.inner.is_writable()
    }
}

pub struct Incoming {
    io: PollableIo<nio::TcpListener>,
}

pub struct TcpListenerBuilder {
    addr: SocketAddr,
    backlog: i32,
    ttl: Option<u32>,
    only_v6: Option<bool>,
}

pub struct TcpListener {
    inner: nio::TcpListener,
}

impl TcpListener {
    #[inline]
    pub fn builder() -> TcpListenerBuilder {
        Default::default()
    }

    #[inline]
    pub fn incoming(self) -> Incoming {
        Incoming { io: PollableIo::new(self.inner) }
    }

    #[inline]
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.inner.local_addr()
    }

    #[inline]
    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        self.inner.set_ttl(ttl)
    }

    #[inline]
    pub fn ttl(&self) -> io::Result<u32> {
        self.inner.ttl()
    }

    #[inline]
    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.inner.take_error()
    }

    #[inline]
    fn from(inner: nio::TcpListener) -> Self {
        TcpListener { inner }
    }
}

impl Default for TcpListenerBuilder {
    #[inline]
    fn default() -> Self {
        TcpListenerBuilder {
            addr: SocketAddr::new(IpAddr::from(Ipv4Addr::from(0)), 0),
            backlog: 128,
            ttl: None,
            only_v6: None,
        }
    }
}

impl TcpListenerBuilder {
    #[inline]
    pub fn addr(mut self, addr: SocketAddr) -> Self {
        self.addr = addr;
        self
    }

    #[inline]
    pub fn port(mut self, port: u16) -> Self {
        self.addr.set_port(port);
        self
    }

    #[inline]
    pub fn backlog(mut self, backlog: i32) -> Self {
        self.backlog = backlog;
        self
    }

    #[inline]
    pub fn ttl(mut self, ttl: Option<u32>) -> Self {
        self.ttl = ttl;
        self
    }

    #[inline]
    pub fn only_v6(mut self, only_v6: Option<bool>) -> Self {
        self.only_v6 = only_v6;
        self
    }

    pub fn build(self) -> io::Result<TcpListener> {
        let builder = match self.addr {
            SocketAddr::V4(..) => TcpBuilder::new_v4()?,
            SocketAddr::V6(..) => TcpBuilder::new_v6()?,
        };
        if let Some(ttl) = self.ttl {
            builder.ttl(ttl)?;
        }
        if let Some(only_v6) = self.only_v6 {
            builder.only_v6(only_v6)?;
        }
        let listener = builder
            .reuse_address(true)?
            .bind(self.addr)?
            .listen(self.backlog)?;
        listener.set_nonblocking(true)?;
        Ok(TcpListener::from(nio::TcpListener::from(listener)))
    }
}

impl Stream for Incoming {
    type Item = (TcpStream, SocketAddr);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match self.io.get_ref().accept() {
            Ok((s, a)) => Ok(Async::Ready(Some((TcpStream::from(s), a)))),
            Err(e) => {
                match e.kind() {
                    io::ErrorKind::WouldBlock => {
                        self.io.need_read()?;
                        Ok(Async::NotReady)
                    }
                    _ => Err(e),
                }
            }
        }
    }
}

impl Future for TcpConnector {
    type Item = TcpStream;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match mem::replace(&mut self.state, ConnectState::Dead) {
            ConnectState::Connecting(mut sock) => {
                sock.need_write()?;
                self.state = ConnectState::Finishing(sock);
                Ok(Async::NotReady)
            }
            ConnectState::Finishing(mut sock) => {
                match sock.is_writable() {
                    true => {
                        match sock.take_error()? {
                            None => {
                                sock.no_need_write()?;
                                Ok(Async::Ready(sock))
                            }
                            Some(e) => Err(e),
                        }
                    }
                    false => {
                        self.state = ConnectState::Finishing(sock);
                        Ok(Async::NotReady)
                    }
                }
            }
            ConnectState::Connected(sock) => Ok(Async::Ready(sock)),
            _ => ::unreachable(),
        }
    }
}
<commit_msg>Ease use of TcpStream::connect<commit_after>use std::io;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, Shutdown};

use net2::TcpBuilder;

use futures::{Future, Poll, Stream, Async};

use nio;
use io::{AsyncRead, AsyncWrite};
use reactor::PollableIo;

#[derive(Debug)]
pub struct TcpStream {
    inner: PollableIo<nio::TcpStream>,
}

enum ConnectState {
    Connecting(TcpStream),
    Finishing(TcpStream),
    Connected(TcpStream),
    Error(io::Error),
    Dead,
}

pub struct TcpConnector {
    state: ConnectState,
}

impl TcpStream {
    #[inline]
    fn from(sock: nio::TcpStream) -> Self {
        TcpStream { inner: PollableIo::new(sock) }
    }

    pub fn connect(addr: &SocketAddr) -> TcpConnector {
        let state = match nio::TcpStream::connect(addr) {
            Ok((sock, connected)) => {
                let io = Self::from(sock);
                match connected {
                    false => ConnectState::Connecting(io),
                    true => ConnectState::Connected(io),
                }
            }
            Err(e) => ConnectState::Error(e),
        };
        TcpConnector { state }
    }

    #[inline]
    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().peer_addr()
    }

    #[inline]
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().local_addr()
    }

    #[inline]
    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
        self.inner.get_ref().shutdown(how)
    }

    #[inline]
    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        self.inner.get_ref().set_nodelay(nodelay)
    }

    #[inline]
    pub fn nodelay(&self) -> io::Result<bool> {
        self.inner.get_ref().nodelay()
    }

    #[inline]
    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        self.inner.get_ref().set_ttl(ttl)
    }

    #[inline]
    pub fn ttl(&self) -> io::Result<u32> {
        self.inner.get_ref().ttl()
    }

    #[inline]
    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.inner.get_ref().take_error()
    }
}

impl io::Read for TcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.get_mut().read(buf)
    }
}

impl nio::ReadV for TcpStream {
    #[inline]
    fn readv(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.inner.get_mut().readv(iovs)
    }
}

impl AsyncRead for TcpStream {
    #[inline]
    fn need_read(&mut self) -> io::Result<()> {
        self.inner.need_read()
    }

    #[inline]
    fn no_need_read(&mut self) -> io::Result<()> {
        self.inner.no_need_read()
    }

    #[inline]
    fn is_readable(&self) -> bool {
        self.inner.is_readable()
    }
}

impl io::Write for TcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.get_mut().write(buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.inner.get_mut().flush()
    }
}

impl nio::WriteV for TcpStream {
    #[inline]
    fn writev(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.inner.get_mut().writev(iovs)
    }
}

impl AsyncWrite for TcpStream {
    #[inline]
    fn need_write(&mut self) -> io::Result<()> {
        self.inner.need_write()
    }

    #[inline]
    fn no_need_write(&mut self) -> io::Result<()> {
        self.inner.no_need_write()
    }

    #[inline]
    fn is_writable(&self) -> bool {
        self.inner.is_writable()
    }
}

pub struct Incoming {
    io: PollableIo<nio::TcpListener>,
}

pub struct TcpListenerBuilder {
    addr: SocketAddr,
    backlog: i32,
    ttl: Option<u32>,
    only_v6: Option<bool>,
}

pub struct TcpListener {
    inner: nio::TcpListener,
}

impl TcpListener {
    #[inline]
    pub fn builder() -> TcpListenerBuilder {
        Default::default()
    }

    #[inline]
    pub fn incoming(self) -> Incoming {
        Incoming { io: PollableIo::new(self.inner) }
    }

    #[inline]
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.inner.local_addr()
    }

    #[inline]
    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        self.inner.set_ttl(ttl)
    }

    #[inline]
    pub fn ttl(&self) -> io::Result<u32> {
        self.inner.ttl()
    }

    #[inline]
    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.inner.take_error()
    }

    #[inline]
    fn from(inner: nio::TcpListener) -> Self {
        TcpListener { inner }
    }
}

impl Default for TcpListenerBuilder {
    #[inline]
    fn default() -> Self {
        TcpListenerBuilder {
            addr: SocketAddr::new(IpAddr::from(Ipv4Addr::from(0)), 0),
            backlog: 128,
            ttl: None,
            only_v6: None,
        }
    }
}

impl TcpListenerBuilder {
    #[inline]
    pub fn addr(mut self, addr: SocketAddr) -> Self {
        self.addr = addr;
        self
    }

    #[inline]
    pub fn port(mut self, port: u16) -> Self {
        self.addr.set_port(port);
        self
    }

    #[inline]
    pub fn backlog(mut self, backlog: i32) -> Self {
        self.backlog = backlog;
        self
    }

    #[inline]
    pub fn ttl(mut self, ttl: Option<u32>) -> Self {
        self.ttl = ttl;
        self
    }

    #[inline]
    pub fn only_v6(mut self, only_v6: Option<bool>) -> Self {
        self.only_v6 = only_v6;
        self
    }

    pub fn build(self) -> io::Result<TcpListener> {
        let builder = match self.addr {
            SocketAddr::V4(..) => TcpBuilder::new_v4()?,
            SocketAddr::V6(..) => TcpBuilder::new_v6()?,
        };
        if let Some(ttl) = self.ttl {
            builder.ttl(ttl)?;
        }
        if let Some(only_v6) = self.only_v6 {
            builder.only_v6(only_v6)?;
        }
        let listener = builder
            .reuse_address(true)?
            .bind(self.addr)?
            .listen(self.backlog)?;
        listener.set_nonblocking(true)?;
        Ok(TcpListener::from(nio::TcpListener::from(listener)))
    }
}

impl Stream for Incoming {
    type Item = (TcpStream, SocketAddr);
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match self.io.get_ref().accept() {
            Ok((s, a)) => Ok(Async::Ready(Some((TcpStream::from(s), a)))),
            Err(e) => {
                match e.kind() {
                    io::ErrorKind::WouldBlock => {
                        self.io.need_read()?;
                        Ok(Async::NotReady)
                    }
                    _ => Err(e),
                }
            }
        }
    }
}

impl Future for TcpConnector {
    type Item = TcpStream;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match mem::replace(&mut self.state, ConnectState::Dead) {
            ConnectState::Connecting(mut sock) => {
                sock.need_write()?;
                self.state = ConnectState::Finishing(sock);
                Ok(Async::NotReady)
            }
            ConnectState::Finishing(mut sock) => {
                match sock.is_writable() {
                    true => {
                        match sock.take_error()? {
                            None => {
                                sock.no_need_write()?;
                                Ok(Async::Ready(sock))
                            }
                            Some(e) => Err(e),
                        }
                    }
                    false => {
                        self.state = ConnectState::Finishing(sock);
                        Ok(Async::NotReady)
                    }
                }
            }
            ConnectState::Connected(sock) => Ok(Async::Ready(sock)),
            ConnectState::Error(e) => Err(e),
            _ => ::unreachable(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;

use commons::HASH_SIZE;
use pool::{ACTION_REQUEST_DATA, ACTION_REQUEST_DESCRIPTION, ACTION_SEND_DATA, ACTION_SEND_DESCRIPTION, MAGIC_NUMBER,
           PROTOCOL_VERSION};
use pool::Pool;
use self::byteorder::{BigEndian, ByteOrder};
use std::cmp::max;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::path::PathBuf;
use std::thread::sleep;
use std::time::{Duration, Instant};

pub struct Network
{
    socket: UdpSocket,
    client: bool,
    send_address: Vec<SocketAddr>,
    pool: Pool,
    megabit_per_second: f64,
}

impl Network
{
    fn sanity_check(&self, header: &[u8; 6]) -> bool
    {
        let mut buffer: [u8; 6] = [0; 6];
        BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
        BigEndian::write_u16(&mut buffer[4..6], PROTOCOL_VERSION);
        return header.clone() == buffer;
    }

    pub fn run(&mut self)
    {
        println!("Program started!");
        if self.client
        {
            let mut finished = false;
            'outer: while !finished
            {
                let mut started = Instant::now();
                while started.elapsed() < Duration::from_millis(2500)
                {
                    let mut buffer: [u8; 1 << 16] = [0; 1 << 16];
                    let buffer_size = match self.socket.recv_from(&mut buffer)
                    {
                        Err(_) => 0,
                        Ok(n) => n.0,
                    };
                    if buffer_size < 7
                    {
                        continue;
                    }
                    let mut head: [u8; 6] = [0; 6];
                    head.clone_from_slice(&buffer[0..6]);
                    if !self.sanity_check(&head)
                    {
                        continue;
                    }
                    if buffer[6] != ACTION_SEND_DESCRIPTION
                    {
                        continue;
                    }
                    let mut v = Vec::new();
                    v.extend_from_slice(&buffer[7..buffer_size]);
                    finished = self.pool.process_binary_description(&v);
                    if finished
                    {
                        break 'outer;
                    }
                    started = Instant::now();
                    println!("Asking for files description: {} left", self.pool.desc_left());
                }
                let mut send_request: Vec<u8> = Vec::new();
                let mut buffer: [u8; 128] = [0; 128];
                // Magic number
                BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
                send_request.extend_from_slice(&buffer[0..4]);
                // Protocol version
                BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
                send_request.extend_from_slice(&buffer[0..2]);
                // Action
                send_request.push(ACTION_REQUEST_DESCRIPTION);
                let _ = match self.socket.send_to(send_request.as_slice(), &self.send_address[0])
                {
                    Err(why) => panic!("Cannot send request for description: {}", why),
                    Ok(n) => n,
                };
            }
        }
        let mut last_print = Instant::now();
        while self.client
        {
            if self.pool.is_complete()
            {
                return;
            }
            let mut buffer: [u8; 1 << 16] = [0; 1 << 16];
            let mut buffer_size;
            let mut count = 0;
            loop
            {
                if last_print.elapsed().as_secs() > 1
                {
                    last_print = Instant::now();
                    println!("~{} kibibytes left", self.pool.chunks_left() * 60000 / 1024);
                }
                if count > 40000 / HASH_SIZE
                {
                    break;
                }
                // TODO: if someone flood us with garbage this cycle never ends
                buffer_size = match self.socket.recv_from(&mut buffer)
                {
                    Err(_) => 0,
                    Ok(n) => n.0,
                };
                if buffer_size == 0
                {
                    break;
                }
                if buffer_size < 7
                {
                    continue;
                }
                let mut head: [u8; 6] = [0; 6];
                head.clone_from_slice(&buffer[0..6]);
                if !self.sanity_check(&head)
                {
                    continue;
                }
                if buffer[6] == ACTION_SEND_DATA
                {
                    count += 1;
                    let mut v: Vec<u8> = Vec::new();
                    v.extend_from_slice(&buffer[7..buffer_size]);
                    self.pool.process_binary_data(&v);
                    if self.pool.is_complete()
                    {
                        return;
                    }
                }
            }
            let send_req = self.pool.get_binary_chunk_request();
            let _ = self.socket.send_to(send_req.as_slice(), &self.send_address[0]);
        }
        let mut send_started = Instant::now();
        while !self.client
        {
            if last_print.elapsed().as_secs() > 1
            {
                last_print = Instant::now();
                println!("Queue length: {}", self.pool.get_queue_size());
            }
            let packet = self.pool.get_binary_send_packet();
            if packet.is_none()
            {
                let _ = self.socket.set_nonblocking(false);
            }
            else
            {
                let unwrapped_packet = packet.unwrap();
                for addr in &self.send_address
                {
                    let _ = self.socket.send_to(unwrapped_packet.as_slice(), addr);
                }
                let converted_size: f64 = (unwrapped_packet.len() as f64) * 8.0 / 1000000.0;
                let milli_stop: u64 = (converted_size * 1000.0 / self.megabit_per_second) as u64;
                let _ = self.socket.set_nonblocking(true);
                sleep(Duration::from_millis(milli_stop));
            }
            let mut buffer: [u8; 1 << 16] = [0; 1 << 16];
            let buffer_size = match self.socket.recv_from(&mut buffer)
            {
                Err(_) => 0,
                Ok(n) => n.0,
            };
            if buffer_size < 7
            {
                continue;
            }
            let mut head: [u8; 6] = [0; 6];
            head.clone_from_slice(&buffer[0..6]);
            if !self.sanity_check(&head)
            {
                continue;
            }
            if buffer[6] == ACTION_REQUEST_DATA
            {
                let mut v: Vec<u8> = Vec::new();
                v.extend_from_slice(&buffer[7..buffer_size]);
                self.pool.process_binary_chunk_request(&v);
            }
            if buffer[6] == ACTION_REQUEST_DESCRIPTION || send_started.elapsed().as_secs() >= 10
            {
                send_started = Instant::now();
                let b = self.pool.generate_binary_description();
                for bv in &b
                {
                    for addr in &self.send_address
                    {
                        let _ = self.socket.send_to(bv.as_slice(), addr);
                    }
                    sleep(max(Duration::from_millis((480.0 / self.megabit_per_second) as u64), Duration::from_millis(1)));
                }
            }
        }
    }

    pub fn new(files: &Vec<PathBuf>, _client: bool, _send_address: Vec<SocketAddr>, _megabit_per_second: f64) -> Network
    {
        println!("Welcome to Stardust");
        if _client && _send_address.len() != 1
        {
            panic!("Cannot have multiple server addresses");
        }
        let sock = match if _client
        {
            UdpSocket::bind("0.0.0.0:31415")
        }
        else
        {
            UdpSocket::bind("0.0.0.0:31416")
        }
        {
            Err(why) => panic!("Cannot create socket: {}", why),
            Ok(s) => s,
        };
        if _client
        {
            println!("Waiting for bootstrap packet");
            let mut bootstrap_packet: [u8; 1 << 16] = [0; 1 << 16];
            let mut bootstrap_packet_size: usize;
            let mut send_request: Vec<u8> = Vec::new();
            let mut buffer: [u8; 128] = [0; 128];
            // Magic number
            BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
            send_request.extend_from_slice(&buffer[0..4]);
            // Protocol version
            BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
            send_request.extend_from_slice(&buffer[0..2]);
            // Action
            send_request.push(ACTION_REQUEST_DESCRIPTION);
            let _ = match sock.set_read_timeout(Some(Duration::from_millis(1500)))
            {
                Err(why) => panic!("Cannot set read timeout: {}", why),
                Ok(_) => 0,
            };
            loop
            {
                println!("Requesting bootstrap...");
                let _ = match sock.send_to(send_request.as_slice(), &_send_address[0])
                {
                    Err(why) => panic!("Cannot send request for description: {}", why),
                    Ok(n) => n,
                };
                bootstrap_packet_size = match sock.recv_from(&mut bootstrap_packet)
                {
                    Err(_) => 0,
                    Ok(v) => v.0,
                };
                if bootstrap_packet_size < 7
                {
                    continue;
                }
                if BigEndian::read_u32(&bootstrap_packet[0..4]) != MAGIC_NUMBER
                {
                    continue;
                }
                if BigEndian::read_u16(&bootstrap_packet[4..6]) != PROTOCOL_VERSION
                {
                    println!("Protocol version mismatch");
                    continue;
                }
                if bootstrap_packet[6] != ACTION_SEND_DESCRIPTION
                {
                    continue;
                }
                println!("Bootstrapping started...");
                break;
            }
            let _ = match sock.set_read_timeout(Some(Duration::from_millis(20)))
            {
                Err(why) => panic!("Cannot set read timeout: {}", why),
                Ok(_) => 0,
            };
            let mut vec_boostrap = Vec::new();
            vec_boostrap.extend_from_slice(&bootstrap_packet[7..bootstrap_packet_size]);
            return Network {
                socket: sock,
                client: true,
                send_address: _send_address,
                pool: Pool::new(files, Some(vec_boostrap)),
                megabit_per_second: _megabit_per_second,
            };
        }
        else
        {
            let _ = match sock.set_broadcast(true)
            {
                Err(why) => panic!("Cannot enable broadcast transmission: {}", why),
                Ok(_) => 0,
            };
            return Network {
                socket: sock,
                client: false,
                send_address: _send_address,
                pool: Pool::new(files, None),
                megabit_per_second: _megabit_per_second,
            };
        }
    }
}
<commit_msg>More verbose<commit_after>extern crate byteorder;

use commons::HASH_SIZE;
use pool::{ACTION_REQUEST_DATA, ACTION_REQUEST_DESCRIPTION, ACTION_SEND_DATA, ACTION_SEND_DESCRIPTION, MAGIC_NUMBER,
           PROTOCOL_VERSION};
use pool::Pool;
use self::byteorder::{BigEndian, ByteOrder};
use std::cmp::max;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::path::PathBuf;
use std::thread::sleep;
use std::time::{Duration, Instant};

pub struct Network
{
    socket: UdpSocket,
    client: bool,
    send_address: Vec<SocketAddr>,
    pool: Pool,
    megabit_per_second: f64,
}

impl Network
{
    fn sanity_check(&self, header: &[u8; 6]) -> bool
    {
        let mut buffer: [u8; 6] = [0; 6];
        BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
        BigEndian::write_u16(&mut buffer[4..6], PROTOCOL_VERSION);
        return header.clone() == buffer;
    }

    pub fn run(&mut self)
    {
        println!("Program started!");
        if self.client
        {
            let mut finished = false;
            'outer: while !finished
            {
                let mut started = Instant::now();
                while started.elapsed() < Duration::from_millis(2500)
                {
                    let mut buffer: [u8; 1 << 16] = [0; 1 << 16];
                    let buffer_size = match self.socket.recv_from(&mut buffer)
                    {
                        Err(_) => 0,
                        Ok(n) => n.0,
                    };
                    if buffer_size < 7
                    {
                        continue;
                    }
                    let mut head: [u8; 6] = [0; 6];
                    head.clone_from_slice(&buffer[0..6]);
                    if !self.sanity_check(&head)
                    {
                        continue;
                    }
                    if buffer[6] != ACTION_SEND_DESCRIPTION
                    {
                        continue;
                    }
                    let mut v = Vec::new();
                    v.extend_from_slice(&buffer[7..buffer_size]);
                    finished = self.pool.process_binary_description(&v);
                    if finished
                    {
                        break 'outer;
                    }
                    started = Instant::now();
                    println!("Asking for files description: {} left", self.pool.desc_left());
                }
                let mut send_request: Vec<u8> = Vec::new();
                let mut buffer: [u8; 128] = [0; 128];
                // Magic number
                BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
                send_request.extend_from_slice(&buffer[0..4]);
                // Protocol version
                BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
                send_request.extend_from_slice(&buffer[0..2]);
                // Action
                send_request.push(ACTION_REQUEST_DESCRIPTION);
                let _ = match self.socket.send_to(send_request.as_slice(), &self.send_address[0])
                {
                    Err(why) => panic!("Cannot send request for description: {}", why),
                    Ok(n) => n,
                };
            }
        }
        let mut last_print = Instant::now();
        while self.client
        {
            if self.pool.is_complete()
            {
                return;
            }
            let mut buffer: [u8; 1 << 16] = [0; 1 << 16];
            let mut buffer_size;
            let mut count = 0;
            loop
            {
                if last_print.elapsed().as_secs() > 1
                {
                    last_print = Instant::now();
                    println!("~{} kibibytes left", self.pool.chunks_left() * 60000 / 1024);
                }
                if count > 40000 / HASH_SIZE
                {
                    break;
                }
                // TODO: if someone flood us with garbage this cycle never ends
                buffer_size = match self.socket.recv_from(&mut buffer)
                {
                    Err(_) => 0,
                    Ok(n) => n.0,
                };
                if buffer_size == 0
                {
                    break;
                }
                if buffer_size < 7
                {
                    continue;
                }
                let mut head: [u8; 6] = [0; 6];
                head.clone_from_slice(&buffer[0..6]);
                if !self.sanity_check(&head)
                {
                    continue;
                }
                if buffer[6] == ACTION_SEND_DATA
                {
                    count += 1;
                    let mut v: Vec<u8> = Vec::new();
                    v.extend_from_slice(&buffer[7..buffer_size]);
                    self.pool.process_binary_data(&v);
                    if self.pool.is_complete()
                    {
                        return;
                    }
                }
            }
            let send_req = self.pool.get_binary_chunk_request();
            let _ = match self.socket.send_to(send_req.as_slice(), &self.send_address[0])
            {
                Ok(n) => n,
                Err(why) =>
                {
                    println!("WARNING!!! Error while sending chunk request: {}", why);
                    0
                }
            };
        }
        let mut send_started = Instant::now();
        while !self.client
        {
            if last_print.elapsed().as_secs() > 1
            {
                last_print = Instant::now();
                println!("Queue length: {}", self.pool.get_queue_size());
            }
            let packet = self.pool.get_binary_send_packet();
            if packet.is_none()
            {
                let _ = self.socket.set_nonblocking(false);
            }
            else
            {
                let unwrapped_packet = packet.unwrap();
                for addr in &self.send_address
                {
                    let _ = self.socket.send_to(unwrapped_packet.as_slice(), addr);
                }
                let converted_size: f64 = (unwrapped_packet.len() as f64) * 8.0 / 1000000.0;
                let milli_stop: u64 = (converted_size * 1000.0 / self.megabit_per_second) as u64;
                let _ = self.socket.set_nonblocking(true);
                sleep(Duration::from_millis(milli_stop));
            }
            let mut buffer: [u8; 1 << 16] = [0; 1 << 16];
            let buffer_size = match self.socket.recv_from(&mut buffer)
            {
                Err(_) => 0,
                Ok(n) => n.0,
            };
            if buffer_size < 7
            {
                continue;
            }
            let mut head: [u8; 6] = [0; 6];
            head.clone_from_slice(&buffer[0..6]);
            if !self.sanity_check(&head)
            {
                continue;
            }
            if buffer[6] == ACTION_REQUEST_DATA
            {
                let mut v: Vec<u8> = Vec::new();
                v.extend_from_slice(&buffer[7..buffer_size]);
                self.pool.process_binary_chunk_request(&v);
            }
            if buffer[6] == ACTION_REQUEST_DESCRIPTION || send_started.elapsed().as_secs() >= 10
            {
                send_started = Instant::now();
                let b = self.pool.generate_binary_description();
                for bv in &b
                {
                    for addr in &self.send_address
                    {
                        let _ = self.socket.send_to(bv.as_slice(), addr);
                    }
                    sleep(max(Duration::from_millis((480.0 / self.megabit_per_second) as u64), Duration::from_millis(1)));
                }
            }
        }
    }

    pub fn new(files: &Vec<PathBuf>, _client: bool, _send_address: Vec<SocketAddr>, _megabit_per_second: f64) -> Network
    {
        println!("Welcome to Stardust");
        if _client && _send_address.len() != 1
        {
            panic!("Cannot have multiple server addresses");
        }
        let sock = match if _client
        {
            UdpSocket::bind("0.0.0.0:31415")
        }
        else
        {
            UdpSocket::bind("0.0.0.0:31416")
        }
        {
            Err(why) => panic!("Cannot create socket: {}", why),
            Ok(s) => s,
        };
        if _client
        {
            println!("Waiting for bootstrap packet");
            let mut bootstrap_packet: [u8; 1 << 16] = [0; 1 << 16];
            let mut bootstrap_packet_size: usize;
            let mut send_request: Vec<u8> = Vec::new();
            let mut buffer: [u8; 128] = [0; 128];
            // Magic number
            BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
            send_request.extend_from_slice(&buffer[0..4]);
            // Protocol version
            BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
            send_request.extend_from_slice(&buffer[0..2]);
            // Action
            send_request.push(ACTION_REQUEST_DESCRIPTION);
            let _ = match sock.set_read_timeout(Some(Duration::from_millis(1500)))
            {
                Err(why) => panic!("Cannot set read timeout: {}", why),
                Ok(_) => 0,
            };
            loop
            {
                println!("Requesting bootstrap...");
                let _ = match sock.send_to(send_request.as_slice(), &_send_address[0])
                {
                    Err(why) => panic!("Cannot send request for description: {}", why),
                    Ok(n) => n,
                };
                bootstrap_packet_size = match sock.recv_from(&mut bootstrap_packet)
                {
                    Err(_) => 0,
                    Ok(v) => v.0,
                };
                if bootstrap_packet_size < 7
                {
                    continue;
                }
                if BigEndian::read_u32(&bootstrap_packet[0..4]) != MAGIC_NUMBER
                {
                    continue;
                }
                if BigEndian::read_u16(&bootstrap_packet[4..6]) != PROTOCOL_VERSION
                {
                    println!("Protocol version mismatch");
                    continue;
                }
                if bootstrap_packet[6] != ACTION_SEND_DESCRIPTION
                {
                    continue;
                }
                println!("Bootstrapping started...");
                break;
            }
            let _ = match sock.set_read_timeout(Some(Duration::from_millis(20)))
            {
                Err(why) => panic!("Cannot set read timeout: {}", why),
                Ok(_) => 0,
            };
            let mut vec_boostrap = Vec::new();
            vec_boostrap.extend_from_slice(&bootstrap_packet[7..bootstrap_packet_size]);
            return Network {
                socket: sock,
                client: true,
                send_address: _send_address,
                pool: Pool::new(files, Some(vec_boostrap)),
                megabit_per_second: _megabit_per_second,
            };
        }
        else
        {
            let _ = match sock.set_broadcast(true)
            {
                Err(why) => panic!("Cannot enable broadcast transmission: {}", why),
                Ok(_) => 0,
            };
            return Network {
                socket: sock,
                client: false,
                send_address: _send_address,
                pool: Pool::new(files, None),
                megabit_per_second: _megabit_per_second,
            };
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
#[cfg(unix)]
mod unix {
  extern crate libc;

  pub type fd_set = libc::fd_set;

  #[repr(C)]
  #[derive(Debug)]
  #[allow(raw_pointer_derive)]
  #[cfg(unix)]
  pub struct hostent {
      pub h_name: *mut libc::c_char,
      pub h_aliases: *mut *mut libc::c_char,
      pub h_addrtype: libc::c_int,
      pub h_length: libc::c_int,
      pub h_addr_list: *mut *mut libc::c_char,
  }

  pub type in_addr = libc::in_addr;
  pub type in6_addr = libc::in6_addr;
  pub type sockaddr = libc::sockaddr;
  pub type sockaddr_in = libc::sockaddr_in;
  pub type sockaddr_in6 = libc::sockaddr_in6;

  pub const AF_INET: i32 = libc::AF_INET;
  pub const AF_INET6: i32 = libc::AF_INET6;
}

#[cfg(windows)]
mod windows {
  extern crate winapi;
  pub type fd_set = winapi::fd_set;
  pub type hostent = winapi::winsock2::hostent;
  pub type in_addr = winapi::in_addr;
  pub type in6_addr = winapi::in6_addr;
  pub type sockaddr = winapi::SOCKADDR;
  pub type sockaddr_in = winapi::ws2def::SOCKADDR_IN;
  pub type sockaddr_in6 = winapi::ws2ipdef::sockaddr_in6;

  pub const AF_INET: i32 = winapi::ws2def::AF_INET;
  pub const AF_INET6: i32 = winapi::ws2def::AF_INET6;
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;
<commit_msg>Tidying<commit_after>#![allow(non_camel_case_types)]
#[cfg(unix)]
mod unix {
  extern crate libc;

  pub type fd_set = libc::fd_set;

  #[repr(C)]
  #[derive(Debug)]
  #[allow(raw_pointer_derive)]
  pub struct hostent {
      pub h_name: *mut libc::c_char,
      pub h_aliases: *mut *mut libc::c_char,
      pub h_addrtype: libc::c_int,
      pub h_length: libc::c_int,
      pub h_addr_list: *mut *mut libc::c_char,
  }

  pub type in_addr = libc::in_addr;
  pub type in6_addr = libc::in6_addr;
  pub type sockaddr = libc::sockaddr;
  pub type sockaddr_in = libc::sockaddr_in;
  pub type sockaddr_in6 = libc::sockaddr_in6;

  pub const AF_INET: i32 = libc::AF_INET;
  pub const AF_INET6: i32 = libc::AF_INET6;
}

#[cfg(windows)]
mod windows {
  extern crate winapi;

  pub type fd_set = winapi::fd_set;
  pub type hostent = winapi::winsock2::hostent;
  pub type in_addr = winapi::in_addr;
  pub type in6_addr = winapi::in6_addr;
  pub type sockaddr = winapi::SOCKADDR;
  pub type sockaddr_in = winapi::ws2def::SOCKADDR_IN;
  pub type sockaddr_in6 = winapi::ws2ipdef::sockaddr_in6;

  pub const AF_INET: i32 = winapi::ws2def::AF_INET;
  pub const AF_INET6: i32 = winapi::ws2def::AF_INET6;
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;
<|endoftext|>


<commit_before>//! Main functions doing actual work.
//!
//!
//! Use `create_hashes()` to prepare the hashes for a path.
//!
//! Then use `write_hashes()` to save it to disk, or `read_hashes()` to get the saved hashes, them with
//! `compare_hashes()` and print them with `write_hash_comparison_results()`.

mod compare;
mod write;

use self::super::util::{relative_name, mul_str};
use std::collections::{BTreeSet, BTreeMap};
use futures_cpupool::{CpuFuture, CpuPool};
use std::io::{BufRead, BufReader, Write};
use self::super::{Algorithm, hash_file};
use futures::future::Future;
use walkdir::WalkDir;
use std::path::{PathBuf, Path};
use tabwriter::TabWriter;
use self::super::Error;
use pbr::ProgressBar;
use std::fs::File;
use regex::Regex;
use once_cell::sync::Lazy;

pub use self::compare::*;
pub use self::write::*;

/// Create subpath->hash mappings for a given path using a given algorithm up to a given depth.
pub fn create_hashes<Wo, We>(path: &Path, ignored_files: BTreeSet<String>, algo: Algorithm, depth: Option<usize>, follow_symlinks: bool, jobs: usize,
                             pb_out: Wo, pb_err: &mut We)
                             -> BTreeMap<String, String>
    where Wo: Write,
          We: Write
{
    let mut walkdir = WalkDir::new(path).follow_links(follow_symlinks);
    if let Some(depth) = depth {
        walkdir = walkdir.max_depth(depth + 1);
    }

    let mut hashes = BTreeMap::new();
    let mut hashes_f: BTreeMap<String, CpuFuture<String, ()>> = BTreeMap::new();

    let mut errored = false;
    let pool = CpuPool::new(jobs);

    let mut walkdir = walkdir.into_iter();
    while let Some(entry) = walkdir.next() {
        match entry {
            Ok(entry) => {
                let file_type = entry.file_type();
                let filename = relative_name(path, entry.path());
                let ignored = ignored_files.contains(&filename);

                if file_type.is_file() {
                    if ignored {
                        hashes.insert(filename, mul_str("-", algo.hexlen()));
                    } else {
                        hashes_f.insert(filename, pool.spawn_fn(move || Ok(hash_file(entry.path(), algo))));
                    }
                } else if ignored {
                    walkdir.skip_current_dir();
                }
            }
            Err(error) => {
                errored = true;
                writeln!(pb_err, "Symlink loop detected at {}", relative_name(path, &error.path().unwrap())).unwrap();
            }
        }
    }

    if errored {
        writeln!(pb_err, "").unwrap();
    }

    let mut pb = ProgressBar::on(pb_out, hashes_f.len() as u64);
    pb.set_width(Some(80));
    pb.show_speed = false;
    pb.show_tick = true;

    hashes.extend(hashes_f.into_iter()
        .map(|(k, f)| {
            pb.message(&format!("{} ", k));
            pb.inc();

            match f.wait() {
                Ok(result) => return (k, result),
                Err(error) => panic!("Failed to hash file \"{}\": {:?}", k, error),
            }
        }));

    pb.show_tick = false;
    pb.tick();
    pb.finish_print("");
    hashes
}

/// Serialise the specified hashes to the specified output file.
pub fn write_hashes(out_file: &(String, PathBuf), algo: Algorithm, mut hashes: BTreeMap<String, String>) {
    let mut out = TabWriter::new(File::create(&out_file.1).unwrap());

    hashes.insert(out_file.0.clone(), mul_str("-", algo.hexlen()));
    for (fname, hash) in hashes {
        writeln!(&mut out, "{}\t{}", fname, hash).unwrap();
    }

    out.flush().unwrap();
}

/// Read hashes saved with `write_hashes()` from the specified path or fail with line numbers not matching pattern.
pub fn read_hashes(err: &mut dyn Write, file: &(String, PathBuf)) -> Result<BTreeMap<String, String>, Error> {
    static LINE_RGX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(.+?)\s{2,}([[:xdigit:]-]+)$").unwrap());

    let mut hashes = BTreeMap::new();
    let mut failed = false;

    let in_file = BufReader::new(File::open(&file.1).unwrap());
    for (n, line) in in_file.lines().map(Result::unwrap).enumerate() {
        if !line.is_empty() {
            match LINE_RGX.captures(&line) {
                Some(captures) => {
                    hashes.insert(captures[1].to_string(), captures[2].to_string());
                }
                None => {
                    failed = true;
                    writeln!(err, "{}:{}: Line doesn't match accepted pattern", file.0, n).unwrap();
                }
            };
        }
    }

    if !failed {
        Ok(hashes)
    } else {
        Err(Error::HashesFileParsingFailure)
    }
}
<commit_msg>Upper-case hashes when reading<commit_after>//! Main functions doing actual work.
//!
//!
//! Use `create_hashes()` to prepare the hashes for a path.
//!
//! Then use `write_hashes()` to save it to disk, or `read_hashes()` to get the saved hashes, them with
//! `compare_hashes()` and print them with `write_hash_comparison_results()`.

mod compare;
mod write;

use self::super::util::{relative_name, mul_str};
use std::collections::{BTreeSet, BTreeMap};
use futures_cpupool::{CpuFuture, CpuPool};
use std::io::{BufRead, BufReader, Write};
use self::super::{Algorithm, hash_file};
use futures::future::Future;
use walkdir::WalkDir;
use std::path::{PathBuf, Path};
use tabwriter::TabWriter;
use self::super::Error;
use pbr::ProgressBar;
use std::fs::File;
use regex::Regex;
use once_cell::sync::Lazy;

pub use self::compare::*;
pub use self::write::*;

/// Create subpath->hash mappings for a given path using a given algorithm up to a given depth.
pub fn create_hashes<Wo, We>(path: &Path, ignored_files: BTreeSet<String>, algo: Algorithm, depth: Option<usize>, follow_symlinks: bool, jobs: usize,
                             pb_out: Wo, pb_err: &mut We)
                             -> BTreeMap<String, String>
    where Wo: Write,
          We: Write
{
    let mut walkdir = WalkDir::new(path).follow_links(follow_symlinks);
    if let Some(depth) = depth {
        walkdir = walkdir.max_depth(depth + 1);
    }

    let mut hashes = BTreeMap::new();
    let mut hashes_f: BTreeMap<String, CpuFuture<String, ()>> = BTreeMap::new();

    let mut errored = false;
    let pool = CpuPool::new(jobs);

    let mut walkdir = walkdir.into_iter();
    while let Some(entry) = walkdir.next() {
        match entry {
            Ok(entry) => {
                let file_type = entry.file_type();
                let filename = relative_name(path, entry.path());
                let ignored = ignored_files.contains(&filename);

                if file_type.is_file() {
                    if ignored {
                        hashes.insert(filename, mul_str("-", algo.hexlen()));
                    } else {
                        hashes_f.insert(filename, pool.spawn_fn(move || Ok(hash_file(entry.path(), algo))));
                    }
                } else if ignored {
                    walkdir.skip_current_dir();
                }
            }
            Err(error) => {
                errored = true;
                writeln!(pb_err, "Symlink loop detected at {}", relative_name(path, &error.path().unwrap())).unwrap();
            }
        }
    }

    if errored {
        writeln!(pb_err, "").unwrap();
    }

    let mut pb = ProgressBar::on(pb_out, hashes_f.len() as u64);
    pb.set_width(Some(80));
    pb.show_speed = false;
    pb.show_tick = true;

    hashes.extend(hashes_f.into_iter()
        .map(|(k, f)| {
            pb.message(&format!("{} ", k));
            pb.inc();

            match f.wait() {
                Ok(result) => return (k, result),
                Err(error) => panic!("Failed to hash file \"{}\": {:?}", k, error),
            }
        }));

    pb.show_tick = false;
    pb.tick();
    pb.finish_print("");
    hashes
}

/// Serialise the specified hashes to the specified output file.
pub fn write_hashes(out_file: &(String, PathBuf), algo: Algorithm, mut hashes: BTreeMap<String, String>) {
    let mut out = TabWriter::new(File::create(&out_file.1).unwrap());

    hashes.insert(out_file.0.clone(), mul_str("-", algo.hexlen()));
    for (fname, hash) in hashes {
        writeln!(&mut out, "{}\t{}", fname, hash).unwrap();
    }

    out.flush().unwrap();
}

/// Read upper-cased hashes saved with `write_hashes()` from the specified path or fail with line numbers not matching pattern.
pub fn read_hashes(err: &mut dyn Write, file: &(String, PathBuf)) -> Result<BTreeMap<String, String>, Error> {
    static LINE_RGX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(.+?)\s{2,}([[:xdigit:]-]+)$").unwrap());

    let mut hashes = BTreeMap::new();
    let mut failed = false;

    let in_file = BufReader::new(File::open(&file.1).unwrap());
    for (n, line) in in_file.lines().map(Result::unwrap).enumerate() {
        if !line.is_empty() {
            match LINE_RGX.captures(&line) {
                Some(captures) => {
                    hashes.insert(captures[1].to_string(), captures[2].to_uppercase());
                }
                None => {
                    failed = true;
                    writeln!(err, "{}:{}: Line doesn't match accepted pattern", file.0, n).unwrap();
                }
            };
        }
    }

    if !failed {
        Ok(hashes)
    } else {
        Err(Error::HashesFileParsingFailure)
    }
}
<|endoftext|>


<commit_before>//! This module contains the common driver code. Specific implementations for
//! different databases exist elsewhere.

use error::Error;
use values::*;
use structure::*;
use request::Request;

/// The trait to be implemented by all drivers.
pub trait Driver {
  /// Get‘s the structure of the underlying database. This will run whenever a
  /// service is starting up.
  fn get_structure() -> Result<Structure, Error>;

  /// The create request. Designed after a [SQL `INSERT` statmenet][1].
  ///
  /// Returns all of the values created in the database with any automatically
  /// generated properties. This is useful if you need the id of the just
  /// inserted value.
  ///
  /// [1]: http://www.postgresql.org/docs/current/static/sql-insert.html
  fn create<Iter>(&collection: Collection,
                  values: Vec<Value>,
                  returning: Vec<Pointer> /* = all_pointer */)
                  -> Result<Iter, Error>
                  where Iter: Iterator<Item=Value>;

  // TODO: NEEDS A GOOD RANGE IMPLEMENTATION.
  // /// The read request. Designed after a [SQL `SELECT` statement][1]. Also, a
  // /// read request (after much thought) is not recursive/join capable. Instead
  // /// join decomposition should be preferred. For more information, see “[big
  // /// query v. small query][2]”.
  // ///
  // /// Must return an iterator of the set of values described in this request.
  // ///
  // /// [1]: http://www.postgresql.org/docs/current/static/sql-select.html
  // /// [2]: http://dba.stackexchange.com/questions/76973
  // fn read<Iter>(&collection: Collection,
  //               filter: Option<Filter>,
  //               range: Range,
  //               order: Vec<Ordering>,
  //               returning: Vec<Pointer> /* = all_pointer */)
  //               -> Result<Iter, Error>
  //               where Iter: Iterator<Item=Value>;

  /// The update request. Designed after a [SQL `UPDATE` statement][1].
  ///
  /// Must return an array of all the documents that were updated with this
  /// request.
  ///
  /// [1]: http://www.postgresql.org/docs/current/static/sql-update.html
  fn update<Iter>(&collection: Collection,
                  filter: Option<Filter>,
                  patches: Vec<Patch>,
                  returning: Vec<Pointer> /* = all_pointer */)
                  -> Result<Iter, Error>
                  where Iter: Iterator<Item=Value>;

  /// The delete request. Desinged after a [SQL `DELETE` statement][1].
  ///
  /// Must return an array of all documents that were deleted with this
  /// request.
  ///
  /// [1]: http://www.postgresql.org/docs/current/static/sql-delete.html
  fn delete<Iter>(&collection: Collection,
                  filter: Option<Filter>,
                  returning: Vec<Pointer> /* = all_pointer */)
                  -> Result<Iter, Error>
                  where Iter: Iterator<Item=Value>;
}
<commit_msg>Single letter traits<commit_after>//! This module contains the common driver code. Specific implementations for
//! different databases exist elsewhere.

use error::Error;
use values::*;
use structure::*;
use request::Request;

/// The trait to be implemented by all drivers.
pub trait Driver {
  /// Get‘s the structure of the underlying database. This will run whenever a
  /// service is starting up.
  fn get_structure() -> Result<Structure, Error>;

  /// The create request. Designed after a [SQL `INSERT` statmenet][1].
  ///
  /// Returns all of the values created in the database with any automatically
  /// generated properties. This is useful if you need the id of the just
  /// inserted value.
  ///
  /// [1]: http://www.postgresql.org/docs/current/static/sql-insert.html
  fn create<I>(&collection: Collection,
               values: Vec<Value>,
               returning: Vec<Pointer> /* = all_pointer */)
               -> Result<I, Error>
               where I: Iterator<Item=Value>;

  // TODO: NEEDS A GOOD RANGE IMPLEMENTATION.
  // /// The read request. Designed after a [SQL `SELECT` statement][1]. Also, a
  // /// read request (after much thought) is not recursive/join capable. Instead
  // /// join decomposition should be preferred. For more information, see “[big
  // /// query v. small query][2]”.
  // ///
  // /// Must return an iterator of the set of values described in this request.
  // ///
  // /// [1]: http://www.postgresql.org/docs/current/static/sql-select.html
  // /// [2]: http://dba.stackexchange.com/questions/76973
  // fn read<I>(&collection: Collection,
  //            filter: Option<Filter>,
  //            range: Range,
  //            order: Vec<Ordering>,
  //            returning: Vec<Pointer> /* = all_pointer */)
  //            -> Result<I, Error>
  //            where I: Iterator<Item=Value>;

  /// The update request. Designed after a [SQL `UPDATE` statement][1].
  ///
  /// Must return an array of all the documents that were updated with this
  /// request.
  ///
  /// [1]: http://www.postgresql.org/docs/current/static/sql-update.html
  fn update<I>(&collection: Collection,
               filter: Option<Filter>,
               patches: Vec<Patch>,
               returning: Vec<Pointer> /* = all_pointer */)
               -> Result<I, Error>
               where I: Iterator<Item=Value>;

  /// The delete request. Desinged after a [SQL `DELETE` statement][1].
  ///
  /// Must return an array of all documents that were deleted with this
  /// request.
  ///
  /// [1]: http://www.postgresql.org/docs/current/static/sql-delete.html
  fn delete<I>(&collection: Collection,
               filter: Option<Filter>,
               returning: Vec<Pointer> /* = all_pointer */)
               -> Result<I, Error>
               where I: Iterator<Item=Value>;
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    kv_storage::KVStorage, Capability, CryptoKVStorage, Error, Identity, Policy, Storage, Value,
};
use libra_vault_client::{self as vault, Client};

/// VaultStorage utilizes Vault for maintaining encrypted, authenticated data for Libra. This
/// version currently matches the behavior of OnDiskStorage and InMemoryStorage. In the future,
/// Vault will be able to create keys, sign messages, and handle permissions across different
/// services. The specific vault service leveraged herein is called KV (Key Value) Secrets Engine -
/// Version 2 (https://www.vaultproject.io/api/secret/kv/kv-v2.html). So while Libra Secure Storage
/// calls pointers to data keys, Vault has actually a secret that contains multiple key value
/// pairs.
pub struct VaultStorage {
    pub client: Client,
}

impl VaultStorage {
    pub fn new(host: String, token: String) -> Self {
        Self {
            client: Client::new(host, token),
        }
    }

    /// Erase all secrets and keys from the vault storage. Use with caution.
    pub fn reset(&self) -> Result<(), Error> {
        let secrets = self.client.list_secrets("")?;
        for secret in secrets {
            self.client.delete_secret(&secret)?;
        }
        Ok(())
    }

    /// Retrieves a key from a given secret. Libra Secure Storage inserts each key into its own
    /// distinct secret store and thus the secret and key have the same identifier.
    fn get_secret(&self, key: &str) -> Result<Value, Error> {
        let value = self.client.read_secret(key, key)?;
        let v = Value::from_base64(&value).unwrap();
        Ok(v)
    }

    /// Inserts a key, value pair into a secret that shares the name of the key.
    fn set_secret(&self, key: &str, value: Value) -> Result<(), Error> {
        self.client.write_secret(key, key, &value.to_base64()?)?;
        Ok(())
    }

    /// Create a new policy in Vault, see the explanation for Policy for how the data is
    /// structured. Vault does not distingush a create and update. An update must first read the
    /// existing policy, amend the contents,  and then be applied via this API.
    fn set_policy(
        &self,
        policy_name: &str,
        key: &str,
        capabilities: &[Capability],
    ) -> Result<(), Error> {
        let path = format!("secret/data/{}", key);
        let mut vault_policy = self.client.read_policy(&policy_name).unwrap_or_default();
        let vault_capabilities: Vec<vault::Capability> = capabilities
            .iter()
            .map(|c| match c {
                Capability::Write => vault::Capability::Update,
                Capability::Read => vault::Capability::Read,
            })
            .collect();
        vault_policy.add_policy(&path, vault_capabilities);
        self.client.set_policy(policy_name, &vault_policy)?;
        Ok(())
    }

    /// Public convenience function to return a new Vault based Storage.
    pub fn new_boxed_vault_storage(host: String, token: String) -> Box<dyn Storage> {
        Box::new(VaultStorage::new(host, token))
    }
}

impl KVStorage for VaultStorage {
    fn available(&self) -> bool {
        self.client.unsealed().unwrap_or(false)
    }

    fn create(&mut self, key: &str, value: Value, policy: &Policy) -> Result<(), Error> {
        // Vault internally does not distinguish creation versus update except by permissions. So we
        // simulate that by first getting the key. If it doesn't exist, we're okay.
        match self.get_secret(&key) {
            Ok(_) => return Err(Error::KeyAlreadyExists(key.to_string())),
            Err(Error::KeyNotSet(_)) => (/* Expected this for new keys! */),
            Err(e) => return Err(e),
        }

        self.set_secret(&key, value)?;
        for permission in &policy.permissions {
            match &permission.id {
                Identity::User(id) => self.set_policy(id, key, &permission.capabilities)?,
                Identity::Anyone => self.set_policy("default", key, &permission.capabilities)?,
                Identity::NoOne => (),
            };
        }
        Ok(())
    }

    fn get(&self, key: &str) -> Result<Value, Error> {
        self.get_secret(&key)
    }

    fn set(&mut self, key: &str, value: Value) -> Result<(), Error> {
        // Vault internally does not distinguish create versus udpate except by permissions. So we
        // simulate that by first getting the key. If it exists, we can update it.
        self.get_secret(&key)?;
        self.set_secret(&key, value)?;
        Ok(())
    }

    #[cfg(test)]
    fn reset_and_clear(&mut self) -> Result<(), Error> {
        self.reset()
    }
}

impl CryptoKVStorage for VaultStorage {}
<commit_msg>[secure-storage] make vault internal logic only visible to local crate<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    kv_storage::KVStorage, Capability, CryptoKVStorage, Error, Identity, Policy, Storage, Value,
};
use libra_vault_client::{self as vault, Client};

/// VaultStorage utilizes Vault for maintaining encrypted, authenticated data for Libra. This
/// version currently matches the behavior of OnDiskStorage and InMemoryStorage. In the future,
/// Vault will be able to create keys, sign messages, and handle permissions across different
/// services. The specific vault service leveraged herein is called KV (Key Value) Secrets Engine -
/// Version 2 (https://www.vaultproject.io/api/secret/kv/kv-v2.html). So while Libra Secure Storage
/// calls pointers to data keys, Vault has actually a secret that contains multiple key value
/// pairs.
pub struct VaultStorage {
    pub(crate) client: Client,
}

impl VaultStorage {
    pub fn new(host: String, token: String) -> Self {
        Self {
            client: Client::new(host, token),
        }
    }

    /// Erase all secrets and keys from the vault storage. Use with caution.
    pub fn reset(&self) -> Result<(), Error> {
        let secrets = self.client.list_secrets("")?;
        for secret in secrets {
            self.client.delete_secret(&secret)?;
        }
        Ok(())
    }

    /// Retrieves a key from a given secret. Libra Secure Storage inserts each key into its own
    /// distinct secret store and thus the secret and key have the same identifier.
    fn get_secret(&self, key: &str) -> Result<Value, Error> {
        let value = self.client.read_secret(key, key)?;
        let v = Value::from_base64(&value).unwrap();
        Ok(v)
    }

    /// Inserts a key, value pair into a secret that shares the name of the key.
    fn set_secret(&self, key: &str, value: Value) -> Result<(), Error> {
        self.client.write_secret(key, key, &value.to_base64()?)?;
        Ok(())
    }

    /// Create a new policy in Vault, see the explanation for Policy for how the data is
    /// structured. Vault does not distingush a create and update. An update must first read the
    /// existing policy, amend the contents,  and then be applied via this API.
    fn set_policy(
        &self,
        policy_name: &str,
        key: &str,
        capabilities: &[Capability],
    ) -> Result<(), Error> {
        let path = format!("secret/data/{}", key);
        let mut vault_policy = self.client.read_policy(&policy_name).unwrap_or_default();
        let vault_capabilities: Vec<vault::Capability> = capabilities
            .iter()
            .map(|c| match c {
                Capability::Write => vault::Capability::Update,
                Capability::Read => vault::Capability::Read,
            })
            .collect();
        vault_policy.add_policy(&path, vault_capabilities);
        self.client.set_policy(policy_name, &vault_policy)?;
        Ok(())
    }

    /// Public convenience function to return a new Vault based Storage.
    pub fn new_boxed_vault_storage(host: String, token: String) -> Box<dyn Storage> {
        Box::new(VaultStorage::new(host, token))
    }
}

impl KVStorage for VaultStorage {
    fn available(&self) -> bool {
        self.client.unsealed().unwrap_or(false)
    }

    fn create(&mut self, key: &str, value: Value, policy: &Policy) -> Result<(), Error> {
        // Vault internally does not distinguish creation versus update except by permissions. So we
        // simulate that by first getting the key. If it doesn't exist, we're okay.
        match self.get_secret(&key) {
            Ok(_) => return Err(Error::KeyAlreadyExists(key.to_string())),
            Err(Error::KeyNotSet(_)) => (/* Expected this for new keys! */),
            Err(e) => return Err(e),
        }

        self.set_secret(&key, value)?;
        for permission in &policy.permissions {
            match &permission.id {
                Identity::User(id) => self.set_policy(id, key, &permission.capabilities)?,
                Identity::Anyone => self.set_policy("default", key, &permission.capabilities)?,
                Identity::NoOne => (),
            };
        }
        Ok(())
    }

    fn get(&self, key: &str) -> Result<Value, Error> {
        self.get_secret(&key)
    }

    fn set(&mut self, key: &str, value: Value) -> Result<(), Error> {
        // Vault internally does not distinguish create versus udpate except by permissions. So we
        // simulate that by first getting the key. If it exists, we can update it.
        self.get_secret(&key)?;
        self.set_secret(&key, value)?;
        Ok(())
    }

    #[cfg(test)]
    fn reset_and_clear(&mut self) -> Result<(), Error> {
        self.reset()
    }
}

impl CryptoKVStorage for VaultStorage {}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::iterator::Iterator;
use std::ascii::to_ascii_lower;
use cssparser::*;
use selectors;
use properties;
use errors::{ErrorLoggerIterator, log_css_error};
use namespaces::{NamespaceMap, parse_namespace_rule};
use media_queries::{MediaRule, parse_media_rule};

pub struct Stylesheet {
    style_rules: ~[CSSRule],
    namespaces: NamespaceMap,
}

pub enum CSSRule {
    CSSStyleRule(StyleRule),
    CSSMediaRule(MediaRule),
}

pub struct StyleRule {
    selectors: ~[selectors::Selector],
    declarations: ~[properties::PropertyDeclaration],
}

fn parse_stylesheet(css: &str) -> Stylesheet {
    static STATE_CHARSET: uint = 1;
    static STATE_IMPORTS: uint = 2;
    static STATE_NAMESPACES: uint = 3;
    static STATE_BODY: uint = 4;
    let mut state: uint = STATE_CHARSET;

    let mut rules = ~[];
    let mut namespaces = NamespaceMap::new();

    for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
        let next_state;  // Unitialized to force each branch to set it.
        match rule {
            QualifiedRule(rule) => {
                next_state = STATE_BODY;
                parse_style_rule(rule, &mut rules, &namespaces)
            },
            AtRule(rule) => {
                let lower_name: &str = to_ascii_lower(rule.name);
                match lower_name {
                    "charset" => {
                        if state > STATE_CHARSET {
                            log_css_error(rule.location, "@charset must be the first rule")
                        }
                        // Valid @charset rules are just ignored
                        next_state = state;
                    },
                    "import" => {
                        if state > STATE_IMPORTS {
                            next_state = state;
                            log_css_error(rule.location,
                                          "@import must be before any rule but @charset")
                        } else {
                            next_state = STATE_IMPORTS;
                            log_css_error(rule.location, "@import is not supported yet")  // TODO
                        }
                    },
                    "namespace" => {
                        if state > STATE_NAMESPACES {
                            next_state = state;
                            log_css_error(
                                rule.location,
                                "@namespace must be before any rule but @charset and @import"
                            )
                        } else {
                            next_state = STATE_NAMESPACES;
                            parse_namespace_rule(rule, &mut namespaces)
                        }
                    },
                    _ => {
                        next_state = STATE_BODY;
                        parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
                    },
                }
            },
        }
        state = next_state;
    }
    Stylesheet{ style_rules: rules, namespaces: namespaces }
}

pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
                        namespaces: &NamespaceMap) {
    let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
    match selectors::parse_selector_list(prelude, namespaces) {
        Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
            selectors: selectors,
            declarations: properties::parse_property_declaration_list(block)
        })),
        None => log_css_error(location, "Unsupported CSS selector."),
    }
}

// lower_name is passed explicitly to avoid computing it twice.
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
                            parent_rules: &mut ~[CSSRule], namespaces: &NamespaceMap) {
    match lower_name {
        "media" => parse_media_rule(rule, parent_rules, namespaces),
        _ => log_css_error(rule.location, fmt!("Unsupported at-rule: @%s", lower_name))
    }
}
<commit_msg>Add a recursive style rule iterator for stylesheets.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::iterator::Iterator;
use std::ascii::to_ascii_lower;
use cssparser::*;
use selectors;
use properties;
use errors::{ErrorLoggerIterator, log_css_error};
use namespaces::{NamespaceMap, parse_namespace_rule};
use media_queries::{MediaRule, parse_media_rule};
use media_queries;

pub struct Stylesheet {
    rules: ~[CSSRule],
    namespaces: NamespaceMap,
}

pub enum CSSRule {
    CSSStyleRule(StyleRule),
    CSSMediaRule(MediaRule),
}

pub struct StyleRule {
    selectors: ~[selectors::Selector],
    declarations: ~[properties::PropertyDeclaration],
}

fn parse_stylesheet(css: &str) -> Stylesheet {
    static STATE_CHARSET: uint = 1;
    static STATE_IMPORTS: uint = 2;
    static STATE_NAMESPACES: uint = 3;
    static STATE_BODY: uint = 4;
    let mut state: uint = STATE_CHARSET;

    let mut rules = ~[];
    let mut namespaces = NamespaceMap::new();

    for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
        let next_state;  // Unitialized to force each branch to set it.
        match rule {
            QualifiedRule(rule) => {
                next_state = STATE_BODY;
                parse_style_rule(rule, &mut rules, &namespaces)
            },
            AtRule(rule) => {
                let lower_name: &str = to_ascii_lower(rule.name);
                match lower_name {
                    "charset" => {
                        if state > STATE_CHARSET {
                            log_css_error(rule.location, "@charset must be the first rule")
                        }
                        // Valid @charset rules are just ignored
                        next_state = state;
                    },
                    "import" => {
                        if state > STATE_IMPORTS {
                            next_state = state;
                            log_css_error(rule.location,
                                          "@import must be before any rule but @charset")
                        } else {
                            next_state = STATE_IMPORTS;
                            log_css_error(rule.location, "@import is not supported yet")  // TODO
                        }
                    },
                    "namespace" => {
                        if state > STATE_NAMESPACES {
                            next_state = state;
                            log_css_error(
                                rule.location,
                                "@namespace must be before any rule but @charset and @import"
                            )
                        } else {
                            next_state = STATE_NAMESPACES;
                            parse_namespace_rule(rule, &mut namespaces)
                        }
                    },
                    _ => {
                        next_state = STATE_BODY;
                        parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
                    },
                }
            },
        }
        state = next_state;
    }
    Stylesheet{ rules: rules, namespaces: namespaces }
}

pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
                        namespaces: &NamespaceMap) {
    let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
    match selectors::parse_selector_list(prelude, namespaces) {
        Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
            selectors: selectors,
            declarations: properties::parse_property_declaration_list(block)
        })),
        None => log_css_error(location, "Unsupported CSS selector."),
    }
}

// lower_name is passed explicitly to avoid computing it twice.
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
                            parent_rules: &mut ~[CSSRule], namespaces: &NamespaceMap) {
    match lower_name {
        "media" => parse_media_rule(rule, parent_rules, namespaces),
        _ => log_css_error(rule.location, fmt!("Unsupported at-rule: @%s", lower_name))
    }
}

impl Stylesheet {
    fn iter_style_rules<'a>(&'a self, device: media_queries::Device) -> StyleRuleIterator<'a> {
        StyleRuleIterator { device: device, stack: ~[(self.rules.as_slice(), 0)] }
    }
}

struct StyleRuleIterator<'self> {
    device: media_queries::Device,
    // FIXME: I couldn’t get this to borrow-check with a stack of VecIterator
    stack: ~[(&'self [CSSRule], uint)],
}

impl<'self> Iterator<&'self StyleRule> for StyleRuleIterator<'self> {
    fn next(&mut self) -> Option<&'self StyleRule> {
        loop {
            match self.stack.pop_opt() {
                None => return None,
                Some((rule_list, i)) => {
                    if i + 1 < rule_list.len() {
                        self.stack.push((rule_list, i + 1))
                    }
                    match rule_list[i] {
                        CSSStyleRule(ref rule) => return Some(rule),
                        CSSMediaRule(ref rule) => {
                            if rule.media_queries.evaluate(&self.device) {
                                self.stack.push((rule.rules.as_slice(), 0))
                            }
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Generator Engine backend
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
//============================================================================

use std::sync::mpsc::{Sender, Receiver};
use std::vec::Vec;

use protocol::{RenderType, EngineStatus, EngineCommand};

static PREVIEW_WIDTH: i32 = 256;
static PREVIEW_HEIGHT: i32 = 256;

//----------------------------------------------------------------------------

type RGB8 = (u8, u8, u8);

pub struct MandelEngine {
    buffer_width: u32,
    buffer_height: u32,
    palette: Vec<RGB8>,
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
}

impl MandelEngine {

    pub fn new(w: u32, h: u32) -> MandelEngine {

        // Init palette using hue sweep in HSV colour space
        let mut p: Vec<RGB8> = Vec::with_capacity(720);
        let s = 1.0f32; // saturation
        let v = 1.0f32; // value
        let c = v * s; // chroma
        for h in 0..720u32 { // hue
            let hp = h as f32/60.0;
            let x = c * (1.0-(hp % 2.0 - 1.0).abs());
            let (r,g,b) = if 0.0 <= hp && hp < 1.0 {
                (c, x, 0.0)
            } else if 1.0 <= hp && hp < 2.0 {
                (x, c, 0.0)
            } else if 2.0 <= hp && hp < 3.0 {
                (0.0, c, x)
            } else if 3.0 <= hp && hp < 4.0 {
                (0.0, x, c)
            } else if 4.0 <= hp && hp < 5.0 {
                (x, 0.0, c)
            } else if 5.0 <= hp && hp < 6.0 {
                (c, 0.0, x)
            } else {
                (0.0, 0.0, 0.0)
            };
            let m = v-c;
            p.push((((r+m)*255.0) as u8, ((g+m)*255.0) as u8, ((b+m)*255.0) as u8));
        }

        MandelEngine {
            re0: -1.4f32,
            re1:  0.6f32,
            im0: -1.0f32,
            im1:  1.0f32,
            buffer_width: w,
            buffer_height: h,
            palette: p
        }
    }

    // Rescale pixel coord (x,y) into cspace
    fn scale_coords(&self, x: u32, y: u32, w: u32, h: u32) -> (f32, f32) {
        let x0 = self.re0;
        let x1 = self.re1;
        let y0 = self.im0;
        let y1 = self.im1;

        let xx = (x as f32) / (w as f32) * (x1-x0) + x0;
        let yy = (y as f32) / (h as f32) * (y1-y0) + y0;

        (xx, yy)
    }

    pub fn serve(&mut self, cmd_chan: &Receiver<EngineCommand>, progress_chan: &Sender<EngineStatus>) {
        let mut running = true;
        while running {
            // pan/zoom by 10% of width
            let delta_r = ((self.re1 - self.re0)*0.1f32).abs();
            let delta_i = ((self.im1 - self.im0)*0.1f32).abs();
            println!("delta r,i {},{}", delta_r, delta_i);

            let cmd = cmd_chan.recv().unwrap();
            println!("engine: command {:?}", cmd);
            match cmd {
                EngineCommand::UpdateRegion(re0, re1, im0, im1) => {
                    self.re0 = re0; self.re1 = re1; self.im0 = im0; self.im1 = im1;
                },
                EngineCommand::ZoomIn => {
                    self.re0 += delta_r;
                    self.re1 -= delta_r;
                    self.im0 += delta_i;
                    self.im1 -= delta_i;
                },
                EngineCommand::ZoomOut => {
                    self.re0 -= delta_r;
                    self.re1 += delta_r;
                    self.im0 -= delta_i;
                    self.im1 += delta_i;
                },
                EngineCommand::PanLeft => {
                    self.re0 -= delta_r;
                    self.re1 -= delta_r;
                },
                EngineCommand::PanRight => {
                    self.re0 += delta_r;
                    self.re1 += delta_r;
                },
                EngineCommand::PanUp => {
                    self.im0 += delta_i;
                    self.im1 += delta_i;
                },
                EngineCommand::PanDown => {
                    self.im0 -= delta_i;
                    self.im1 -= delta_i;
                },
                EngineCommand::Render(typ) => self.process(typ, progress_chan),
                EngineCommand::Shutdown => running = false,
            }
        }

        println!("engine: shutdown");
    }

    // Evalute entire region
    fn process(&mut self, typ: RenderType, progress_chan: &Sender<EngineStatus>) {

        let (width, height) = match typ {
            RenderType::PreviewRender => (PREVIEW_WIDTH as u32, PREVIEW_HEIGHT as u32),
            RenderType::FullRender => (self.buffer_width, self.buffer_height),
        };

        let mut img: Vec<u8> = Vec::with_capacity((width*height*3) as usize);

        let max_iteration = 500;

        println!("+++ process {}x{} RGB8 in {} bytes", width, height, img.capacity());
        println!("            re: {}..{} im: {}..{}", self.re0, self.re1, self.im0, self.im1);

        progress_chan.send(EngineStatus::Startup).unwrap();

        // Process each pixel
        for py in 0..height {
            for px in 0..width {

                // Project pixels into Mandelbrot domain
                let (x0, y0) = self.scale_coords(px, py, width, height);

                let mut x = 0.0f32;
                let mut y = 0.0f32;
                let mut iteration = 0;

                // Iterate!
                while (x*x + y*y < 4.0) && (iteration < max_iteration) {
                    let x1 = x*x - y*y + x0;
                    y = 2.0*x*y + y0;
                    x = x1;

                    iteration += 1;
                }

                // Colour and plot
                let color = self.palette.get(iteration % 580);
                let &(r,g, b) = color.unwrap();

                img.push(r);
                img.push(g);
                img.push(b);
            }
            if py % 100 == 0 {
                progress_chan.send(EngineStatus::Processing(py)).unwrap();
            }
        }

        progress_chan.send(EngineStatus::RenderComplete(typ, img)).unwrap();
    }
}

//----------------------------------------------------------------------------
<commit_msg>Improve error handling/reporting in serve<commit_after>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Generator Engine backend
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
//============================================================================

use std::sync::mpsc::{Sender, Receiver};
use std::vec::Vec;

use protocol::{RenderType, EngineStatus, EngineCommand};

static PREVIEW_WIDTH: i32 = 256;
static PREVIEW_HEIGHT: i32 = 256;

//----------------------------------------------------------------------------

type RGB8 = (u8, u8, u8);

pub struct MandelEngine {
    buffer_width: u32,
    buffer_height: u32,
    palette: Vec<RGB8>,
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
}

impl MandelEngine {

    pub fn new(w: u32, h: u32) -> MandelEngine {

        // Init palette using hue sweep in HSV colour space
        let mut p: Vec<RGB8> = Vec::with_capacity(720);
        let s = 1.0f32; // saturation
        let v = 1.0f32; // value
        let c = v * s; // chroma
        for h in 0..720u32 { // hue
            let hp = h as f32/60.0;
            let x = c * (1.0-(hp % 2.0 - 1.0).abs());
            let (r,g,b) = if 0.0 <= hp && hp < 1.0 {
                (c, x, 0.0)
            } else if 1.0 <= hp && hp < 2.0 {
                (x, c, 0.0)
            } else if 2.0 <= hp && hp < 3.0 {
                (0.0, c, x)
            } else if 3.0 <= hp && hp < 4.0 {
                (0.0, x, c)
            } else if 4.0 <= hp && hp < 5.0 {
                (x, 0.0, c)
            } else if 5.0 <= hp && hp < 6.0 {
                (c, 0.0, x)
            } else {
                (0.0, 0.0, 0.0)
            };
            let m = v-c;
            p.push((((r+m)*255.0) as u8, ((g+m)*255.0) as u8, ((b+m)*255.0) as u8));
        }

        MandelEngine {
            re0: -1.4f32,
            re1:  0.6f32,
            im0: -1.0f32,
            im1:  1.0f32,
            buffer_width: w,
            buffer_height: h,
            palette: p
        }
    }

    // Rescale pixel coord (x,y) into cspace
    fn scale_coords(&self, x: u32, y: u32, w: u32, h: u32) -> (f32, f32) {
        let x0 = self.re0;
        let x1 = self.re1;
        let y0 = self.im0;
        let y1 = self.im1;

        let xx = (x as f32) / (w as f32) * (x1-x0) + x0;
        let yy = (y as f32) / (h as f32) * (y1-y0) + y0;

        (xx, yy)
    }

    pub fn serve(&mut self, cmd_chan: &Receiver<EngineCommand>, progress_chan: &Sender<EngineStatus>) {
        let mut running = true;
        while running {
            // pan/zoom by 10% of width
            let delta_r = ((self.re1 - self.re0)*0.1f32).abs();
            let delta_i = ((self.im1 - self.im0)*0.1f32).abs();
            println!("delta r,i {},{}", delta_r, delta_i);

            let cmd = match cmd_chan.recv() {
                Ok(cmd) => cmd,
                Err(e) => {
                    println!("serve: cmd_chan error: {}", e);
                    running = false;
                    break;
                }
            };

            println!("engine: command {:?}", cmd);
            match cmd {
                EngineCommand::UpdateRegion(re0, re1, im0, im1) => {
                    self.re0 = re0; self.re1 = re1; self.im0 = im0; self.im1 = im1;
                },
                EngineCommand::ZoomIn => {
                    self.re0 += delta_r;
                    self.re1 -= delta_r;
                    self.im0 += delta_i;
                    self.im1 -= delta_i;
                },
                EngineCommand::ZoomOut => {
                    self.re0 -= delta_r;
                    self.re1 += delta_r;
                    self.im0 -= delta_i;
                    self.im1 += delta_i;
                },
                EngineCommand::PanLeft => {
                    self.re0 -= delta_r;
                    self.re1 -= delta_r;
                },
                EngineCommand::PanRight => {
                    self.re0 += delta_r;
                    self.re1 += delta_r;
                },
                EngineCommand::PanUp => {
                    self.im0 += delta_i;
                    self.im1 += delta_i;
                },
                EngineCommand::PanDown => {
                    self.im0 -= delta_i;
                    self.im1 -= delta_i;
                },
                EngineCommand::Render(typ) => self.process(typ, progress_chan),
                EngineCommand::Shutdown => running = false,
            }
        }

        println!("engine: shutdown");
    }

    // Evalute entire region
    fn process(&mut self, typ: RenderType, progress_chan: &Sender<EngineStatus>) {

        let (width, height) = match typ {
            RenderType::PreviewRender => (PREVIEW_WIDTH as u32, PREVIEW_HEIGHT as u32),
            RenderType::FullRender => (self.buffer_width, self.buffer_height),
        };

        let mut img: Vec<u8> = Vec::with_capacity((width*height*3) as usize);

        let max_iteration = 500;

        println!("+++ process {}x{} RGB8 in {} bytes", width, height, img.capacity());
        println!("            re: {}..{} im: {}..{}", self.re0, self.re1, self.im0, self.im1);

        progress_chan.send(EngineStatus::Startup).unwrap();

        // Process each pixel
        for py in 0..height {
            for px in 0..width {

                // Project pixels into Mandelbrot domain
                let (x0, y0) = self.scale_coords(px, py, width, height);

                let mut x = 0.0f32;
                let mut y = 0.0f32;
                let mut iteration = 0;

                // Iterate!
                while (x*x + y*y < 4.0) && (iteration < max_iteration) {
                    let x1 = x*x - y*y + x0;
                    y = 2.0*x*y + y0;
                    x = x1;

                    iteration += 1;
                }

                // Colour and plot
                let color = self.palette.get(iteration % 580);
                let &(r,g, b) = color.unwrap();

                img.push(r);
                img.push(g);
                img.push(b);
            }
            if py % 100 == 0 {
                progress_chan.send(EngineStatus::Processing(py)).unwrap();
            }
        }

        progress_chan.send(EngineStatus::RenderComplete(typ, img)).unwrap();
    }
}

//----------------------------------------------------------------------------
<|endoftext|>