<commit_before>use std::fmt;
use std::io;
use std::error::Error;
use std::marker::PhantomData;
use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero};

use time::SteadyTime;
use rotor::{Response, Scope, Machine};
use mio::{EventSet, PollOpt};
use netbuf::Buf;
use void::{Void, unreachable};

use substr::find_substr;
use {Expectation, Protocol, StreamSocket, Stream, StreamImpl, Request};
use {Transport, Deadline, Accepted, Exception};

#[derive(Debug)]
enum IoOp {
    Done,
    NoOp,
    Eos,
    Error(io::Error),
}

impl<S: StreamSocket> StreamImpl<S> {
    fn transport(&mut self) -> Transport<S> {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    fn _action<C, M>(mut self, req: Request<M>, scope: &mut Scope<C>)
        -> Result<Stream<C, S, M>, ()>
        where M: Protocol<C, S>,
              S: StreamSocket,
    {
        use Expectation::*;
        let mut req = try!(req.ok_or(()));
        let mut can_write = match self.write() {
            IoOp::Done => true,
            IoOp::NoOp => false,
            IoOp::Eos => {
                req = try!(req.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(io::Error::new(
                        WriteZero, "failed to write whole buffer")),
                    scope).ok_or(()));
                self.outbuf.remove_range(..);
                false
            }
            IoOp::Error(e) => {
                req = try!(req.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(e),
                    scope).ok_or(()));
                // TODO(tailhook) should we flush buffer here too?
                false
            }
        };
        'outer: loop {
            if can_write {
                can_write = match self.write() {
                    IoOp::Done => true,
                    IoOp::NoOp => false,
                    IoOp::Eos => {
                        req = try!(req.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(io::Error::new(
                                WriteZero, "failed to write whole buffer")),
                            scope).ok_or(()));
                        self.outbuf.remove_range(..);
                        false
                    }
                    IoOp::Error(e) => {
                        req = try!(req.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(e),
                            scope).ok_or(()));
                        // TODO(tailhook) should we flush buffer here too?
                        false
                    }
                };
            }
            match req.1 {
                Bytes(num) => {
                    loop {
                        if self.inbuf.len() >= num {
                            req = try!(req.0.bytes_read(&mut self.transport(),
                                num, scope).ok_or(()));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, req, scope));
                            }
                            IoOp::Eos => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                        }
                    }
                }
                Delimiter(min, delim, max) => {
                    loop {
                        if self.inbuf.len() > min {
                            let opt = find_substr(&self.inbuf[min..], delim);
                            if let Some(num) = opt {
                                req = try!(req.0.bytes_read(
                                    &mut self.transport(),
                                    num, scope).ok_or(()));
                                continue 'outer;
                            }
                        }
                        if self.inbuf.len() > max {
                            return Err(());
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, req, scope));
                            }
                            IoOp::Eos => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                        }
                    }
                }
                Flush(num) => {
                    if self.outbuf.len() <= num {
                        req = try!(req.0.bytes_flushed(&mut self.transport(),
                            scope).ok_or(()));
                    } else {
                        return Ok(Stream::compose(self, req, scope));
                    }
                }
                Sleep => {
                    return Ok(Stream::compose(self, req, scope));
                }
            }
        }
    }
    fn action<C, M>(self, req: Request<M>, scope: &mut Scope<C>)
        -> Response<Stream<C, S, M>, Void>
        where M: Protocol<C, S>,
              S: StreamSocket
    {
        let old_timeout = self.timeout;
        match self._action(req, scope) {
            Ok(x) => Response::ok(x),
            Err(()) => {
                scope.clear_timeout(old_timeout);
                Response::done()
            }
        }
    }
    // Returns Ok(true) to if we have read something, does not loop for reading
    // because this might use whole memory, and we may parse and consume the
    // input instead of buffering it whole.
    fn read(&mut self) -> IoOp {
        match self.inbuf.read_from(&mut self.socket) {
            Ok(0) => IoOp::Eos,
            Ok(_) => IoOp::Done,
            Err(ref e) if e.kind() == BrokenPipe => IoOp::Eos,
            Err(ref e) if e.kind() == WouldBlock => IoOp::NoOp,
            Err(e) => IoOp::Error(e),
        }
    }
    fn write(&mut self) -> IoOp {
        loop {
            if self.outbuf.len() == 0 {
                return IoOp::Done;
            }
            match self.outbuf.write_to(&mut self.socket) {
                Ok(0) => return IoOp::Eos,
                Ok(_) => continue,
                Err(ref e) if e.kind() == BrokenPipe => return IoOp::Eos,
                Err(ref e) if e.kind() == WouldBlock => return IoOp::NoOp,
                Err(e) => return IoOp::Error(e),
            }
        }
    }
}

impl<C, S, P> Accepted<C, S> for Stream<C, S, P>
    where S: StreamSocket, P: Protocol<C, S, Seed=()>
{
    fn accepted(sock: S, scope: &mut Scope<C>) -> Result<Self, Box<Error>> {
        Self::new(sock, (), scope)
    }
}

impl<C, S: StreamSocket, P: Protocol<C, S>> Stream<C, S, P> {
    fn decompose(self) -> (P, Expectation, StreamImpl<S>) {
        (self.fsm, self.expectation, StreamImpl {
            socket: self.socket,
            deadline: self.deadline,
            timeout: self.timeout,
            inbuf: self.inbuf,
            outbuf: self.outbuf,
        })
    }
    fn compose(implem: StreamImpl<S>,
        (fsm, exp, dline): (P, Expectation, Deadline),
        scope: &mut Scope<C>)
        -> Stream<C, S, P>
    {
        let mut timeout = implem.timeout;
        if dline != implem.deadline {
            scope.clear_timeout(timeout);
            // Assuming that we can always add timeout since we have just
            // cancelled one. It may be not true if timer is already expired
            // or timeout is too far in future. But I'm not sure that killing
            // state machine here is much better idea than panicking.
            timeout = scope.timeout_ms(
                (dline - SteadyTime::now()).num_milliseconds() as u64)
                // TODO(tailhook) can we process the error somehow?
                .expect("Can't replace timer");
        }
        Stream {
            fsm: fsm,
            socket: implem.socket,
            expectation: exp,
            deadline: dline,
            timeout: timeout,
            inbuf: implem.inbuf,
            outbuf: implem.outbuf,
            phantom: PhantomData,
        }
    }
    pub fn new(mut sock: S, seed: P::Seed, scope: &mut Scope<C>)
        -> Result<Self, Box<Error>>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        try!(scope.register(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge()));
        match P::create(seed, &mut sock, scope) {
            None => return Err(Box::new(ProtocolStop)),
            Some((m, exp, dline)) => {
                let diff = dline - SteadyTime::now();
                let timeout = scope.timeout_ms(
                    diff.num_milliseconds() as u64)
                    // TODO(tailhook) propagate error carefully
                    .expect("Can't insert timer");
                Ok(Stream {
                    socket: sock,
                    expectation: exp,
                    deadline: dline,
                    timeout: timeout,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                    phantom: PhantomData,
                })
            }
        }
    }
}

impl<C, S: StreamSocket, P: Protocol<C, S>> Machine<C> for Stream<C, S, P> {
    type Seed = Void;
    fn create(void: Void, _scope: &mut Scope<C>)
        -> Result<Self, Box<Error>>
    {
        unreachable(void);
    }
    fn ready(self, _events: EventSet, scope: &mut Scope<C>)
        -> Response<Self, Self::Seed>
    {
        // TODO(tailhook) use `events` to optimize reading
        let (fsm, exp, imp) = self.decompose();
        let deadline = imp.deadline;
        imp.action(Some((fsm, exp, deadline)), scope)
    }
    fn spawned(self, _scope: &mut Scope<C>) -> Response<Self, Self::Seed> {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<C>) -> Response<Self, Self::Seed> {
        if Deadline::now() >= self.deadline {
            let (fsm, _exp, mut imp) = self.decompose();
            let res = fsm.timeout(&mut imp.transport(), scope);
            imp.action(res, scope)
        } else {
            // Spurious timeouts are possible for the couple of reasons
            Response::ok(self)
        }
    }
    fn wakeup(self, scope: &mut Scope<C>) -> Response<Self, Self::Seed> {
        let (fsm, _exp, mut imp) = self.decompose();
        let res = fsm.wakeup(&mut imp.transport(), scope);
        imp.action(res, scope)
    }
}

/// Protocol returned None right at the start of the stream processing
#[derive(Debug)]
pub struct ProtocolStop;

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

impl Error for ProtocolStop {
    fn cause(&self) -> Option<&Error> { None }
    fn description(&self) -> &'static str {
        r#"Protocol returned None (which means "stop") at start"#
    }
}

/// Can't insert timer, so can't create a connection
///
/// It's may be because there are too many timers in mio event loop or
/// because timer is too far away in the future (this is a limitation of
/// mio event loop too)
#[derive(Debug)]
pub struct TimerError;

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

impl Error for TimerError {
    fn cause(&self) -> Option<&Error> { None }
    fn description(&self) -> &'static str {
        "Can't insert timer, probably too much timers or time is too far away"
    }
}
<commit_msg>Revealed proper timer insertion error instead of panic<commit_after>use std::fmt;
use std::io;
use std::error::Error;
use std::marker::PhantomData;
use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero};

use time::SteadyTime;
use rotor::{Response, Scope, Machine};
use mio::{EventSet, PollOpt};
use netbuf::Buf;
use void::{Void, unreachable};

use substr::find_substr;
use {Expectation, Protocol, StreamSocket, Stream, StreamImpl, Request};
use {Transport, Deadline, Accepted, Exception};

#[derive(Debug)]
enum IoOp {
    Done,
    NoOp,
    Eos,
    Error(io::Error),
}

impl<S: StreamSocket> StreamImpl<S> {
    fn transport(&mut self) -> Transport<S> {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    fn _action<C, M>(mut self, req: Request<M>, scope: &mut Scope<C>)
        -> Result<Stream<C, S, M>, ()>
        where M: Protocol<C, S>,
              S: StreamSocket,
    {
        use Expectation::*;
        let mut req = try!(req.ok_or(()));
        let mut can_write = match self.write() {
            IoOp::Done => true,
            IoOp::NoOp => false,
            IoOp::Eos => {
                req = try!(req.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(io::Error::new(
                        WriteZero, "failed to write whole buffer")),
                    scope).ok_or(()));
                self.outbuf.remove_range(..);
                false
            }
            IoOp::Error(e) => {
                req = try!(req.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(e),
                    scope).ok_or(()));
                // TODO(tailhook) should we flush buffer here too?
                false
            }
        };
        'outer: loop {
            if can_write {
                can_write = match self.write() {
                    IoOp::Done => true,
                    IoOp::NoOp => false,
                    IoOp::Eos => {
                        req = try!(req.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(io::Error::new(
                                WriteZero, "failed to write whole buffer")),
                            scope).ok_or(()));
                        self.outbuf.remove_range(..);
                        false
                    }
                    IoOp::Error(e) => {
                        req = try!(req.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(e),
                            scope).ok_or(()));
                        // TODO(tailhook) should we flush buffer here too?
                        false
                    }
                };
            }
            match req.1 {
                Bytes(num) => {
                    loop {
                        if self.inbuf.len() >= num {
                            req = try!(req.0.bytes_read(&mut self.transport(),
                                num, scope).ok_or(()));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, req, scope));
                            }
                            IoOp::Eos => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                        }
                    }
                }
                Delimiter(min, delim, max) => {
                    loop {
                        if self.inbuf.len() > min {
                            let opt = find_substr(&self.inbuf[min..], delim);
                            if let Some(num) = opt {
                                req = try!(req.0.bytes_read(
                                    &mut self.transport(),
                                    num, scope).ok_or(()));
                                continue 'outer;
                            }
                        }
                        if self.inbuf.len() > max {
                            return Err(());
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, req, scope));
                            }
                            IoOp::Eos => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                req = try!(req.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope).ok_or(()));
                                continue 'outer;
                            }
                        }
                    }
                }
                Flush(num) => {
                    if self.outbuf.len() <= num {
                        req = try!(req.0.bytes_flushed(&mut self.transport(),
                            scope).ok_or(()));
                    } else {
                        return Ok(Stream::compose(self, req, scope));
                    }
                }
                Sleep => {
                    return Ok(Stream::compose(self, req, scope));
                }
            }
        }
    }
    fn action<C, M>(self, req: Request<M>, scope: &mut Scope<C>)
        -> Response<Stream<C, S, M>, Void>
        where M: Protocol<C, S>,
              S: StreamSocket
    {
        let old_timeout = self.timeout;
        match self._action(req, scope) {
            Ok(x) => Response::ok(x),
            Err(()) => {
                scope.clear_timeout(old_timeout);
                Response::done()
            }
        }
    }
    // Returns Ok(true) to if we have read something, does not loop for reading
    // because this might use whole memory, and we may parse and consume the
    // input instead of buffering it whole.
    fn read(&mut self) -> IoOp {
        match self.inbuf.read_from(&mut self.socket) {
            Ok(0) => IoOp::Eos,
            Ok(_) => IoOp::Done,
            Err(ref e) if e.kind() == BrokenPipe => IoOp::Eos,
            Err(ref e) if e.kind() == WouldBlock => IoOp::NoOp,
            Err(e) => IoOp::Error(e),
        }
    }
    fn write(&mut self) -> IoOp {
        loop {
            if self.outbuf.len() == 0 {
                return IoOp::Done;
            }
            match self.outbuf.write_to(&mut self.socket) {
                Ok(0) => return IoOp::Eos,
                Ok(_) => continue,
                Err(ref e) if e.kind() == BrokenPipe => return IoOp::Eos,
                Err(ref e) if e.kind() == WouldBlock => return IoOp::NoOp,
                Err(e) => return IoOp::Error(e),
            }
        }
    }
}

impl<C, S, P> Accepted<C, S> for Stream<C, S, P>
    where S: StreamSocket, P: Protocol<C, S, Seed=()>
{
    fn accepted(sock: S, scope: &mut Scope<C>) -> Result<Self, Box<Error>> {
        Self::new(sock, (), scope)
    }
}

impl<C, S: StreamSocket, P: Protocol<C, S>> Stream<C, S, P> {
    fn decompose(self) -> (P, Expectation, StreamImpl<S>) {
        (self.fsm, self.expectation, StreamImpl {
            socket: self.socket,
            deadline: self.deadline,
            timeout: self.timeout,
            inbuf: self.inbuf,
            outbuf: self.outbuf,
        })
    }
    fn compose(implem: StreamImpl<S>,
        (fsm, exp, dline): (P, Expectation, Deadline),
        scope: &mut Scope<C>)
        -> Stream<C, S, P>
    {
        let mut timeout = implem.timeout;
        if dline != implem.deadline {
            scope.clear_timeout(timeout);
            // Assuming that we can always add timeout since we have just
            // cancelled one. It may be not true if timer is already expired
            // or timeout is too far in future. But I'm not sure that killing
            // state machine here is much better idea than panicking.
            timeout = scope.timeout_ms(
                (dline - SteadyTime::now()).num_milliseconds() as u64)
                // TODO(tailhook) can we process the error somehow?
                .expect("Can't replace timer");
        }
        Stream {
            fsm: fsm,
            socket: implem.socket,
            expectation: exp,
            deadline: dline,
            timeout: timeout,
            inbuf: implem.inbuf,
            outbuf: implem.outbuf,
            phantom: PhantomData,
        }
    }
    pub fn new(mut sock: S, seed: P::Seed, scope: &mut Scope<C>)
        -> Result<Self, Box<Error>>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        try!(scope.register(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge()));
        match P::create(seed, &mut sock, scope) {
            None => return Err(Box::new(ProtocolStop)),
            Some((m, exp, dline)) => {
                let diff = dline - SteadyTime::now();
                let timeout = try!(scope.timeout_ms(
                    diff.num_milliseconds() as u64)
                    .map_err(|_| TimerError));
                Ok(Stream {
                    socket: sock,
                    expectation: exp,
                    deadline: dline,
                    timeout: timeout,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                    phantom: PhantomData,
                })
            }
        }
    }
}

impl<C, S: StreamSocket, P: Protocol<C, S>> Machine<C> for Stream<C, S, P> {
    type Seed = Void;
    fn create(void: Void, _scope: &mut Scope<C>)
        -> Result<Self, Box<Error>>
    {
        unreachable(void);
    }
    fn ready(self, _events: EventSet, scope: &mut Scope<C>)
        -> Response<Self, Self::Seed>
    {
        // TODO(tailhook) use `events` to optimize reading
        let (fsm, exp, imp) = self.decompose();
        let deadline = imp.deadline;
        imp.action(Some((fsm, exp, deadline)), scope)
    }
    fn spawned(self, _scope: &mut Scope<C>) -> Response<Self, Self::Seed> {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<C>) -> Response<Self, Self::Seed> {
        if Deadline::now() >= self.deadline {
            let (fsm, _exp, mut imp) = self.decompose();
            let res = fsm.timeout(&mut imp.transport(), scope);
            imp.action(res, scope)
        } else {
            // Spurious timeouts are possible for the couple of reasons
            Response::ok(self)
        }
    }
    fn wakeup(self, scope: &mut Scope<C>) -> Response<Self, Self::Seed> {
        let (fsm, _exp, mut imp) = self.decompose();
        let res = fsm.wakeup(&mut imp.transport(), scope);
        imp.action(res, scope)
    }
}

/// Protocol returned None right at the start of the stream processing
#[derive(Debug)]
pub struct ProtocolStop;

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

impl Error for ProtocolStop {
    fn cause(&self) -> Option<&Error> { None }
    fn description(&self) -> &'static str {
        r#"Protocol returned None (which means "stop") at start"#
    }
}

/// Can't insert timer, so can't create a connection
///
/// It's may be because there are too many timers in mio event loop or
/// because timer is too far away in the future (this is a limitation of
/// mio event loop too)
#[derive(Debug)]
pub struct TimerError;

impl fmt::Display for TimerError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "error inserting timer")
    }
}

impl Error for TimerError {
    fn cause(&self) -> Option<&Error> { None }
    fn description(&self) -> &'static str {
        "Can't insert timer, probably too much timers or time is too far away"
    }
}
<|endoftext|>


<commit_before>use scroll::ctx::TryFromCtx;

use crate::common::*;
use crate::tpi::constants::*;

#[inline]
fn parse_optional_id_index<'t>(buf: &mut ParseBuffer<'t>) -> Result<Option<IdIndex>> {
    Ok(match buf.parse()? {
        IdIndex(0) => None,
        index => Some(index),
    })
}

#[inline]
fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>> {
    if leaf > LF_ST_MAX {
        buf.parse_cstring()
    } else {
        buf.parse_u8_pascal_string()
    }
}

/// Encapsulates parsed data about an `Id`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IdData<'t> {
    /// Global function, usually inlined.
    Function(FunctionId<'t>),
    /// Member function, usually inlined.
    MemberFunction(MemberFunctionId<'t>),
    /// Tool, version and command line build information.
    BuildInfo(BuildInfoId),
    /// A list of substrings.
    StringList(StringListId),
    /// A string.
    String(StringId<'t>),
    /// Source and line of the definition of a User Defined Type (UDT).
    UserDefinedTypeSource(UserDefinedTypeSourceId),
}

impl<'t> IdData<'t> {}

impl<'t> TryFromCtx<'t, scroll::Endian> for IdData<'t> {
    type Error = Error;

    fn try_from_ctx(this: &'t [u8], _ctx: scroll::Endian) -> Result<(Self, usize)> {
        let mut buf = ParseBuffer::from(this);
        let leaf = buf.parse_u16()?;

        let data = match leaf {
            LF_FUNC_ID => IdData::Function(FunctionId {
                scope: parse_optional_id_index(&mut buf)?,
                function_type: buf.parse()?,
                name: parse_string(leaf, &mut buf)?,
            }),
            LF_MFUNC_ID => IdData::MemberFunction(MemberFunctionId {
                parent: buf.parse()?,
                function_type: buf.parse()?,
                name: parse_string(leaf, &mut buf)?,
            }),
            LF_BUILDINFO => IdData::BuildInfo({
                let count = buf.parse::<u16>()?;
                let mut arguments = Vec::with_capacity(count as usize);
                for _ in 0..count {
                    arguments.push(buf.parse()?);
                }
                BuildInfoId { arguments }
            }),
            LF_SUBSTR_LIST => IdData::StringList({
                let count = buf.parse::<u32>()?;
                let mut substrings = Vec::with_capacity(count as usize);
                for _ in 0..count {
                    substrings.push(buf.parse()?);
                }
                StringListId { substrings }
            }),
            LF_STRING_ID => IdData::String(StringId {
                substrings: parse_optional_id_index(&mut buf)?,
                name: parse_string(leaf, &mut buf)?,
            }),
            LF_UDT_SRC_LINE | LF_UDT_MOD_SRC_LINE => {
                let mut udt = UserDefinedTypeSourceId {
                    udt: buf.parse()?,
                    source_file: buf.parse()?,
                    line: buf.parse()?,
                    module: None,
                };

                if leaf == LF_UDT_MOD_SRC_LINE {
                    udt.module = Some(buf.parse()?);
                }

                IdData::UserDefinedTypeSource(udt)
            }
            _ => return Err(Error::UnimplementedTypeKind(leaf)),
        };

        Ok((data, buf.pos()))
    }
}

/// Global function, usually inlined.
///
/// This Id is usually referenced by [`InlineSiteSymbol`](crate::InlineSiteSymbol).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionId<'t> {
    /// Parent scope of this id.
    pub scope: Option<IdIndex>,
    /// Index of the function type declaration.
    pub function_type: TypeIndex,
    /// Name of the function.
    pub name: RawString<'t>,
}

/// Member function, usually inlined.
///
/// This Id is usually referenced by [`InlineSiteSymbol`](crate::InlineSiteSymbol).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MemberFunctionId<'t> {
    /// Index of the parent type.
    pub parent: TypeIndex,
    /// Index of the member function type declaration.
    pub function_type: TypeIndex,
    /// Name of the member function.
    pub name: RawString<'t>,
}

/// Tool, version and command line build information.
///
/// This Id is usually referenced by [`BuildInfoSymbol`](crate::BuildInfoSymbol).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BuildInfoId {
    /// Indexes of build arguments.
    pub arguments: Vec<IdIndex>,
}

/// A list of substrings.
///
/// This Id is usually referenced by [`StringId`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringListId {
    /// The list of substrings.
    pub substrings: Vec<TypeIndex>,
}

/// A string.
///
/// This Id is usually referenced by [`FunctionId`] and contains the full namespace of a function.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringId<'t> {
    /// Index of the list of substrings.
    pub substrings: Option<IdIndex>,
    /// The string.
    pub name: RawString<'t>,
}

/// Source and line of the definition of a User Defined Type (UDT).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UserDefinedTypeSourceId {
    /// Index of the UDT's type definition.
    pub udt: TypeIndex,
    /// Index of the source file name.
    pub source_file: IdIndex,
    /// Line number in the source file.
    pub line: u32,
    /// Module that contributes this UDT definition.
    ///
    /// If None, the UDT is declared in the same module.
    pub module: Option<u16>,
}
<commit_msg>Fix UDT source reference parsing<commit_after>use scroll::ctx::TryFromCtx;

use crate::common::*;
use crate::tpi::constants::*;

#[inline]
fn parse_optional_id_index<'t>(buf: &mut ParseBuffer<'t>) -> Result<Option<IdIndex>> {
    Ok(match buf.parse()? {
        IdIndex(0) => None,
        index => Some(index),
    })
}

#[inline]
fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>> {
    if leaf > LF_ST_MAX {
        buf.parse_cstring()
    } else {
        buf.parse_u8_pascal_string()
    }
}

/// Encapsulates parsed data about an `Id`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IdData<'t> {
    /// Global function, usually inlined.
    Function(FunctionId<'t>),
    /// Member function, usually inlined.
    MemberFunction(MemberFunctionId<'t>),
    /// Tool, version and command line build information.
    BuildInfo(BuildInfoId),
    /// A list of substrings.
    StringList(StringListId),
    /// A string.
    String(StringId<'t>),
    /// Source and line of the definition of a User Defined Type (UDT).
    UserDefinedTypeSource(UserDefinedTypeSourceId),
}

impl<'t> IdData<'t> {}

impl<'t> TryFromCtx<'t, scroll::Endian> for IdData<'t> {
    type Error = Error;

    fn try_from_ctx(this: &'t [u8], _ctx: scroll::Endian) -> Result<(Self, usize)> {
        let mut buf = ParseBuffer::from(this);
        let leaf = buf.parse_u16()?;

        let data = match leaf {
            LF_FUNC_ID => IdData::Function(FunctionId {
                scope: parse_optional_id_index(&mut buf)?,
                function_type: buf.parse()?,
                name: parse_string(leaf, &mut buf)?,
            }),
            LF_MFUNC_ID => IdData::MemberFunction(MemberFunctionId {
                parent: buf.parse()?,
                function_type: buf.parse()?,
                name: parse_string(leaf, &mut buf)?,
            }),
            LF_BUILDINFO => IdData::BuildInfo({
                let count = buf.parse::<u16>()?;
                let mut arguments = Vec::with_capacity(count as usize);
                for _ in 0..count {
                    arguments.push(buf.parse()?);
                }
                BuildInfoId { arguments }
            }),
            LF_SUBSTR_LIST => IdData::StringList({
                let count = buf.parse::<u32>()?;
                let mut substrings = Vec::with_capacity(count as usize);
                for _ in 0..count {
                    substrings.push(buf.parse()?);
                }
                StringListId { substrings }
            }),
            LF_STRING_ID => IdData::String(StringId {
                substrings: parse_optional_id_index(&mut buf)?,
                name: parse_string(leaf, &mut buf)?,
            }),
            LF_UDT_SRC_LINE | LF_UDT_MOD_SRC_LINE => {
                let udt = buf.parse()?;
                let file_id = buf.parse()?;
                let line = buf.parse()?;

                let source_file = if leaf == self::LF_UDT_SRC_LINE {
                    UserDefinedTypeSourceFileRef::Local(IdIndex(file_id))
                } else {
                    UserDefinedTypeSourceFileRef::Remote(buf.parse()?, StringRef(file_id))
                };

                IdData::UserDefinedTypeSource(UserDefinedTypeSourceId {
                    udt,
                    source_file,
                    line,
                })
            }
            _ => return Err(Error::UnimplementedTypeKind(leaf)),
        };

        Ok((data, buf.pos()))
    }
}

/// Global function, usually inlined.
///
/// This Id is usually referenced by [`InlineSiteSymbol`](crate::InlineSiteSymbol).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionId<'t> {
    /// Parent scope of this id.
    pub scope: Option<IdIndex>,
    /// Index of the function type declaration.
    pub function_type: TypeIndex,
    /// Name of the function.
    pub name: RawString<'t>,
}

/// Member function, usually inlined.
///
/// This Id is usually referenced by [`InlineSiteSymbol`](crate::InlineSiteSymbol).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MemberFunctionId<'t> {
    /// Index of the parent type.
    pub parent: TypeIndex,
    /// Index of the member function type declaration.
    pub function_type: TypeIndex,
    /// Name of the member function.
    pub name: RawString<'t>,
}

/// Tool, version and command line build information.
///
/// This Id is usually referenced by [`BuildInfoSymbol`](crate::BuildInfoSymbol).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BuildInfoId {
    /// Indexes of build arguments.
    pub arguments: Vec<IdIndex>,
}

/// A list of substrings.
///
/// This Id is usually referenced by [`StringId`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringListId {
    /// The list of substrings.
    pub substrings: Vec<TypeIndex>,
}

/// A string.
///
/// This Id is usually referenced by [`FunctionId`] and contains the full namespace of a function.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringId<'t> {
    /// Index of the list of substrings.
    pub substrings: Option<IdIndex>,
    /// The string.
    pub name: RawString<'t>,
}

/// A reference to the source file name of a [`UserDefinedTypeSourceId`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UserDefinedTypeSourceFileRef {
    /// Index of the source file name in the [`IdInformation`](crate::IdInformation) of the same module.
    ///
    /// The index should resolve to a [`IdData::String`].
    Local(IdIndex),
    /// Reference into the [`StringTable`](crate::StringTable) of another module that contributes
    /// this UDT definition.
    ///
    /// Use [`DebugInformation::modules`](crate::DebugInformation::modules) to resolve the
    /// corresponding module.
    Remote(u16, StringRef),
}

/// Source and line of the definition of a User Defined Type (UDT).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UserDefinedTypeSourceId {
    /// Index of the UDT's type definition.
    pub udt: TypeIndex,
    /// Reference to the source file name.
    pub source_file: UserDefinedTypeSourceFileRef,
    /// Line number in the source file.
    pub line: u32,
}
<|endoftext|>


<commit_before>use std::{mem, ptr};
use std::c_str::{CString, ToCStr};
use libc::{c_char, c_void, c_int, size_t, pid_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC, F_SETFD, F_SETFL};
use errno::{SysResult, SysError, from_ffi};

#[cfg(target_os = "linux")]
pub use self::linux::*;

mod ffi {
    use libc::{c_char, c_int, size_t};
    pub use libc::{close, read, write, pipe};
    pub use libc::funcs::posix88::unistd::fork;

    extern {
        // duplicate a file descriptor
        // doc: http://man7.org/linux/man-pages/man2/dup.2.html
        pub fn dup(oldfd: c_int) -> c_int;
        pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;

        // TODO: dup3 is only available in newer linux kernels and possibly a few *bsds
        // pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int;

        // change working directory
        // doc: http://man7.org/linux/man-pages/man2/chdir.2.html
        pub fn chdir(path: *const c_char) -> c_int;

        // execute program
        // doc: http://man7.org/linux/man-pages/man2/execve.2.html
        pub fn execve(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int;

        // run the current process in the background
        // doc: http://man7.org/linux/man-pages/man3/daemon.3.html
        pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int;

        // sets the hostname to the value given
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn gethostname(name: *mut c_char, len: size_t) -> c_int;

        // gets the hostname
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn sethostname(name: *const c_char, len: size_t) -> c_int;
    }
}

pub enum Fork {
    Parent(pid_t),
    Child
}

impl Fork {
    pub fn is_child(&self) -> bool {
        match *self {
            Child => true,
            _ => false
        }
    }

    pub fn is_parent(&self) -> bool {
        match *self {
            Parent(_) => true,
            _ => false
        }
    }
}

pub fn fork() -> SysResult<Fork> {
    let res = unsafe { ffi::fork() };

    if res < 0 {
        return Err(SysError::last());
    } else if res == 0 {
        Ok(Child)
    } else {
        Ok(Parent(res))
    }
}

#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup(oldfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup2(oldfd, newfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

/*
Same TODO as above
#[inline]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    let res = unsafe { ffi::dup3(oldfd, newfd, flags.bits()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}
*/

#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {
    let path = path.to_c_str();
    let res = unsafe { ffi::chdir(path.as_ptr()) };

    if res != 0 {
        return Err(SysError::last());
    }

    return Ok(())
}

#[inline]
pub fn execve(filename: CString, args: &[CString], env: &[CString]) -> SysResult<()> {
    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());

    let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
    env_p.push(ptr::null());

    let res = unsafe {
        ffi::execve(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    if res != 0 {
        return Err(SysError::last());
    }

    // Should never reach here
    Ok(())
}

pub fn daemon(nochdir: bool, noclose: bool) -> SysResult<()> {
    let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) };
    from_ffi(res)
}

pub fn sethostname(name: &[u8]) -> SysResult<()> {
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::sethostname(ptr, len) };
    from_ffi(res)
}

pub fn gethostname(name: &mut [u8]) -> SysResult<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::gethostname(ptr, len) };
    from_ffi(res)
}

pub fn close(fd: Fd) -> SysResult<()> {
    let res = unsafe { ffi::close(fd) };
    from_ffi(res)
}

pub fn read(fd: Fd, buf: &mut [u8]) -> SysResult<uint> {
    let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<uint> {
    let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn pipe() -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "linux")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    type F = unsafe extern "C" fn(fds: *mut c_int, flags: c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static pipe2: *const ();
    }

    let feat_atomic = !pipe2.is_null();

    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        if feat_atomic {
            res = mem::transmute::<*const (), F>(pipe2)(
                fds.as_mut_ptr(), flags.bits());
        } else {
            res = ffi::pipe(fds.as_mut_ptr());
        }

        if res < 0 {
            return Err(SysError::last());
        }

        if !feat_atomic {
            try!(pipe2_setflags(fds[0], fds[1], flags));
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> {
    let mut res = Ok(());

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

#[cfg(target_os = "linux")]
mod linux {
    use std::path::Path;
    use syscall::{syscall, SysPivotRoot};
    use errno::{SysResult, SysError};

    pub fn pivot_root(new_root: &Path, put_old: &Path) -> SysResult<()> {
        let new_root = new_root.to_c_str();
        let put_old = put_old.to_c_str();

        let res = unsafe {
            syscall(SysPivotRoot, new_root.as_ptr(), put_old.as_ptr())
        };

        if res != 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}
<commit_msg>execve should take a ref to a CString<commit_after>use std::{mem, ptr};
use std::c_str::{CString, ToCStr};
use libc::{c_char, c_void, c_int, size_t, pid_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC, F_SETFD, F_SETFL};
use errno::{SysResult, SysError, from_ffi};

#[cfg(target_os = "linux")]
pub use self::linux::*;

mod ffi {
    use libc::{c_char, c_int, size_t};
    pub use libc::{close, read, write, pipe};
    pub use libc::funcs::posix88::unistd::fork;

    extern {
        // duplicate a file descriptor
        // doc: http://man7.org/linux/man-pages/man2/dup.2.html
        pub fn dup(oldfd: c_int) -> c_int;
        pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;

        // TODO: dup3 is only available in newer linux kernels and possibly a few *bsds
        // pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int;

        // change working directory
        // doc: http://man7.org/linux/man-pages/man2/chdir.2.html
        pub fn chdir(path: *const c_char) -> c_int;

        // execute program
        // doc: http://man7.org/linux/man-pages/man2/execve.2.html
        pub fn execve(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int;

        // run the current process in the background
        // doc: http://man7.org/linux/man-pages/man3/daemon.3.html
        pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int;

        // sets the hostname to the value given
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn gethostname(name: *mut c_char, len: size_t) -> c_int;

        // gets the hostname
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn sethostname(name: *const c_char, len: size_t) -> c_int;
    }
}

pub enum Fork {
    Parent(pid_t),
    Child
}

impl Fork {
    pub fn is_child(&self) -> bool {
        match *self {
            Child => true,
            _ => false
        }
    }

    pub fn is_parent(&self) -> bool {
        match *self {
            Parent(_) => true,
            _ => false
        }
    }
}

pub fn fork() -> SysResult<Fork> {
    let res = unsafe { ffi::fork() };

    if res < 0 {
        return Err(SysError::last());
    } else if res == 0 {
        Ok(Child)
    } else {
        Ok(Parent(res))
    }
}

#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup(oldfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup2(oldfd, newfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

/*
Same TODO as above
#[inline]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    let res = unsafe { ffi::dup3(oldfd, newfd, flags.bits()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}
*/

#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {
    let path = path.to_c_str();
    let res = unsafe { ffi::chdir(path.as_ptr()) };

    if res != 0 {
        return Err(SysError::last());
    }

    return Ok(())
}

#[inline]
pub fn execve(filename: &CString, args: &[CString], env: &[CString]) -> SysResult<()> {
    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());

    let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
    env_p.push(ptr::null());

    let res = unsafe {
        ffi::execve(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    if res != 0 {
        return Err(SysError::last());
    }

    unreachable!()
}

pub fn daemon(nochdir: bool, noclose: bool) -> SysResult<()> {
    let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) };
    from_ffi(res)
}

pub fn sethostname(name: &[u8]) -> SysResult<()> {
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::sethostname(ptr, len) };
    from_ffi(res)
}

pub fn gethostname(name: &mut [u8]) -> SysResult<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::gethostname(ptr, len) };
    from_ffi(res)
}

pub fn close(fd: Fd) -> SysResult<()> {
    let res = unsafe { ffi::close(fd) };
    from_ffi(res)
}

pub fn read(fd: Fd, buf: &mut [u8]) -> SysResult<uint> {
    let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<uint> {
    let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn pipe() -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "linux")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    type F = unsafe extern "C" fn(fds: *mut c_int, flags: c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static pipe2: *const ();
    }

    let feat_atomic = !pipe2.is_null();

    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        if feat_atomic {
            res = mem::transmute::<*const (), F>(pipe2)(
                fds.as_mut_ptr(), flags.bits());
        } else {
            res = ffi::pipe(fds.as_mut_ptr());
        }

        if res < 0 {
            return Err(SysError::last());
        }

        if !feat_atomic {
            try!(pipe2_setflags(fds[0], fds[1], flags));
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> {
    let mut res = Ok(());

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

#[cfg(target_os = "linux")]
mod linux {
    use std::path::Path;
    use syscall::{syscall, SysPivotRoot};
    use errno::{SysResult, SysError};

    pub fn pivot_root(new_root: &Path, put_old: &Path) -> SysResult<()> {
        let new_root = new_root.to_c_str();
        let put_old = put_old.to_c_str();

        let res = unsafe {
            syscall(SysPivotRoot, new_root.as_ptr(), put_old.as_ptr())
        };

        if res != 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::intrinsics::TypeId;

use GenericEvent;
use ptr::Ptr;

/// Update argument.
#[deriving(Clone, PartialEq, Show)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Implemented by event structures that supports update event.
pub trait UpdateEvent {
    /// Creates an update event.
    fn from_update_args(args: &UpdateArgs) -> Option<Self>;
    /// Creates an update event with delta time.
    #[inline(always)]
    fn from_dt(dt: f64) -> Option<Self> {
        UpdateEvent::from_update_args(&UpdateArgs { dt: dt })
    }
    /// Calls closure if this is an update event.
    fn update<U>(&self, f: |&UpdateArgs| -> U) -> Option<U>;
}

impl<T: GenericEvent> UpdateEvent for T {
    #[inline(always)]
    fn from_update_args(args: &UpdateArgs) -> Option<T> {
        let id = TypeId::of::<Box<UpdateEvent>>();
        Ptr::with_ref::<UpdateArgs, Option<T>>(args, |ptr| {
            GenericEvent::from_event(id, ptr)
        })
    }

    #[inline(always)]
    fn update<U>(&self, f: |&UpdateArgs| -> U) -> Option<U> {
        let id = TypeId::of::<Box<UpdateEvent>>();
        self.with_event(id, |ptr| {
            f(ptr.expect::<UpdateArgs>())
        })
    }
}
<commit_msg>Move from_dt in update.rs to <T: GenericEvent> implementation<commit_after>use std::intrinsics::TypeId;

use GenericEvent;
use ptr::Ptr;

/// Update argument.
#[deriving(Clone, PartialEq, Show)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Implemented by event structures that supports update event.
pub trait UpdateEvent {
    /// Creates an update event.
    fn from_update_args(args: &UpdateArgs) -> Option<Self>;
    /// Creates an update event with delta time.
    fn from_dt(dt: f64) -> Option<Self>;
    /// Calls closure if this is an update event.
    fn update<U>(&self, f: |&UpdateArgs| -> U) -> Option<U>;
}

impl<T: GenericEvent> UpdateEvent for T {
    #[inline(always)]
    fn from_update_args(args: &UpdateArgs) -> Option<T> {
        let id = TypeId::of::<Box<UpdateEvent>>();
        Ptr::with_ref::<UpdateArgs, Option<T>>(args, |ptr| {
            GenericEvent::from_event(id, ptr)
        })
    }

    #[inline(always)]
    fn from_dt(dt: f64) -> Option<T> {
        UpdateEvent::from_update_args(&UpdateArgs { dt: dt })
    }

    #[inline(always)]
    fn update<U>(&self, f: |&UpdateArgs| -> U) -> Option<U> {
        let id = TypeId::of::<Box<UpdateEvent>>();
        self.with_event(id, |ptr| {
            f(ptr.expect::<UpdateArgs>())
        })
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016-2017 Ivan Dejanovic
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::io::stdin;
use std::collections::HashMap;
use std::mem::transmute;

use common::INSTRUCTIONS;

// Bit Masks
const INST_MASK: u64 = 0xFF;

// Opcodes
const HALT: u64 = 0x00;
const IN_N: u64 = 0x01;
const OUT_N: u64 = 0x02;
const IN_S: u64 = 0x03;
const OUT_S: u64 = 0x04;
const ADD: u64 = 0x05;
const SUB: u64 = 0x06;
const MUL: u64 = 0x07;
const DIV: u64 = 0x08;
const CON: u64 = 0x09;
const PUSH: u64 = 0x0A;
const POP: u64 = 0x0B;
const LD: u64 = 0x0C;
const ST: u64 = 0x0D;
const JMP: u64 = 0x0E;
const JGR: u64 = 0x0F;
const JGE: u64 = 0x10;
const JEQ: u64 = 0x11;
const JNE: u64 = 0x12;
const JLE: u64 = 0x13;
const JLS: u64 = 0x14;

const REG_NUM: usize = 8;
const INS_MEM_CAP: usize = 50000;

pub struct Vm {
    ip: usize,
    sp: usize,
    acc: u64,
    reg: [u64; REG_NUM],
    ins_mem: [u64; INS_MEM_CAP],
}

impl Vm {
    pub fn new() -> Box<Vm> {
        Box::new(Vm {
                     ip: 0,
                     sp: 0,
                     acc: 0,
                     reg: [0; REG_NUM],
                     ins_mem: [0; INS_MEM_CAP],
                 })
    }

    pub fn load_code(&mut self, code: Vec<String>) {
        println!("{}", code.len());

        let mut opcode_map: HashMap<&'static str, u64> = HashMap::new();

        opcode_map.insert(INSTRUCTIONS.halt, HALT);
        opcode_map.insert(INSTRUCTIONS.in_n, IN_N);
        opcode_map.insert(INSTRUCTIONS.out_n, OUT_N);
        opcode_map.insert(INSTRUCTIONS.in_s, IN_S);
        opcode_map.insert(INSTRUCTIONS.out_s, OUT_S);
        opcode_map.insert(INSTRUCTIONS.add, ADD);
        opcode_map.insert(INSTRUCTIONS.sub, SUB);
        opcode_map.insert(INSTRUCTIONS.mul, MUL);
        opcode_map.insert(INSTRUCTIONS.div, DIV);
        opcode_map.insert(INSTRUCTIONS.con, CON);
        opcode_map.insert(INSTRUCTIONS.push, PUSH);
        opcode_map.insert(INSTRUCTIONS.pop, POP);
        opcode_map.insert(INSTRUCTIONS.ld, LD);
        opcode_map.insert(INSTRUCTIONS.st, ST);
        opcode_map.insert(INSTRUCTIONS.jmp, JMP);
        opcode_map.insert(INSTRUCTIONS.jgr, JGR);
        opcode_map.insert(INSTRUCTIONS.jge, JGE);
        opcode_map.insert(INSTRUCTIONS.jeq, JEQ);
        opcode_map.insert(INSTRUCTIONS.jne, JNE);
        opcode_map.insert(INSTRUCTIONS.jle, JLE);
        opcode_map.insert(INSTRUCTIONS.jls, JLS);

        for instruction in code {
            println!("{}", instruction);
        }
    }

    pub fn execute(&mut self) {
        loop {
            let inst = self.ins_mem[self.ip];
            let opcode = inst.rotate_left(8) & INST_MASK;

            match opcode {
                HALT => break,
                IN_N => self.process_in_n(),
                OUT_N => self.process_out_n(),
                IN_S => self.process_in_s(),
                OUT_S => self.process_out_s(),
                ADD => self.process_add(),
                SUB => self.process_sub(),
                MUL => self.process_mul(),
                DIV => self.process_div(),
                CON => self.process_con(),
                PUSH => self.process_push(),
                POP => self.process_pop(),
                LD => self.process_ld(),
                ST => self.process_st(),
                JMP => self.process_jmp(),
                JGR => self.process_jgr(),
                JGE => self.process_jge(),
                JEQ => self.process_jeq(),
                JNE => self.process_jne(),
                JLE => self.process_jle(),
                JLS => self.process_jls(),
                _ => {
                    println!("Unknow instruction. Aborting.");
                    break;
                }

            }

            if self.has_errors() {
                self.throw_exception();
                break;
            }
        }
    }

    fn process_in_n(&mut self) {
        let mut input_text = String::new();
        stdin().read_line(&mut input_text).expect("failed to read from stdin");

        let trimmed = input_text.trim();
        match trimmed.parse::<f64>() {
            Ok(i) => {
                self.acc = unsafe { transmute::<f64, u64>(i) };
                self.ip = self.ip + 1;
            }
            Err(..) => self.set_io_error_flag(),
        };
    }

    fn process_out_n(&mut self) {
        let output = unsafe { transmute::<u64, f64>(self.acc) };
        println!("{}", output)
    }

    fn process_in_s(&mut self) {}

    fn process_out_s(&mut self) {}

    fn process_add(&mut self) {}

    fn process_sub(&mut self) {}

    fn process_mul(&mut self) {}

    fn process_div(&mut self) {}

    fn process_con(&mut self) {}

    fn process_push(&mut self) {}

    fn process_pop(&mut self) {}

    fn process_ld(&mut self) {}

    fn process_st(&mut self) {}

    fn process_jmp(&mut self) {}

    fn process_jgr(&mut self) {}

    fn process_jge(&mut self) {}

    fn process_jeq(&mut self) {}

    fn process_jne(&mut self) {}

    fn process_jle(&mut self) {}

    fn process_jls(&mut self) {}

    fn set_io_error_flag(&mut self) {
        println!("IO error flag set!")
    }

    fn has_errors(&mut self) -> bool {
        false
    }

    fn throw_exception(&mut self) {
        println!("Exception thrown!")
    }
}
<commit_msg>VM improvement.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016-2017 Ivan Dejanovic
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::io::stdin;
use std::collections::HashMap;
use std::mem::transmute;

use common::INSTRUCTIONS;

// Bit Masks
const INST_MASK: u64 = 0xFF;
const REG_MASK: u64 = 0xF;

// Opcodes
const HALT: u64 = 0x00;
const IN_N: u64 = 0x01;
const OUT_N: u64 = 0x02;
const IN_S: u64 = 0x03;
const OUT_S: u64 = 0x04;
const ADD: u64 = 0x05;
const SUB: u64 = 0x06;
const MUL: u64 = 0x07;
const DIV: u64 = 0x08;
const CON: u64 = 0x09;
const PUSH: u64 = 0x0A;
const POP: u64 = 0x0B;
const LD: u64 = 0x0C;
const ST: u64 = 0x0D;
const JMP: u64 = 0x0E;
const JGR: u64 = 0x0F;
const JGE: u64 = 0x10;
const JEQ: u64 = 0x11;
const JNE: u64 = 0x12;
const JLE: u64 = 0x13;
const JLS: u64 = 0x14;

const REG_NUM: usize = 8;
const INS_MEM_CAP: usize = 50000;

pub struct Vm {
    ip: usize,
    sp: usize,
    acc: u64,
    reg: [u64; REG_NUM],
    ins_mem: [u64; INS_MEM_CAP],
}

impl Vm {
    pub fn new() -> Box<Vm> {
        Box::new(Vm {
                     ip: 0,
                     sp: 0,
                     acc: 0,
                     reg: [0; REG_NUM],
                     ins_mem: [0; INS_MEM_CAP],
                 })
    }

    pub fn load_code(&mut self, code: Vec<String>) {
        println!("{}", code.len());

        let mut opcode_map: HashMap<&'static str, u64> = HashMap::new();

        opcode_map.insert(INSTRUCTIONS.halt, HALT);
        opcode_map.insert(INSTRUCTIONS.in_n, IN_N);
        opcode_map.insert(INSTRUCTIONS.out_n, OUT_N);
        opcode_map.insert(INSTRUCTIONS.in_s, IN_S);
        opcode_map.insert(INSTRUCTIONS.out_s, OUT_S);
        opcode_map.insert(INSTRUCTIONS.add, ADD);
        opcode_map.insert(INSTRUCTIONS.sub, SUB);
        opcode_map.insert(INSTRUCTIONS.mul, MUL);
        opcode_map.insert(INSTRUCTIONS.div, DIV);
        opcode_map.insert(INSTRUCTIONS.con, CON);
        opcode_map.insert(INSTRUCTIONS.push, PUSH);
        opcode_map.insert(INSTRUCTIONS.pop, POP);
        opcode_map.insert(INSTRUCTIONS.ld, LD);
        opcode_map.insert(INSTRUCTIONS.st, ST);
        opcode_map.insert(INSTRUCTIONS.jmp, JMP);
        opcode_map.insert(INSTRUCTIONS.jgr, JGR);
        opcode_map.insert(INSTRUCTIONS.jge, JGE);
        opcode_map.insert(INSTRUCTIONS.jeq, JEQ);
        opcode_map.insert(INSTRUCTIONS.jne, JNE);
        opcode_map.insert(INSTRUCTIONS.jle, JLE);
        opcode_map.insert(INSTRUCTIONS.jls, JLS);

        for instruction in code {
            println!("{}", instruction);
        }
    }

    pub fn execute(&mut self) {
        loop {
            let inst = self.ins_mem[self.ip];
            let opcode = inst.rotate_left(8) & INST_MASK;

            match opcode {
                HALT => break,
                IN_N => self.process_in_n(),
                OUT_N => self.process_out_n(),
                IN_S => self.process_in_s(),
                OUT_S => self.process_out_s(),
                ADD => self.process_add(),
                SUB => self.process_sub(),
                MUL => self.process_mul(),
                DIV => self.process_div(),
                CON => self.process_con(),
                PUSH => self.process_push(),
                POP => self.process_pop(),
                LD => self.process_ld(),
                ST => self.process_st(),
                JMP => self.process_jmp(),
                JGR => self.process_jgr(),
                JGE => self.process_jge(),
                JEQ => self.process_jeq(),
                JNE => self.process_jne(),
                JLE => self.process_jle(),
                JLS => self.process_jls(),
                _ => {
                    println!("Unknow instruction. Aborting.");
                    break;
                }

            }

            if self.has_errors() {
                self.throw_exception();
                break;
            }
        }
    }

    fn process_in_n(&mut self) {
        let mut input_text = String::new();
        stdin()
            .read_line(&mut input_text)
            .expect("failed to read from stdin");

        let trimmed = input_text.trim();
        match trimmed.parse::<f64>() {
            Ok(i) => {
                self.acc = unsafe { transmute::<f64, u64>(i) };
                self.ip = self.ip + 1;
            }
            Err(..) => self.set_io_error_flag(),
        };
    }

    fn process_out_n(&mut self) {
        let output = unsafe { transmute::<u64, f64>(self.acc) };
        println!("{}", output);
        self.ip = self.ip + 1;
    }

    fn process_in_s(&mut self) {}

    fn process_out_s(&mut self) {}

    fn process_add(&mut self) {
        let inst = self.ins_mem[self.ip];
        let operand1Reg = (inst.rotate_left(15) & REG_MASK) as usize;
        let operand2Reg = (inst.rotate_left(18) & REG_MASK) as usize;

        let operand1 = unsafe { transmute::<u64, f64>(self.reg[operand1Reg]) };
        let operand2 = unsafe { transmute::<u64, f64>(self.reg[operand2Reg]) };

        let result = operand1 + operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_sub(&mut self) {
        let inst = self.ins_mem[self.ip];
        let operand1Reg = (inst.rotate_left(15) & REG_MASK) as usize;
        let operand2Reg = (inst.rotate_left(18) & REG_MASK) as usize;

        let operand1 = unsafe { transmute::<u64, f64>(self.reg[operand1Reg]) };
        let operand2 = unsafe { transmute::<u64, f64>(self.reg[operand2Reg]) };

        let result = operand1 - operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_mul(&mut self) {
        let inst = self.ins_mem[self.ip];
        let operand1Reg = (inst.rotate_left(15) & REG_MASK) as usize;
        let operand2Reg = (inst.rotate_left(18) & REG_MASK) as usize;

        let operand1 = unsafe { transmute::<u64, f64>(self.reg[operand1Reg]) };
        let operand2 = unsafe { transmute::<u64, f64>(self.reg[operand2Reg]) };

        let result = operand1 * operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_div(&mut self) {
        let inst = self.ins_mem[self.ip];
        let operand1Reg = (inst.rotate_left(15) & REG_MASK) as usize;
        let operand2Reg = (inst.rotate_left(18) & REG_MASK) as usize;

        let operand1 = unsafe { transmute::<u64, f64>(self.reg[operand1Reg]) };
        let operand2 = unsafe { transmute::<u64, f64>(self.reg[operand2Reg]) };

        let result = operand1 / operand2;

        self.acc = unsafe { transmute::<f64, u64>(result) };
        self.ip = self.ip + 1;
    }

    fn process_con(&mut self) {}

    fn process_push(&mut self) {}

    fn process_pop(&mut self) {}

    fn process_ld(&mut self) {}

    fn process_st(&mut self) {}

    fn process_jmp(&mut self) {}

    fn process_jgr(&mut self) {}

    fn process_jge(&mut self) {}

    fn process_jeq(&mut self) {}

    fn process_jne(&mut self) {}

    fn process_jle(&mut self) {}

    fn process_jls(&mut self) {}

    fn set_io_error_flag(&mut self) {
        println!("IO error flag set!")
    }

    fn has_errors(&mut self) -> bool {
        false
    }

    fn throw_exception(&mut self) {
        println!("Exception thrown!")
    }
}
<|endoftext|>


<commit_before>// .env parsing
extern crate dotenv;
// command line argument parsing
extern crate clap;
// logging macros
#[macro_use]
extern crate log;
// console logging output
extern crate fern;
extern crate chrono;
// Screeps API
extern crate screeps_api;
// HTTP connection
extern crate hyper;
// secure HTTPS connection
extern crate hyper_rustls;
// json pretty printing
extern crate serde_json;

use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

use hyper::client::Client;
use hyper::net::HttpsConnector;

use screeps_api::sockets::{ParsedMessage, Channel, ChannelUpdate};
use screeps_api::sockets::ws::Result as WsResult;

/// Set up dotenv and retrieve a specific variable, informatively panicking if it does not exist.
fn env(var: &str) -> String {
    dotenv::dotenv().ok();
    match ::std::env::var(var) {
        Ok(value) => value,
        Err(e) => panic!("must have `{}` defined (err: {:?})", var, e),
    }
}

fn setup_logging(verbose: bool) {
    let log_level = if verbose {
        log::LogLevelFilter::Debug
    } else {
        log::LogLevelFilter::Info
    };
    fern::Dispatch::new()
        .level(log_level)
        .level_for("rustls", log::LogLevelFilter::Warn)
        .level_for("hyper", log::LogLevelFilter::Warn)
        .format(|out, message, record| {
            let now = chrono::Local::now();

            out.finish(format_args!("[{}][{}] {}: {}",
                                    now.format("%H:%M:%S"),
                                    record.level(),
                                    record.target(),
                                    message));
        })
        .chain(std::io::stdout())
        .apply()
        // ignore errors
        .unwrap_or(());
}

struct Handler<T: screeps_api::TokenStorage> {
    sender: screeps_api::sockets::Sender,
    tokens: T,
    info: screeps_api::MyInfo,
}

impl<T: screeps_api::TokenStorage> screeps_api::sockets::Handler for Handler<T> {
    fn on_message(&mut self, message: ParsedMessage) -> WsResult<()> {
        match message {
            ParsedMessage::AuthFailed => panic!("authentication with stored token failed!"),
            ParsedMessage::AuthOk { new_token } => {
                info!("authentication succeeded, now authenticated as {}.",
                      self.info.username);
                // return the token to the token storage in case we need it again - we won't in this example
                // program, but this is a good practice
                //
                // TODO: find an efficient way to do this automatically in the handler.
                self.tokens.return_token(new_token);

                let id = &*self.info.user_id;

                self.sender.subscribe(Channel::ServerMessages)?;
                self.sender.subscribe(Channel::user_cpu(id))?;
                self.sender.subscribe(Channel::user_messages(id))?;
                self.sender.subscribe(Channel::user_credits(id))?;
                self.sender.subscribe(Channel::user_console(id))?;
                self.sender.subscribe(Channel::room_map_updates("E0N0"))?;
                self.sender.subscribe(Channel::room_map_updates("E25S23"))?;
                // self.sender.subscribe(Channel::room_map_updates("E24S23"))?;
                // self.sender.subscribe(Channel::room_map_updates("E23S23"))?;
                // self.sender.subscribe(Channel::room_map_updates("E22S23"))?;
                // self.sender.subscribe(Channel::room_updates("W0S0"))?;
                // self.sender.subscribe(Channel::room_updates("W25S23"))?;

                info!("Successfully subscribed to channels!");
            }
            ParsedMessage::ChannelUpdate { update } => {
                match update {
                    ChannelUpdate::UserCpu { user_id, update } => info!("CPU: [{}] {:#?}", user_id, update),
                    ChannelUpdate::RoomMapView { room_name, update } => {
                        info!("Map View: [{}] {:?}", room_name, update);
                    }
                    ChannelUpdate::UserConsole { user_id, update } => {
                        info!("Console: [{}] {:#?}", user_id, update);
                    }
                    ChannelUpdate::Other { channel, update } => {
                        warn!("ChannelUpdate::Other: {}\n{}",
                              channel,
                              serde_json::to_string_pretty(&update).expect("failed to serialize json string"));
                    }
                }
            }
            ParsedMessage::ServerProtocol { protocol } => {
                info!("server protocol: {}", protocol);
            }
            ParsedMessage::ServerTime { time } => {
                info!("server time: {}", time);
            }
            ParsedMessage::ServerPackage { package } => {
                info!("server package: {}", package);
            }
            ParsedMessage::Other(other) => {
                warn!("ParsedMessage::Other: {}", other);
            }
        }

        Ok(())
    }

    /// Run on any websocket error or message parsing error.
    fn on_error(&mut self, err: screeps_api::sockets::Error) {
        error!("{}", err);
    }
}

fn main() {
    let cmd_arguments = clap::App::new("ws-debug")
        .arg(clap::Arg::with_name("verbose")
            .short("v")
            .long("verbose")
            .multiple(true)
            .help("Enables verbose logging"))
        .get_matches();
    setup_logging(cmd_arguments.is_present("verbose"));

    // Create a sharable hyper client
    let hyper = Arc::new(Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new())));
    // Create a sharable token storage.
    let token_storage = Arc::new(Mutex::new(VecDeque::new()));
    // Create the API client for this thread.
    let mut client = screeps_api::API::with_token(hyper, token_storage.clone());

    // Login using the API client - this will storage the auth token in token_storage.
    client.login(env("SCREEPS_API_USERNAME"), env("SCREEPS_API_PASSWORD")).expect("failed to login");

    let my_info = client.my_info().unwrap();

    info!("Logged in as {}, attempting to connect to stream.",
          my_info.username);

    let factory_token = token_storage.clone();
    let factory = move |sender| {
        Handler {
            sender: sender,
            tokens: factory_token.clone(),
            info: my_info.clone(),
        }
    };

    // TODO: somehow create a way to go from API url to websocket url.
    screeps_api::sockets::connect("wss://screeps.com/socket/785/40128567/websocket",
                                  factory,
                                  token_storage)
        .expect("failed to connect to socket");
}
<commit_msg>Make default verbosity level for ws-debug warnings only.<commit_after>// .env parsing
extern crate dotenv;
// command line argument parsing
extern crate clap;
// logging macros
#[macro_use]
extern crate log;
// console logging output
extern crate fern;
extern crate chrono;
// Screeps API
extern crate screeps_api;
// HTTP connection
extern crate hyper;
// secure HTTPS connection
extern crate hyper_rustls;
// json pretty printing
extern crate serde_json;

use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

use hyper::client::Client;
use hyper::net::HttpsConnector;

use screeps_api::sockets::{ParsedMessage, Channel, ChannelUpdate};
use screeps_api::sockets::ws::Result as WsResult;

/// Set up dotenv and retrieve a specific variable, informatively panicking if it does not exist.
fn env(var: &str) -> String {
    dotenv::dotenv().ok();
    match ::std::env::var(var) {
        Ok(value) => value,
        Err(e) => panic!("must have `{}` defined (err: {:?})", var, e),
    }
}

fn setup_logging(verbosity: u64) {
    let log_level = match verbosity {
        0 => log::LogLevelFilter::Warn,
        1 => log::LogLevelFilter::Info,
        _ => log::LogLevelFilter::Debug,
    };
    fern::Dispatch::new()
        .level(log_level)
        .level_for("rustls", log::LogLevelFilter::Warn)
        .level_for("hyper", log::LogLevelFilter::Warn)
        .format(|out, message, record| {
            let now = chrono::Local::now();

            out.finish(format_args!("[{}][{}] {}: {}",
                                    now.format("%H:%M:%S"),
                                    record.level(),
                                    record.target(),
                                    message));
        })
        .chain(std::io::stdout())
        .apply()
        // ignore errors
        .unwrap_or(());
}

struct Handler<T: screeps_api::TokenStorage> {
    sender: screeps_api::sockets::Sender,
    tokens: T,
    info: screeps_api::MyInfo,
}

impl<T: screeps_api::TokenStorage> screeps_api::sockets::Handler for Handler<T> {
    fn on_message(&mut self, message: ParsedMessage) -> WsResult<()> {
        match message {
            ParsedMessage::AuthFailed => panic!("authentication with stored token failed!"),
            ParsedMessage::AuthOk { new_token } => {
                info!("authentication succeeded, now authenticated as {}.",
                      self.info.username);
                // return the token to the token storage in case we need it again - we won't in this example
                // program, but this is a good practice
                //
                // TODO: find an efficient way to do this automatically in the handler.
                self.tokens.return_token(new_token);

                let id = &*self.info.user_id;

                self.sender.subscribe(Channel::ServerMessages)?;
                self.sender.subscribe(Channel::user_cpu(id))?;
                self.sender.subscribe(Channel::user_messages(id))?;
                self.sender.subscribe(Channel::user_credits(id))?;
                self.sender.subscribe(Channel::user_console(id))?;
                self.sender.subscribe(Channel::room_map_updates("E0N0"))?;
                self.sender.subscribe(Channel::room_map_updates("E25S23"))?;
                // self.sender.subscribe(Channel::room_map_updates("E24S23"))?;
                // self.sender.subscribe(Channel::room_map_updates("E23S23"))?;
                // self.sender.subscribe(Channel::room_map_updates("E22S23"))?;
                // self.sender.subscribe(Channel::room_updates("W0S0"))?;
                // self.sender.subscribe(Channel::room_updates("W25S23"))?;

                info!("Successfully subscribed to channels!");
            }
            ParsedMessage::ChannelUpdate { update } => {
                match update {
                    ChannelUpdate::UserCpu { user_id, update } => info!("CPU: [{}] {:#?}", user_id, update),
                    ChannelUpdate::RoomMapView { room_name, update } => {
                        info!("Map View: [{}] {:?}", room_name, update);
                    }
                    ChannelUpdate::UserConsole { user_id, update } => {
                        info!("Console: [{}] {:#?}", user_id, update);
                    }
                    ChannelUpdate::Other { channel, update } => {
                        warn!("ChannelUpdate::Other: {}\n{}",
                              channel,
                              serde_json::to_string_pretty(&update).expect("failed to serialize json string"));
                    }
                }
            }
            ParsedMessage::ServerProtocol { protocol } => {
                info!("server protocol: {}", protocol);
            }
            ParsedMessage::ServerTime { time } => {
                info!("server time: {}", time);
            }
            ParsedMessage::ServerPackage { package } => {
                info!("server package: {}", package);
            }
            ParsedMessage::Other(other) => {
                warn!("ParsedMessage::Other: {}", other);
            }
        }

        Ok(())
    }

    /// Run on any websocket error or message parsing error.
    fn on_error(&mut self, err: screeps_api::sockets::Error) {
        error!("{}", err);
    }
}

fn main() {
    let cmd_arguments = clap::App::new("ws-debug")
        .arg(clap::Arg::with_name("verbose")
            .short("v")
            .long("verbose")
            .multiple(true)
            .help("Enables verbose logging"))
        .get_matches();
    setup_logging(cmd_arguments.occurrences_of("verbose"));

    // Create a sharable hyper client
    let hyper = Arc::new(Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new())));
    // Create a sharable token storage.
    let token_storage = Arc::new(Mutex::new(VecDeque::new()));
    // Create the API client for this thread.
    let mut client = screeps_api::API::with_token(hyper, token_storage.clone());

    // Login using the API client - this will storage the auth token in token_storage.
    client.login(env("SCREEPS_API_USERNAME"), env("SCREEPS_API_PASSWORD")).expect("failed to login");

    let my_info = client.my_info().unwrap();

    info!("Logged in as {}, attempting to connect to stream.",
          my_info.username);

    let factory_token = token_storage.clone();
    let factory = move |sender| {
        Handler {
            sender: sender,
            tokens: factory_token.clone(),
            info: my_info.clone(),
        }
    };

    // TODO: somehow create a way to go from API url to websocket url.
    screeps_api::sockets::connect("wss://screeps.com/socket/785/40128567/websocket",
                                  factory,
                                  token_storage)
        .expect("failed to connect to socket");
}
<|endoftext|>