<commit_before>//! The core reactor driving all I/O
//!
//! This module contains the `Core` type which is the reactor for all I/O
//! happening in `tokio-core`. This reactor (or event loop) is used to drive I/O
//! resources.

use std::fmt;
use std::io::{self, ErrorKind};
use std::sync::{Arc, Weak, RwLock};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::time::{Duration};

use futures::{Future, Async};
use futures::executor::{self, Notify};
use futures::task::{AtomicTask};
use mio;
use mio::event::Evented;
use slab::Slab;

mod io_token;

mod poll_evented;
pub use self::poll_evented::PollEvented;

/// Global counter used to assign unique IDs to reactor instances.
static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// An event loop.
///
/// The event loop is the main source of blocking in an application which drives
/// all other I/O events and notifications happening. Each event loop can have
/// multiple handles pointing to it, each of which can then be used to create
/// various I/O objects to interact with the event loop in interesting ways.
pub struct Core {
    /// Reuse the `mio::Events` value across calls to poll.
    events: mio::Events,

    /// State shared between the reactor and the handles.
    inner: Arc<Inner>,

    /// Used for determining when the future passed to `run` is ready. Once the
    /// registration is passed to `io` above we never touch it again, just keep
    /// it alive.
    _future_registration: mio::Registration,
    future_readiness: Arc<MySetReadiness>,
}

struct Inner {
    /// Unique identifier referencing this reactor.
    id: usize,

    /// The underlying system event queue.
    io: mio::Poll,

    /// Dispatch slabs for I/O and futures events
    io_dispatch: RwLock<Slab<ScheduledIo>>,
}

/// An unique ID for a Core
///
/// An ID by which different cores may be distinguished. Can be compared and used as an index in
/// a `HashMap`.
///
/// The ID is globally unique and never reused.
#[derive(Clone,Copy,Eq,PartialEq,Hash,Debug)]
pub struct CoreId(usize);

/// Handle to an event loop, used to construct I/O objects, send messages, and
/// otherwise interact indirectly with the event loop itself.
///
/// Handles can be cloned, and when cloned they will still refer to the
/// same underlying event loop.
#[derive(Clone)]
pub struct Remote {
    id: usize,
    inner: Weak<Inner>,
}

/// A non-sendable handle to an event loop, useful for manufacturing instances
/// of `LoopData`.
#[derive(Clone)]
pub struct Handle {
    remote: Remote,
}

struct ScheduledIo {
    readiness: AtomicUsize,
    reader: AtomicTask,
    writer: AtomicTask,
}

enum Direction {
    Read,
    Write,
}

const TOKEN_FUTURE: mio::Token = mio::Token(1);
const TOKEN_START: usize = 2;

fn _assert_kinds() {
    fn _assert<T: Send + Sync>() {}

    _assert::<Handle>();
    _assert::<Remote>();
}

impl Core {
    /// Creates a new event loop, returning any error that happened during the
    /// creation.
    pub fn new() -> io::Result<Core> {
        // Create the I/O poller
        let io = try!(mio::Poll::new());

        // Create a registration for unblocking the reactor when the "run"
        // future becomes ready.
        let future_pair = mio::Registration::new2();
        try!(io.register(&future_pair.0,
                         TOKEN_FUTURE,
                         mio::Ready::readable(),
                         mio::PollOpt::level()));

        Ok(Core {
            events: mio::Events::with_capacity(1024),
            _future_registration: future_pair.0,
            future_readiness: Arc::new(MySetReadiness(future_pair.1)),
            inner: Arc::new(Inner {
                id: NEXT_LOOP_ID.fetch_add(1, Ordering::Relaxed),
                io: io,
                io_dispatch: RwLock::new(Slab::with_capacity(1)),
            }),
        })
    }

    /// Returns a handle to this event loop which cannot be sent across threads
    /// but can be used as a proxy to the event loop itself.
    ///
    /// Handles are cloneable and clones always refer to the same event loop.
    /// This handle is typically passed into functions that create I/O objects
    /// to bind them to this event loop.
    pub fn handle(&self) -> Handle {
        let remote = self.remote();
        Handle { remote }
    }

    /// Generates a remote handle to this event loop which can be used to spawn
    /// tasks from other threads into this event loop.
    pub fn remote(&self) -> Remote {
        Remote {
            id: self.inner.id,
            inner: Arc::downgrade(&self.inner),
        }
    }

    /// Runs a future until completion, driving the event loop while we're
    /// otherwise waiting for the future to complete.
    ///
    /// This function will begin executing the event loop and will finish once
    /// the provided future is resolved. Note that the future argument here
    /// crucially does not require the `'static` nor `Send` bounds. As a result
    /// the future will be "pinned" to not only this thread but also this stack
    /// frame.
    ///
    /// This function will return the value that the future resolves to once
    /// the future has finished. If the future never resolves then this function
    /// will never return.
    ///
    /// # Panics
    ///
    /// This method will **not** catch panics from polling the future `f`. If
    /// the future panics then it's the responsibility of the caller to catch
    /// that panic and handle it as appropriate.
    pub fn run<F>(&mut self, f: F) -> Result<F::Item, F::Error>
        where F: Future,
    {
        let mut task = executor::spawn(f);
        let mut future_fired = true;

        loop {
            if future_fired {
                let res = task.poll_future_notify(&self.future_readiness, 0)?;
                if let Async::Ready(e) = res {
                    return Ok(e)
                }
            }
            future_fired = self.poll(None);
        }
    }

    /// Performs one iteration of the event loop, blocking on waiting for events
    /// for at most `max_wait` (forever if `None`).
    ///
    /// It only makes sense to call this method if you've previously spawned
    /// a future onto this event loop.
    ///
    /// `loop { lp.turn(None) }` is equivalent to calling `run` with an
    /// empty future (one that never finishes).
    pub fn turn(&mut self, max_wait: Option<Duration>) {
        self.poll(max_wait);
    }

    fn poll(&mut self, max_wait: Option<Duration>) -> bool {
        // Block waiting for an event to happen, peeling out how many events
        // happened.
        match self.inner.io.poll(&mut self.events, max_wait) {
            Ok(_) => {}
            Err(ref e) if e.kind() == ErrorKind::Interrupted => return false,
            // TODO: This should return an io::Result instead of panic.
            Err(e) => panic!("error in poll: {}", e),
        }

        // Process all the events that came in, dispatching appropriately
        let mut fired = false;
        for i in 0..self.events.len() {
            let event = self.events.get(i).unwrap();
            let token = event.token();
            trace!("event {:?} {:?}", event.readiness(), event.token());

            if token == TOKEN_FUTURE {
                self.future_readiness.0.set_readiness(mio::Ready::empty()).unwrap();
                fired = true;
            } else {
                self.dispatch(token, event.readiness());
            }
        }

        return fired
    }

    fn dispatch(&mut self, token: mio::Token, ready: mio::Ready) {
        let token = usize::from(token) - TOKEN_START;
        let io_dispatch = self.inner.io_dispatch.read().unwrap();

        if let Some(io) = io_dispatch.get(token) {
            io.readiness.fetch_or(ready2usize(ready), Ordering::Relaxed);
            if ready.is_writable() {
                io.writer.notify();
            }
            if !(ready & (!mio::Ready::writable())).is_empty() {
                io.reader.notify();
            }
        }
    }

    /// Get the ID of this loop
    pub fn id(&self) -> CoreId {
        CoreId(self.inner.id)
    }
}

impl fmt::Debug for Core {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Core")
         .field("id", &self.id())
         .finish()
    }
}

impl Inner {
    /// Register an I/O resource with the reactor.
    ///
    /// The registration token is returned.
    fn add_source(&self, source: &Evented)
        -> io::Result<usize>
    {
        // Acquire a write lock
        let key = self.io_dispatch.write().unwrap()
            .insert(ScheduledIo {
                readiness: AtomicUsize::new(0),
                reader: AtomicTask::new(),
                writer: AtomicTask::new(),
            });

        try!(self.io.register(source,
                              mio::Token(TOKEN_START + key),
                              mio::Ready::readable() |
                                mio::Ready::writable() |
                                platform::all(),
                              mio::PollOpt::edge()));

        Ok(key)
    }

    fn deregister_source(&self, source: &Evented) -> io::Result<()> {
        self.io.deregister(source)
    }

    fn drop_source(&self, token: usize) {
        debug!("dropping I/O source: {}", token);
        self.io_dispatch.write().unwrap().remove(token);
    }

    /// Registers interest in the I/O resource associated with `token`.
    fn schedule(&self, token: usize, dir: Direction) {
        debug!("scheduling direction for: {}", token);
        let io_dispatch = self.io_dispatch.read().unwrap();
        let sched = io_dispatch.get(token).unwrap();

        let (task, ready) = match dir {
            Direction::Read => (&sched.reader, !mio::Ready::writable()),
            Direction::Write => (&sched.writer, mio::Ready::writable()),
        };

        task.register();

        if sched.readiness.load(Ordering::SeqCst) & ready2usize(ready) != 0 {
            task.notify();
        }
    }
}

impl Remote {
    /// Return the ID of the represented Core
    pub fn id(&self) -> CoreId {
        CoreId(self.id)
    }

    /// Attempts to "promote" this remote to a handle, if possible.
    ///
    /// This function is intended for structures which typically work through a
    /// `Remote` but want to optimize runtime when the remote doesn't actually
    /// leave the thread of the original reactor. This will attempt to return a
    /// handle if the `Remote` is on the same thread as the event loop and the
    /// event loop is running.
    ///
    /// If this `Remote` has moved to a different thread or if the event loop is
    /// running, then `None` may be returned. If you need to guarantee access to
    /// a `Handle`, then you can call this function and fall back to using
    /// `spawn` above if it returns `None`.
    pub fn handle(&self) -> Option<Handle> {
        let remote = self.clone();
        Some(Handle { remote } )
    }

    /// Spawns a new future into the event loop this remote is associated with.
    ///
    /// This function takes a closure which is executed within the context of
    /// the I/O loop itself. The future returned by the closure will be
    /// scheduled on the event loop and run to completion.
    ///
    /// Note that while the closure, `F`, requires the `Send` bound as it might
    /// cross threads, the future `R` does not.
    ///
    /// # Panics
    ///
    /// This method will **not** catch panics from polling the future `f`. If
    /// the future panics then it's the responsibility of the caller to catch
    /// that panic and handle it as appropriate.
    pub(crate) fn run<F>(&self, f: F)
        where F: FnOnce(&Handle) + Send + 'static,
    {
        let handle = self.handle().unwrap();
        f(&handle);
    }
}

impl fmt::Debug for Remote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Remote")
         .field("id", &self.id())
         .finish()
    }
}

impl Handle {
    /// Returns a reference to the underlying remote handle to the event loop.
    pub fn remote(&self) -> &Remote {
        &self.remote
    }

    /// Return the ID of the represented Core
    pub fn id(&self) -> CoreId {
        self.remote.id()
    }
}

impl fmt::Debug for Handle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Handle")
         .field("id", &self.id())
         .finish()
    }
}

struct MySetReadiness(mio::SetReadiness);

impl Notify for MySetReadiness {
    fn notify(&self, _id: usize) {
        self.0.set_readiness(mio::Ready::readable())
              .expect("failed to set readiness");
    }
}

trait FnBox: Send + 'static {
    fn call_box(self: Box<Self>, lp: &Core);
}

impl<F: FnOnce(&Core) + Send + 'static> FnBox for F {
    fn call_box(self: Box<Self>, lp: &Core) {
        (*self)(lp)
    }
}

fn read_ready() -> mio::Ready {
    mio::Ready::readable() | platform::hup()
}

const READ: usize = 1 << 0;
const WRITE: usize = 1 << 1;

fn ready2usize(ready: mio::Ready) -> usize {
    let mut bits = 0;
    if ready.is_readable() {
        bits |= READ;
    }
    if ready.is_writable() {
        bits |= WRITE;
    }
    bits | platform::ready2usize(ready)
}

fn usize2ready(bits: usize) -> mio::Ready {
    let mut ready = mio::Ready::empty();
    if bits & READ != 0 {
        ready.insert(mio::Ready::readable());
    }
    if bits & WRITE != 0 {
        ready.insert(mio::Ready::writable());
    }
    ready | platform::usize2ready(bits)
}

#[cfg(all(unix, not(target_os = "fuchsia")))]
mod platform {
    use mio::Ready;
    use mio::unix::UnixReady;

    pub fn aio() -> Ready {
        UnixReady::aio().into()
    }

    pub fn all() -> Ready {
        hup() | aio()
    }

    pub fn hup() -> Ready {
        UnixReady::hup().into()
    }

    const HUP: usize = 1 << 2;
    const ERROR: usize = 1 << 3;
    const AIO: usize = 1 << 4;

    pub fn ready2usize(ready: Ready) -> usize {
        let ready = UnixReady::from(ready);
        let mut bits = 0;
        if ready.is_aio() {
            bits |= AIO;
        }
        if ready.is_error() {
            bits |= ERROR;
        }
        if ready.is_hup() {
            bits |= HUP;
        }
        bits
    }

    pub fn usize2ready(bits: usize) -> Ready {
        let mut ready = UnixReady::from(Ready::empty());
        if bits & AIO != 0 {
            ready.insert(UnixReady::aio());
        }
        if bits & HUP != 0 {
            ready.insert(UnixReady::hup());
        }
        if bits & ERROR != 0 {
            ready.insert(UnixReady::error());
        }
        ready.into()
    }
}

#[cfg(any(windows, target_os = "fuchsia"))]
mod platform {
    use mio::Ready;

    pub fn all() -> Ready {
        // No platform-specific Readinesses for Windows
        Ready::empty()
    }

    pub fn hup() -> Ready {
        Ready::empty()
    }

    pub fn ready2usize(_r: Ready) -> usize {
        0
    }

    pub fn usize2ready(_r: usize) -> Ready {
        Ready::empty()
    }
}
<commit_msg>Remove Core:id. (#41)<commit_after>//! The core reactor driving all I/O
//!
//! This module contains the `Core` type which is the reactor for all I/O
//! happening in `tokio-core`. This reactor (or event loop) is used to drive I/O
//! resources.

use std::fmt;
use std::io::{self, ErrorKind};
use std::sync::{Arc, Weak, RwLock};
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::time::{Duration};

use futures::{Future, Async};
use futures::executor::{self, Notify};
use futures::task::{AtomicTask};
use mio;
use mio::event::Evented;
use slab::Slab;

mod io_token;

mod poll_evented;
pub use self::poll_evented::PollEvented;

/// Global counter used to assign unique IDs to reactor instances.
static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// An event loop.
///
/// The event loop is the main source of blocking in an application which drives
/// all other I/O events and notifications happening. Each event loop can have
/// multiple handles pointing to it, each of which can then be used to create
/// various I/O objects to interact with the event loop in interesting ways.
pub struct Core {
    /// Reuse the `mio::Events` value across calls to poll.
    events: mio::Events,

    /// State shared between the reactor and the handles.
    inner: Arc<Inner>,

    /// Used for determining when the future passed to `run` is ready. Once the
    /// registration is passed to `io` above we never touch it again, just keep
    /// it alive.
    _future_registration: mio::Registration,
    future_readiness: Arc<MySetReadiness>,
}

struct Inner {
    /// Unique identifier referencing this reactor.
    id: usize,

    /// The underlying system event queue.
    io: mio::Poll,

    /// Dispatch slabs for I/O and futures events
    io_dispatch: RwLock<Slab<ScheduledIo>>,
}

/// Handle to an event loop, used to construct I/O objects, send messages, and
/// otherwise interact indirectly with the event loop itself.
///
/// Handles can be cloned, and when cloned they will still refer to the
/// same underlying event loop.
#[derive(Clone)]
pub struct Remote {
    id: usize,
    inner: Weak<Inner>,
}

/// A non-sendable handle to an event loop, useful for manufacturing instances
/// of `LoopData`.
#[derive(Clone)]
pub struct Handle {
    remote: Remote,
}

struct ScheduledIo {
    readiness: AtomicUsize,
    reader: AtomicTask,
    writer: AtomicTask,
}

enum Direction {
    Read,
    Write,
}

const TOKEN_FUTURE: mio::Token = mio::Token(1);
const TOKEN_START: usize = 2;

fn _assert_kinds() {
    fn _assert<T: Send + Sync>() {}

    _assert::<Handle>();
    _assert::<Remote>();
}

impl Core {
    /// Creates a new event loop, returning any error that happened during the
    /// creation.
    pub fn new() -> io::Result<Core> {
        // Create the I/O poller
        let io = try!(mio::Poll::new());

        // Create a registration for unblocking the reactor when the "run"
        // future becomes ready.
        let future_pair = mio::Registration::new2();
        try!(io.register(&future_pair.0,
                         TOKEN_FUTURE,
                         mio::Ready::readable(),
                         mio::PollOpt::level()));

        Ok(Core {
            events: mio::Events::with_capacity(1024),
            _future_registration: future_pair.0,
            future_readiness: Arc::new(MySetReadiness(future_pair.1)),
            inner: Arc::new(Inner {
                id: NEXT_LOOP_ID.fetch_add(1, Ordering::Relaxed),
                io: io,
                io_dispatch: RwLock::new(Slab::with_capacity(1)),
            }),
        })
    }

    /// Returns a handle to this event loop which cannot be sent across threads
    /// but can be used as a proxy to the event loop itself.
    ///
    /// Handles are cloneable and clones always refer to the same event loop.
    /// This handle is typically passed into functions that create I/O objects
    /// to bind them to this event loop.
    pub fn handle(&self) -> Handle {
        let remote = self.remote();
        Handle { remote }
    }

    /// Generates a remote handle to this event loop which can be used to spawn
    /// tasks from other threads into this event loop.
    pub fn remote(&self) -> Remote {
        Remote {
            id: self.inner.id,
            inner: Arc::downgrade(&self.inner),
        }
    }

    /// Runs a future until completion, driving the event loop while we're
    /// otherwise waiting for the future to complete.
    ///
    /// This function will begin executing the event loop and will finish once
    /// the provided future is resolved. Note that the future argument here
    /// crucially does not require the `'static` nor `Send` bounds. As a result
    /// the future will be "pinned" to not only this thread but also this stack
    /// frame.
    ///
    /// This function will return the value that the future resolves to once
    /// the future has finished. If the future never resolves then this function
    /// will never return.
    ///
    /// # Panics
    ///
    /// This method will **not** catch panics from polling the future `f`. If
    /// the future panics then it's the responsibility of the caller to catch
    /// that panic and handle it as appropriate.
    pub fn run<F>(&mut self, f: F) -> Result<F::Item, F::Error>
        where F: Future,
    {
        let mut task = executor::spawn(f);
        let mut future_fired = true;

        loop {
            if future_fired {
                let res = task.poll_future_notify(&self.future_readiness, 0)?;
                if let Async::Ready(e) = res {
                    return Ok(e)
                }
            }
            future_fired = self.poll(None);
        }
    }

    /// Performs one iteration of the event loop, blocking on waiting for events
    /// for at most `max_wait` (forever if `None`).
    ///
    /// It only makes sense to call this method if you've previously spawned
    /// a future onto this event loop.
    ///
    /// `loop { lp.turn(None) }` is equivalent to calling `run` with an
    /// empty future (one that never finishes).
    pub fn turn(&mut self, max_wait: Option<Duration>) {
        self.poll(max_wait);
    }

    fn poll(&mut self, max_wait: Option<Duration>) -> bool {
        // Block waiting for an event to happen, peeling out how many events
        // happened.
        match self.inner.io.poll(&mut self.events, max_wait) {
            Ok(_) => {}
            Err(ref e) if e.kind() == ErrorKind::Interrupted => return false,
            // TODO: This should return an io::Result instead of panic.
            Err(e) => panic!("error in poll: {}", e),
        }

        // Process all the events that came in, dispatching appropriately
        let mut fired = false;
        for i in 0..self.events.len() {
            let event = self.events.get(i).unwrap();
            let token = event.token();
            trace!("event {:?} {:?}", event.readiness(), event.token());

            if token == TOKEN_FUTURE {
                self.future_readiness.0.set_readiness(mio::Ready::empty()).unwrap();
                fired = true;
            } else {
                self.dispatch(token, event.readiness());
            }
        }

        return fired
    }

    fn dispatch(&mut self, token: mio::Token, ready: mio::Ready) {
        let token = usize::from(token) - TOKEN_START;
        let io_dispatch = self.inner.io_dispatch.read().unwrap();

        if let Some(io) = io_dispatch.get(token) {
            io.readiness.fetch_or(ready2usize(ready), Ordering::Relaxed);
            if ready.is_writable() {
                io.writer.notify();
            }
            if !(ready & (!mio::Ready::writable())).is_empty() {
                io.reader.notify();
            }
        }
    }
}

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

impl Inner {
    /// Register an I/O resource with the reactor.
    ///
    /// The registration token is returned.
    fn add_source(&self, source: &Evented)
        -> io::Result<usize>
    {
        // Acquire a write lock
        let key = self.io_dispatch.write().unwrap()
            .insert(ScheduledIo {
                readiness: AtomicUsize::new(0),
                reader: AtomicTask::new(),
                writer: AtomicTask::new(),
            });

        try!(self.io.register(source,
                              mio::Token(TOKEN_START + key),
                              mio::Ready::readable() |
                                mio::Ready::writable() |
                                platform::all(),
                              mio::PollOpt::edge()));

        Ok(key)
    }

    fn deregister_source(&self, source: &Evented) -> io::Result<()> {
        self.io.deregister(source)
    }

    fn drop_source(&self, token: usize) {
        debug!("dropping I/O source: {}", token);
        self.io_dispatch.write().unwrap().remove(token);
    }

    /// Registers interest in the I/O resource associated with `token`.
    fn schedule(&self, token: usize, dir: Direction) {
        debug!("scheduling direction for: {}", token);
        let io_dispatch = self.io_dispatch.read().unwrap();
        let sched = io_dispatch.get(token).unwrap();

        let (task, ready) = match dir {
            Direction::Read => (&sched.reader, !mio::Ready::writable()),
            Direction::Write => (&sched.writer, mio::Ready::writable()),
        };

        task.register();

        if sched.readiness.load(Ordering::SeqCst) & ready2usize(ready) != 0 {
            task.notify();
        }
    }
}

impl Remote {
    /// Attempts to "promote" this remote to a handle, if possible.
    ///
    /// This function is intended for structures which typically work through a
    /// `Remote` but want to optimize runtime when the remote doesn't actually
    /// leave the thread of the original reactor. This will attempt to return a
    /// handle if the `Remote` is on the same thread as the event loop and the
    /// event loop is running.
    ///
    /// If this `Remote` has moved to a different thread or if the event loop is
    /// running, then `None` may be returned. If you need to guarantee access to
    /// a `Handle`, then you can call this function and fall back to using
    /// `spawn` above if it returns `None`.
    pub fn handle(&self) -> Option<Handle> {
        let remote = self.clone();
        Some(Handle { remote } )
    }

    /// Spawns a new future into the event loop this remote is associated with.
    ///
    /// This function takes a closure which is executed within the context of
    /// the I/O loop itself. The future returned by the closure will be
    /// scheduled on the event loop and run to completion.
    ///
    /// Note that while the closure, `F`, requires the `Send` bound as it might
    /// cross threads, the future `R` does not.
    ///
    /// # Panics
    ///
    /// This method will **not** catch panics from polling the future `f`. If
    /// the future panics then it's the responsibility of the caller to catch
    /// that panic and handle it as appropriate.
    pub(crate) fn run<F>(&self, f: F)
        where F: FnOnce(&Handle) + Send + 'static,
    {
        let handle = self.handle().unwrap();
        f(&handle);
    }
}

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

impl Handle {
    /// Returns a reference to the underlying remote handle to the event loop.
    pub fn remote(&self) -> &Remote {
        &self.remote
    }
}

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

struct MySetReadiness(mio::SetReadiness);

impl Notify for MySetReadiness {
    fn notify(&self, _id: usize) {
        self.0.set_readiness(mio::Ready::readable())
              .expect("failed to set readiness");
    }
}

trait FnBox: Send + 'static {
    fn call_box(self: Box<Self>, lp: &Core);
}

impl<F: FnOnce(&Core) + Send + 'static> FnBox for F {
    fn call_box(self: Box<Self>, lp: &Core) {
        (*self)(lp)
    }
}

fn read_ready() -> mio::Ready {
    mio::Ready::readable() | platform::hup()
}

const READ: usize = 1 << 0;
const WRITE: usize = 1 << 1;

fn ready2usize(ready: mio::Ready) -> usize {
    let mut bits = 0;
    if ready.is_readable() {
        bits |= READ;
    }
    if ready.is_writable() {
        bits |= WRITE;
    }
    bits | platform::ready2usize(ready)
}

fn usize2ready(bits: usize) -> mio::Ready {
    let mut ready = mio::Ready::empty();
    if bits & READ != 0 {
        ready.insert(mio::Ready::readable());
    }
    if bits & WRITE != 0 {
        ready.insert(mio::Ready::writable());
    }
    ready | platform::usize2ready(bits)
}

#[cfg(all(unix, not(target_os = "fuchsia")))]
mod platform {
    use mio::Ready;
    use mio::unix::UnixReady;

    pub fn aio() -> Ready {
        UnixReady::aio().into()
    }

    pub fn all() -> Ready {
        hup() | aio()
    }

    pub fn hup() -> Ready {
        UnixReady::hup().into()
    }

    const HUP: usize = 1 << 2;
    const ERROR: usize = 1 << 3;
    const AIO: usize = 1 << 4;

    pub fn ready2usize(ready: Ready) -> usize {
        let ready = UnixReady::from(ready);
        let mut bits = 0;
        if ready.is_aio() {
            bits |= AIO;
        }
        if ready.is_error() {
            bits |= ERROR;
        }
        if ready.is_hup() {
            bits |= HUP;
        }
        bits
    }

    pub fn usize2ready(bits: usize) -> Ready {
        let mut ready = UnixReady::from(Ready::empty());
        if bits & AIO != 0 {
            ready.insert(UnixReady::aio());
        }
        if bits & HUP != 0 {
            ready.insert(UnixReady::hup());
        }
        if bits & ERROR != 0 {
            ready.insert(UnixReady::error());
        }
        ready.into()
    }
}

#[cfg(any(windows, target_os = "fuchsia"))]
mod platform {
    use mio::Ready;

    pub fn all() -> Ready {
        // No platform-specific Readinesses for Windows
        Ready::empty()
    }

    pub fn hup() -> Ready {
        Ready::empty()
    }

    pub fn ready2usize(_r: Ready) -> usize {
        0
    }

    pub fn usize2ready(_r: usize) -> Ready {
        Ready::empty()
    }
}
<|endoftext|>


<commit_before>extern crate wait;
extern crate atomic_counter;

use std::sync::atomic::AtomicUsize;
use std::time::Instant;
use std::net::{SocketAddrV4, Ipv4Addr, TcpListener};
use wait::sleeper::*;
use std::time::Duration;
use std::{thread, time};
use atomic_counter::AtomicCounter;
use atomic_counter::RelaxedCounter;

#[test]
fn should_wait_5_seconds_before() {
    let wait_for : u64 = 5;
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, wait_for, 0), &mut on_timeout);
    assert!( millisElapsed(start) >= wait_for )
}

#[test]
fn should_wait_10_seconds_after() {
    let wait_for = 10;
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, 0, wait_for ), &mut on_timeout);
    assert!( millisElapsed(start) >= wait_for )
}

#[test]
fn should_wait_before_and_after() {
    let wait_for = 10;
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, wait_for, wait_for ), &mut on_timeout);
    assert!( millisElapsed(start) >= (wait_for + wait_for) )
}

#[test]
fn should_execute_without_wait() {
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, 0, 0 ), &mut on_timeout);
    assert!( millisElapsed(start) <= 5 )
}

#[test]
fn should_exit_on_timeout() {
    let timeout = 25;
    let wait_before = 30;
    let wait_after = 300;
    let hosts = "localhost:".to_string() + &free_port().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let mut count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    // assert that the on_timeout callback was called
    assert_eq!(1, count.get());

    assert!( millisElapsed(start)  >= timeout + wait_before );
    assert!( millisElapsed(start)  < timeout + wait_after);
}

#[test]
fn should_identify_the_open_port() {
    let timeout = 500;
    let wait_before = 30;
    let wait_after = 30;

    let tcpListener = newTcpListener();
    let hosts = tcpListener.local_addr().unwrap().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let mut count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    listen_async(tcpListener);

    thread::sleep(time::Duration::from_millis(250));
    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    assert_eq!(0, count.get());

    assert!( millisElapsed(start)  >= wait_before + wait_after );
    assert!( millisElapsed(start)  < timeout + wait_before + wait_after);
}

#[test]
fn should_wait_multiple_hosts() {
    let timeout = 500;
    let wait_before = 30;
    let wait_after = 30;

    let tcpListener1 = newTcpListener();
    let tcpListener2 = newTcpListener();
    let hosts = tcpListener1.local_addr().unwrap().to_string() + "," + &tcpListener2.local_addr().unwrap().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let mut count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    listen_async(tcpListener1);
    listen_async(tcpListener2);

    thread::sleep(time::Duration::from_millis(250));
    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    assert_eq!(0, count.get());

    assert!( millisElapsed(start)  >= wait_before + wait_after );
    assert!( millisElapsed(start)  < timeout + wait_before + wait_after);
}

#[test]
fn should_fail_if_not_all_hosts_are_available() {
    let timeout = 100;
    let wait_before = 30;
    let wait_after = 30;

    let tcpListener1 = newTcpListener();
    let hosts = tcpListener1.local_addr().unwrap().to_string() + ",127.0.0.1:" + &free_port().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let mut count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    listen_async(tcpListener1);

    thread::sleep(time::Duration::from_millis(250));
    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    assert_eq!(1, count.get());

    assert!( millisElapsed(start)  >= wait_before + wait_after );
    assert!( millisElapsed(start)  >= timeout + wait_before + wait_after);
}

fn on_timeout() {}

fn new_config(hosts: &str, timeout: u64, before: u64, after: u64) -> wait::Config {
    wait::Config {
        hosts: hosts.to_string(),
        timeout: timeout,
        wait_before: before,
        wait_after: after,
    }
}

fn newTcpListener() -> TcpListener {
    let loopback = Ipv4Addr::new(127, 0, 0, 1);
    let socket = SocketAddrV4::new(loopback, 0);
    TcpListener::bind(socket).unwrap()
}

fn listen_async(listener: TcpListener) {
    thread::spawn(move || {
            loop {
                match listener.accept() {
                    Ok(_) => {  println!("Connection received!"); }
                    Err(_) => { println!("Error in received connection!"); }
                }
            }
    });
}

fn free_port() -> u16 {
    newTcpListener().local_addr().unwrap().port()
}

fn millisElapsed(start: Instant) -> u64 {
    let elapsed = start.elapsed().subsec_nanos() / 1000000;
    println!("Millis elapsed {}", elapsed);
    elapsed as u64
}

struct MillisSleeper {}

impl Sleeper for MillisSleeper {
    fn sleep(&self, duration: u64) {
        thread::sleep(Duration::from_millis(duration))
    }
}<commit_msg>Fix compiler warnings<commit_after>extern crate wait;
extern crate atomic_counter;

use std::time::Instant;
use std::net::{SocketAddrV4, Ipv4Addr, TcpListener};
use wait::sleeper::*;
use std::time::Duration;
use std::{thread, time};
use atomic_counter::AtomicCounter;

#[test]
fn should_wait_5_seconds_before() {
    let wait_for : u64 = 5;
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, wait_for, 0), &mut on_timeout);
    assert!( millis_elapsed(start) >= wait_for )
}

#[test]
fn should_wait_10_seconds_after() {
    let wait_for = 10;
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, 0, wait_for ), &mut on_timeout);
    assert!( millis_elapsed(start) >= wait_for )
}

#[test]
fn should_wait_before_and_after() {
    let wait_for = 10;
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, wait_for, wait_for ), &mut on_timeout);
    assert!( millis_elapsed(start) >= (wait_for + wait_for) )
}

#[test]
fn should_execute_without_wait() {
    let start = Instant::now();
    let sleeper = MillisSleeper{};
    wait::wait(&sleeper, &new_config("", 1, 0, 0 ), &mut on_timeout);
    assert!( millis_elapsed(start) <= 5 )
}

#[test]
fn should_exit_on_timeout() {
    let timeout = 25;
    let wait_before = 30;
    let wait_after = 300;
    let hosts = "localhost:".to_string() + &free_port().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    // assert that the on_timeout callback was called
    assert_eq!(1, count.get());

    assert!( millis_elapsed(start)  >= timeout + wait_before );
    assert!( millis_elapsed(start)  < timeout + wait_after);
}

#[test]
fn should_identify_the_open_port() {
    let timeout = 500;
    let wait_before = 30;
    let wait_after = 30;

    let tcp_listener = new_tcp_listener();
    let hosts = tcp_listener.local_addr().unwrap().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    listen_async(tcp_listener);

    thread::sleep(time::Duration::from_millis(250));
    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    assert_eq!(0, count.get());

    assert!( millis_elapsed(start)  >= wait_before + wait_after );
    assert!( millis_elapsed(start)  < timeout + wait_before + wait_after);
}

#[test]
fn should_wait_multiple_hosts() {
    let timeout = 500;
    let wait_before = 30;
    let wait_after = 30;

    let tcp_listener1 = new_tcp_listener();
    let tcp_listener2 = new_tcp_listener();
    let hosts = tcp_listener1.local_addr().unwrap().to_string() + "," + &tcp_listener2.local_addr().unwrap().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    listen_async(tcp_listener1);
    listen_async(tcp_listener2);

    thread::sleep(time::Duration::from_millis(250));
    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    assert_eq!(0, count.get());

    assert!( millis_elapsed(start)  >= wait_before + wait_after );
    assert!( millis_elapsed(start)  < timeout + wait_before + wait_after);
}

#[test]
fn should_fail_if_not_all_hosts_are_available() {
    let timeout = 100;
    let wait_before = 30;
    let wait_after = 30;

    let tcp_listener1 = new_tcp_listener();
    let hosts = tcp_listener1.local_addr().unwrap().to_string() + ",127.0.0.1:" + &free_port().to_string();
    let start = Instant::now();
    let sleeper = MillisSleeper{};

    let count : atomic_counter::RelaxedCounter = atomic_counter::RelaxedCounter::new(0);
    let mut fun = || { count.inc(); };
    assert_eq!(0, count.get());

    listen_async(tcp_listener1);

    thread::sleep(time::Duration::from_millis(250));
    wait::wait(&sleeper, &new_config(&hosts, timeout, wait_before, wait_after ), &mut  fun);

    assert_eq!(1, count.get());

    assert!( millis_elapsed(start)  >= wait_before + wait_after );
    assert!( millis_elapsed(start)  >= timeout + wait_before + wait_after);
}

fn on_timeout() {}

fn new_config(hosts: &str, timeout: u64, before: u64, after: u64) -> wait::Config {
    wait::Config {
        hosts: hosts.to_string(),
        timeout: timeout,
        wait_before: before,
        wait_after: after,
    }
}

fn new_tcp_listener() -> TcpListener {
    let loopback = Ipv4Addr::new(127, 0, 0, 1);
    let socket = SocketAddrV4::new(loopback, 0);
    TcpListener::bind(socket).unwrap()
}

fn listen_async(listener: TcpListener) {
    thread::spawn(move || {
            loop {
                match listener.accept() {
                    Ok(_) => {  println!("Connection received!"); }
                    Err(_) => { println!("Error in received connection!"); }
                }
            }
    });
}

fn free_port() -> u16 {
    new_tcp_listener().local_addr().unwrap().port()
}

fn millis_elapsed(start: Instant) -> u64 {
    let elapsed = start.elapsed().subsec_nanos() / 1000000;
    println!("Millis elapsed {}", elapsed);
    elapsed as u64
}

struct MillisSleeper {}

impl Sleeper for MillisSleeper {
    fn sleep(&self, duration: u64) {
        thread::sleep(Duration::from_millis(duration))
    }
}<|endoftext|>


<commit_before>//! The `ztext` module contains encoding functions to encode text in z-ascii characters.
//!

use super::zbytes::Bytes;

pub static ALPHABET: [char; 78] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',

    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',

    '\0', '^', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.',
    ',', '!', '?', '_', '#', '\'','"', '/', '\\','-', ':', '(', ')'];

/// encodes an string to z-characters
/// and returns the length of the used bytes
/// TODO: Only works with lower case letters
///
/// # Examples
///
/// ```ignore
/// let data = Bytes{bytes: Vec::new()};
/// let byteLength = data.encode("hello");
/// ```
pub fn encode(data: &mut Bytes, content: &str) -> u16 {
    let zchars: Vec<u8> = string_to_zchar(content);

    let mut two_bytes: u16 = 0;
    let len = zchars.len();
    for i in 0..len {
        let zasci_id =zchars[i];

        two_bytes |= shift(zasci_id as u16, i as u8);

        if i % 3 == 2 {
            data.write_u16(two_bytes, pos_to_index(i));
            two_bytes = 0;
        }

        // end of string
        if i == len -1 {
            if i % 3 != 2 {
                for j in (i % 3) + 1..3 {
                    two_bytes |= shift(0x05 as u16, j as u8);
                }

                data.write_u16(two_bytes, pos_to_index(i));
            }

            // end bit is written to the first bit of the next to last byte
            let end_index: usize = data.bytes.len() - 2 as usize;
            let mut end_byte: u8 = data.bytes[end_index];

            end_byte |= 0x80;
            data.write_byte(end_byte, end_index as usize);
        }
    }

    data.bytes.len() as u16
}

/// reads the content and converts it to a zasci vector
fn string_to_zchar(content: &str) -> Vec<u8> {
    println!("string_to_zchar: {:?}", content);
    let string_bytes = content.to_string().into_bytes();
        let mut zchars: Vec<u8> = Vec::new();
        for byte in string_bytes{
            let t_index = pos_in_alpha(byte as u8);
            if t_index != -1 {
                if byte == 0x0A {
                    // newline?
                    zchars.push(0x05);
                    zchars.push(7);
                } else if byte == 0x20 {
                    // space
                    //zchars.push(0x05);
                    //zchars.push(0);
                    zchars.push(0x00);
                } else {
                    if t_index > 51 {
                        // in A2
                        zchars.push(0x05);
                        zchars.push(t_index as u8 % 26 + 6);
                    } else if t_index < 26 {
                        // in A0
                        zchars.push(t_index as u8 % 26 + 6);
                    } else {
                        // in A1
                        zchars.push(0x04);
                        zchars.push(t_index as u8 % 26 + 6);
                    }
                }
            } else {
                if t_index <= 126 {
                    // ascii, but not in alphabet

                    // to change alphabet
                    zchars.push(0x05);

                    // for special char (10 bit z-ascii)
                    zchars.push(0x06);

                    // char as 10bit
                    //let zchar_10_bit: u16
                    zchars.push(byte >> 5);
                    zchars.push(byte & 0x1f);
                } else {
                    // unicode

                }
            }
        }
    zchars
}

/// shifts the z-char in a 2 bytes-array to the right position
/// shift_length has 3 possibilities: 10, 5, 0
/// an z-char use 5 bytes
/// look into two bytes:
/// ____byte one____ ____byte two____
/// 1 2 3 4 5 6  7 8 1 2 3  4 5 6 7 8
///   ^          ^          1
///   1 2 3 4 5  1 2 3 4 5  1 2 3 4 5
///   1. zchar   2. zchar   3. zchar
///   10         5          0
fn shift(zchar: u16, position: u8) -> u16 {
    let shift_length = 10 - (position % 3) * 5;
    zchar << shift_length
}

/// Returns the location of the character of the specified index in the zcode character array
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_in_alpha('c'), 2);
/// ```
fn pos_in_alpha(letter: u8) -> i8 {
    for i in 0..ALPHABET.len() {
        if ALPHABET[i] as u8 == letter {
            return i as i8
        }
    }

    return -1
}

/// position in the vector from the position of an character in the string
/// every 3 zchars encode() writes 2 bytes
/// for example "helloworld"
/// "h": nothing
/// "e": nothing
/// "l": write 2 bytes to position 0   (2 * 2/3))
/// "l": nothing
/// "o": nothing
/// "w": write 2 bytes to position 2   (2 * 5/3))
/// ...
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_to_index(5), 2);
/// ```
fn pos_to_index(position: usize) -> usize {
    2 * (position / 3)
}
<commit_msg>-support for circumflex<commit_after>//! The `ztext` module contains encoding functions to encode text in z-ascii characters.
//!

use super::zbytes::Bytes;

pub static ALPHABET: [char; 78] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',

    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',

    '\0', '\n', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.',
    ',', '!', '?', '_', '#', '\'','"', '/', '\\','-', ':', '(', ')'];

/// encodes an string to z-characters
/// and returns the length of the used bytes
/// TODO: Only works with lower case letters
///
/// # Examples
///
/// ```ignore
/// let data = Bytes{bytes: Vec::new()};
/// let byteLength = data.encode("hello");
/// ```
pub fn encode(data: &mut Bytes, content: &str) -> u16 {
    let zchars: Vec<u8> = string_to_zchar(content);

    let mut two_bytes: u16 = 0;
    let len = zchars.len();
    for i in 0..len {
        let zasci_id =zchars[i];

        two_bytes |= shift(zasci_id as u16, i as u8);

        if i % 3 == 2 {
            data.write_u16(two_bytes, pos_to_index(i));
            two_bytes = 0;
        }

        // end of string
        if i == len -1 {
            if i % 3 != 2 {
                for j in (i % 3) + 1..3 {
                    two_bytes |= shift(0x05 as u16, j as u8);
                }

                data.write_u16(two_bytes, pos_to_index(i));
            }

            // end bit is written to the first bit of the next to last byte
            let end_index: usize = data.bytes.len() - 2 as usize;
            let mut end_byte: u8 = data.bytes[end_index];

            end_byte |= 0x80;
            data.write_byte(end_byte, end_index as usize);
        }
    }

    data.bytes.len() as u16
}

/// reads the content and converts it to a zasci vector
fn string_to_zchar(content: &str) -> Vec<u8> {
    println!("string_to_zchar: {:?}", content);
    let string_bytes = content.to_string().into_bytes();
        let mut zchars: Vec<u8> = Vec::new();
        for byte in string_bytes{
            let t_index = pos_in_alpha(byte as u8);

            if t_index != -1 {
                if byte == 0x0A {
                    // newline?
                    zchars.push(0x05);
                    zchars.push(7);
                } else if byte == 0x20 {
                    // space
                    //zchars.push(0x05);
                    //zchars.push(0);
                    zchars.push(0x00);
                } else {
                    if t_index > 51 {
                        // in A2
                        zchars.push(0x05);
                        zchars.push(t_index as u8 % 26 + 6);
                    } else if t_index < 26 {
                        // in A0
                        zchars.push(t_index as u8 % 26 + 6);
                    } else {
                        // in A1
                        zchars.push(0x04);
                        zchars.push(t_index as u8 % 26 + 6);
                    }
                }
            } else {
                if t_index <= 126 {
                    // ascii, but not in alphabet

                    // to change alphabet
                    zchars.push(0x05);

                    // for special char (10 bit z-ascii)
                    zchars.push(0x06);

                    // char as 10bit
                    //let zchar_10_bit: u16
                    zchars.push(byte >> 5);
                    zchars.push(byte & 0x1f);
                } else {
                    // unicode

                }
            }
        }
    zchars
}

/// shifts the z-char in a 2 bytes-array to the right position
/// shift_length has 3 possibilities: 10, 5, 0
/// an z-char use 5 bytes
/// look into two bytes:
/// ____byte one____ ____byte two____
/// 1 2 3 4 5 6  7 8 1 2 3  4 5 6 7 8
///   ^          ^          1
///   1 2 3 4 5  1 2 3 4 5  1 2 3 4 5
///   1. zchar   2. zchar   3. zchar
///   10         5          0
fn shift(zchar: u16, position: u8) -> u16 {
    let shift_length = 10 - (position % 3) * 5;
    zchar << shift_length
}

/// Returns the location of the character of the specified index in the zcode character array
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_in_alpha('c'), 2);
/// ```
fn pos_in_alpha(letter: u8) -> i8 {
    for i in 0..ALPHABET.len() {
        if ALPHABET[i] as u8 == letter {
            return i as i8
        }
    }

    return -1
}

/// position in the vector from the position of an character in the string
/// every 3 zchars encode() writes 2 bytes
/// for example "helloworld"
/// "h": nothing
/// "e": nothing
/// "l": write 2 bytes to position 0   (2 * 2/3))
/// "l": nothing
/// "o": nothing
/// "w": write 2 bytes to position 2   (2 * 5/3))
/// ...
///
/// # Examples
///
/// ```ignore
/// assert_eq!(pos_to_index(5), 2);
/// ```
fn pos_to_index(position: usize) -> usize {
    2 * (position / 3)
}
<|endoftext|>


<commit_before>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    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 clap::{App, ArgGroup};
use clap::load_yaml;

use cargo_esr::esr_crate::CrateSearch;
use cargo_esr::esr_score::Scores;
use cargo_esr::esr_printer::EsrPrinter;

use std::env;

const LIMIT_LOW: usize = 5;
const LIMIT_HIGH: usize = 100;

fn check_limit(limit: &str) -> usize {
    match str::parse::<usize>(limit) {
        Ok(limit_num) => {
            let ll = LIMIT_LOW;
            let lh = LIMIT_HIGH;
            if limit_num < ll || limit_num > lh {
                EsrPrinter::limit_out_of_range(limit_num, ll, lh).println();
                std::process::exit(1);
            } else {
                limit_num
            }
        },
        Err(_) => {
            EsrPrinter::limit_invalid(limit).println();
            std::process::exit(1);
        },
    }
}

async fn run() {
    // clap
    let mut args: Vec<_> = env::args().collect();

    // cargo subcommand compat
    if args.len() >= 2 && args[1] == "esr" {
        args[0] = "cargo-esr".into();
        let _ = args.remove(1);
    }

    let yaml = load_yaml!("cargo-esr.yml");
    let search_or_score = ArgGroup::with_name("search-or-score")
        .args(&["search", "score", "gh-score"])
        .required(true);

    let search_by = ArgGroup::with_name("search-by")
        .args(&["search-by-relevance", "search-by-recent-downloads", "search-by-total-downloads"])
        .required(false);

    let score_filter = ArgGroup::with_name("score-filter")
        .args(&["crate-only", "repo-only"])
        .required(false);

    let clap_app = App::from_yaml(yaml)
        .group(search_or_score)
        .group(search_by)
        .group(score_filter);

    let m = clap_app.get_matches_from(args);

    let crate_only = m.is_present("crate-only");
    let repo_only = m.is_present("repo-only");
    let sort_positive = m.is_present("sort-positive");
    let results_limit = m.value_of("results-limit").unwrap_or("10");
    let search_limit = m.value_of("search-limit").unwrap_or("25");

    let search_by_relevance = m.is_present("search-by-relevance");
    let search_by_recent_downloads = m.is_present("search-by-recent-downloads");
    let search_by_total_downloads = m.is_present("search-by-total-downloads");

    if m.is_present("debug") {
        let _logger_setup = fern::Dispatch::new()
            .format(|out, message, _| {
                out.finish(format_args!(
                        "{} {}",
                        chrono::Local::now().format("[%H:%M:%S]"),
                        message
                ))
            })
            .level(log::LevelFilter::Off)
            //.level_for("reqwest", log::LevelFilter::Debug)
            .level_for("cargo_esr", log::LevelFilter::Debug)
            .chain(std::io::stderr())
            .apply();

        if _logger_setup.is_err() {
            EsrPrinter::err("Logger setup failed.");
            std::process::exit(1);
        }
    }

    let results_limit_num = check_limit(results_limit);
    let _search_limit_num = check_limit(search_limit);

    let mut gh_token = String::with_capacity(48);
    if m.value_of("gh-score").is_some() || !crate_only {
        if let Some(arg_token) = m.value_of("gh-token") {
            gh_token.push_str(arg_token);
        } else if let Ok(env_token) = std::env::var("CARGO_ESR_GH_TOKEN") {
            gh_token.push_str(&env_token);
        } else {
            EsrPrinter::no_token().println();
            std::process::exit(1);
        }
    }

    match (m.value_of("gh-score"), m.value_of("score"), m.values_of("search")) {
        (Some(repo_path), _, _)  => {
            match Scores::from_repo_with_token(repo_path.into(), gh_token).await {
                Ok(repo_scores) => repo_scores.detailed_scores().println(),
                Err(ref e) => {
                    EsrPrinter::repo_no_score(repo_path, e).println();
                    std::process::exit(1);
                },
            }
        },
        (_, Some(crate_name), _) => {
            let crates_scores_res = match (crate_only, repo_only) {
                (false, false) => Scores::from_id_with_token(crate_name.into(), gh_token).await,
                (true, false)  => Scores::from_id_crate_only(crate_name.into()).await,
                (false, true)  => Scores::from_id_with_token_repo_only(crate_name.into(), gh_token).await,
                (true, true)   => unreachable!(),
            };

            match crates_scores_res {
                Ok(crate_scores) => crate_scores.detailed_scores().println(),
                Err(ref e) => {
                    EsrPrinter::crate_no_score(crate_name, e).println();
                    std::process::exit(1);
                },
            }
        },

        (_, _, Some(search_pattern)) => {
            let search_str = search_pattern.fold(String::with_capacity(128), |s, p| s + p + "+")
                // In case a multi-word search is quoted
                .replace(' ', "+")
                .trim_end_matches('+')
                .to_string();

            let search_args = match search_str.is_empty() {
                true => match (search_by_relevance, search_by_total_downloads, search_by_recent_downloads) {
                    // default
                    (false, false, _) => "per_page=".to_string() + search_limit + "&sort=recent-downloads",
                    (_, true, _)      => "per_page=".to_string() + search_limit + "&sort=downloads",
                    (true, _, _)      => "per_page=".to_string() + search_limit,
                },
                false => match (search_by_relevance, search_by_total_downloads, search_by_recent_downloads) {
                    // default
                    (false, false, _) => "per_page=".to_string() + search_limit + "&q=" + &*search_str + "&sort=recent-downloads",
                    (_, true, _)      => "per_page=".to_string() + search_limit + "&q=" + &*search_str + "&sort=downloads",
                    (true, _, _)      => "per_page=".to_string() + search_limit + "&q=" + &*search_str,
                },

            };

            match CrateSearch::from_id_single_page(&search_args).await {
                Ok(search) => {
                    let crates = search.get_crates();

                    if crates.is_empty() {
                        EsrPrinter::search_no_results(&search_str).println();
                        std::process::exit(1);
                    }

                    let crates_scores_res = Scores::collect_scores(crates, &gh_token, crate_only, repo_only).await;
                    Scores::search_results(&*crates_scores_res, sort_positive, results_limit_num).println();
                },
                Err(ref e) => {
                    EsrPrinter::search_failed(&search_str, e).println();
                    std::process::exit(1);
                }
            }
        },

        (_, _, _) => unreachable!(),
    }
}

fn main() {
    smol::block_on(run());
}
<commit_msg>Fix slowness by setting SMOL_THREADS<commit_after>/*
    This file is a part of cargo-esr.

    Copyright (C) 2017 Mohammad AlSaleh <CE.Mohammad.AlSaleh at gmail.com>
    https://github.com/rust-alt/cargo-esr

    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 clap::{App, ArgGroup};
use clap::load_yaml;

use cargo_esr::esr_crate::CrateSearch;
use cargo_esr::esr_score::Scores;
use cargo_esr::esr_printer::EsrPrinter;

use std::env;

const LIMIT_LOW: usize = 5;
const LIMIT_HIGH: usize = 100;

fn check_limit(limit: &str) -> usize {
    match str::parse::<usize>(limit) {
        Ok(limit_num) => {
            let ll = LIMIT_LOW;
            let lh = LIMIT_HIGH;
            if limit_num < ll || limit_num > lh {
                EsrPrinter::limit_out_of_range(limit_num, ll, lh).println();
                std::process::exit(1);
            } else {
                limit_num
            }
        },
        Err(_) => {
            EsrPrinter::limit_invalid(limit).println();
            std::process::exit(1);
        },
    }
}

async fn run() {
    // clap
    let mut args: Vec<_> = env::args().collect();

    // cargo subcommand compat
    if args.len() >= 2 && args[1] == "esr" {
        args[0] = "cargo-esr".into();
        let _ = args.remove(1);
    }

    let yaml = load_yaml!("cargo-esr.yml");
    let search_or_score = ArgGroup::with_name("search-or-score")
        .args(&["search", "score", "gh-score"])
        .required(true);

    let search_by = ArgGroup::with_name("search-by")
        .args(&["search-by-relevance", "search-by-recent-downloads", "search-by-total-downloads"])
        .required(false);

    let score_filter = ArgGroup::with_name("score-filter")
        .args(&["crate-only", "repo-only"])
        .required(false);

    let clap_app = App::from_yaml(yaml)
        .group(search_or_score)
        .group(search_by)
        .group(score_filter);

    let m = clap_app.get_matches_from(args);

    let crate_only = m.is_present("crate-only");
    let repo_only = m.is_present("repo-only");
    let sort_positive = m.is_present("sort-positive");
    let results_limit = m.value_of("results-limit").unwrap_or("10");
    let search_limit = m.value_of("search-limit").unwrap_or("25");

    let search_by_relevance = m.is_present("search-by-relevance");
    let search_by_recent_downloads = m.is_present("search-by-recent-downloads");
    let search_by_total_downloads = m.is_present("search-by-total-downloads");

    if m.is_present("debug") {
        let _logger_setup = fern::Dispatch::new()
            .format(|out, message, _| {
                out.finish(format_args!(
                        "{} {}",
                        chrono::Local::now().format("[%H:%M:%S]"),
                        message
                ))
            })
            .level(log::LevelFilter::Off)
            //.level_for("reqwest", log::LevelFilter::Debug)
            .level_for("cargo_esr", log::LevelFilter::Debug)
            .chain(std::io::stderr())
            .apply();

        if _logger_setup.is_err() {
            EsrPrinter::err("Logger setup failed.");
            std::process::exit(1);
        }
    }

    let results_limit_num = check_limit(results_limit);
    let _search_limit_num = check_limit(search_limit);

    let mut gh_token = String::with_capacity(48);
    if m.value_of("gh-score").is_some() || !crate_only {
        if let Some(arg_token) = m.value_of("gh-token") {
            gh_token.push_str(arg_token);
        } else if let Ok(env_token) = std::env::var("CARGO_ESR_GH_TOKEN") {
            gh_token.push_str(&env_token);
        } else {
            EsrPrinter::no_token().println();
            std::process::exit(1);
        }
    }

    match (m.value_of("gh-score"), m.value_of("score"), m.values_of("search")) {
        (Some(repo_path), _, _)  => {
            match Scores::from_repo_with_token(repo_path.into(), gh_token).await {
                Ok(repo_scores) => repo_scores.detailed_scores().println(),
                Err(ref e) => {
                    EsrPrinter::repo_no_score(repo_path, e).println();
                    std::process::exit(1);
                },
            }
        },
        (_, Some(crate_name), _) => {
            let crates_scores_res = match (crate_only, repo_only) {
                (false, false) => Scores::from_id_with_token(crate_name.into(), gh_token).await,
                (true, false)  => Scores::from_id_crate_only(crate_name.into()).await,
                (false, true)  => Scores::from_id_with_token_repo_only(crate_name.into(), gh_token).await,
                (true, true)   => unreachable!(),
            };

            match crates_scores_res {
                Ok(crate_scores) => crate_scores.detailed_scores().println(),
                Err(ref e) => {
                    EsrPrinter::crate_no_score(crate_name, e).println();
                    std::process::exit(1);
                },
            }
        },

        (_, _, Some(search_pattern)) => {
            let search_str = search_pattern.fold(String::with_capacity(128), |s, p| s + p + "+")
                // In case a multi-word search is quoted
                .replace(' ', "+")
                .trim_end_matches('+')
                .to_string();

            let search_args = match search_str.is_empty() {
                true => match (search_by_relevance, search_by_total_downloads, search_by_recent_downloads) {
                    // default
                    (false, false, _) => "per_page=".to_string() + search_limit + "&sort=recent-downloads",
                    (_, true, _)      => "per_page=".to_string() + search_limit + "&sort=downloads",
                    (true, _, _)      => "per_page=".to_string() + search_limit,
                },
                false => match (search_by_relevance, search_by_total_downloads, search_by_recent_downloads) {
                    // default
                    (false, false, _) => "per_page=".to_string() + search_limit + "&q=" + &*search_str + "&sort=recent-downloads",
                    (_, true, _)      => "per_page=".to_string() + search_limit + "&q=" + &*search_str + "&sort=downloads",
                    (true, _, _)      => "per_page=".to_string() + search_limit + "&q=" + &*search_str,
                },

            };

            match CrateSearch::from_id_single_page(&search_args).await {
                Ok(search) => {
                    let crates = search.get_crates();

                    if crates.is_empty() {
                        EsrPrinter::search_no_results(&search_str).println();
                        std::process::exit(1);
                    }

                    let crates_scores_res = Scores::collect_scores(crates, &gh_token, crate_only, repo_only).await;
                    Scores::search_results(&*crates_scores_res, sort_positive, results_limit_num).println();
                },
                Err(ref e) => {
                    EsrPrinter::search_failed(&search_str, e).println();
                    std::process::exit(1);
                }
            }
        },

        (_, _, _) => unreachable!(),
    }
}

fn main() {
    env::set_var("SMOL_THREADS", "32");
    smol::block_on(run());
}
<|endoftext|>


<commit_before>//! Job management on Windows for bootstrapping
//!
//! Most of the time when you're running a build system (e.g., make) you expect
//! Ctrl-C or abnormal termination to actually terminate the entire tree of
//! process in play, not just the one at the top. This currently works "by
//! default" on Unix platforms because Ctrl-C actually sends a signal to the
//! *process group* rather than the parent process, so everything will get torn
//! down. On Windows, however, this does not happen and Ctrl-C just kills the
//! parent process.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!
//!
//! Unfortunately most of the time the build system is actually called from a
//! python wrapper (which manages things like building the build system) so this
//! all doesn't quite cut it so far. To go the last mile we duplicate the job
//! object handle into our parent process (a python process probably) and then
//! close our own handle. This means that the only handle to the job object
//! resides in the parent python process, so when python dies the whole build
//! system dies (as one would probably expect!).
//!
//! Note that this module has a #[cfg(windows)] above it as none of this logic
//! is required on Unix.

#![allow(nonstandard_style, dead_code)]

use crate::Build;
use std::env;
use std::io;
use std::mem;
use std::ptr;

use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
use winapi::um::errhandlingapi::SetErrorMode;
use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
use winapi::um::winnt::{
    JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
};

pub unsafe fn setup(build: &mut Build) {
    // Enable the Windows Error Reporting dialog which msys disables,
    // so we can JIT debug rustc
    let mode = SetErrorMode(0);
    SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);

    // Create a new job object for us to use
    let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
    assert!(!job.is_null(), "{}", io::Error::last_os_error());

    // Indicate that when all handles to the job object are gone that all
    // process in the object should be killed. Note that this includes our
    // entire process tree by default because we've added ourselves and our
    // children will reside in the job by default.
    let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
    info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    if build.config.low_priority {
        info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
    }
    let r = SetInformationJobObject(
        job,
        JobObjectExtendedLimitInformation,
        &mut info as *mut _ as LPVOID,
        mem::size_of_val(&info) as DWORD,
    );
    assert!(r != 0, "{}", io::Error::last_os_error());

    // Assign our process to this job object. Note that if this fails, one very
    // likely reason is that we are ourselves already in a job object! This can
    // happen on the build bots that we've got for Windows, or if just anyone
    // else is instrumenting the build. In this case we just bail out
    // immediately and assume that they take care of it.
    //
    // Also note that nested jobs (why this might fail) are supported in recent
    // versions of Windows, but the version of Windows that our bots are running
    // at least don't support nested job objects.
    let r = AssignProcessToJobObject(job, GetCurrentProcess());
    if r == 0 {
        CloseHandle(job);
        return;
    }

    // If we've got a parent process (e.g., the python script that called us)
    // then move ownership of this job object up to them. That way if the python
    // script is killed (e.g., via ctrl-c) then we'll all be torn down.
    //
    // If we don't have a parent (e.g., this was run directly) then we
    // intentionally leak the job object handle. When our process exits
    // (normally or abnormally) it will close the handle implicitly, causing all
    // processes in the job to be cleaned up.
    let pid = match env::var("BOOTSTRAP_PARENT_ID") {
        Ok(s) => s,
        Err(..) => return,
    };

    let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
    assert!(
        !parent.is_null(),
        "PID `{}` doesn't seem to exist: {}",
        pid,
        io::Error::last_os_error()
    );
    let mut parent_handle = ptr::null_mut();
    let r = DuplicateHandle(
        GetCurrentProcess(),
        job,
        parent,
        &mut parent_handle,
        0,
        FALSE,
        DUPLICATE_SAME_ACCESS,
    );

    // If this failed, well at least we tried! An example of DuplicateHandle
    // failing in the past has been when the wrong python2 package spawned this
    // build system (e.g., the `python2` package in MSYS instead of
    // `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
    // mode" here is that we only clean everything up when the build system
    // dies, not when the python parent does, so not too bad.
    if r != 0 {
        CloseHandle(job);
    }
}
<commit_msg>Rollup merge of #87185 - waterlens:issue-86499-fix, r=Mark-Simulacrum<commit_after>//! Job management on Windows for bootstrapping
//!
//! Most of the time when you're running a build system (e.g., make) you expect
//! Ctrl-C or abnormal termination to actually terminate the entire tree of
//! process in play, not just the one at the top. This currently works "by
//! default" on Unix platforms because Ctrl-C actually sends a signal to the
//! *process group* rather than the parent process, so everything will get torn
//! down. On Windows, however, this does not happen and Ctrl-C just kills the
//! parent process.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!
//!
//! Unfortunately most of the time the build system is actually called from a
//! python wrapper (which manages things like building the build system) so this
//! all doesn't quite cut it so far. To go the last mile we duplicate the job
//! object handle into our parent process (a python process probably) and then
//! close our own handle. This means that the only handle to the job object
//! resides in the parent python process, so when python dies the whole build
//! system dies (as one would probably expect!).
//!
//! Note that this module has a #[cfg(windows)] above it as none of this logic
//! is required on Unix.

#![allow(nonstandard_style, dead_code)]

use crate::Build;
use std::env;
use std::io;
use std::mem;
use std::ptr;

use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
use winapi::um::errhandlingapi::SetErrorMode;
use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
use winapi::um::winnt::{
    JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
};

pub unsafe fn setup(build: &mut Build) {
    // Enable the Windows Error Reporting dialog which msys disables,
    // so we can JIT debug rustc
    let mode = SetErrorMode(0);
    SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);

    // Create a new job object for us to use
    let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
    assert!(!job.is_null(), "{}", io::Error::last_os_error());

    // Indicate that when all handles to the job object are gone that all
    // process in the object should be killed. Note that this includes our
    // entire process tree by default because we've added ourselves and our
    // children will reside in the job by default.
    let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
    info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    if build.config.low_priority {
        info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
        info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
    }
    let r = SetInformationJobObject(
        job,
        JobObjectExtendedLimitInformation,
        &mut info as *mut _ as LPVOID,
        mem::size_of_val(&info) as DWORD,
    );
    assert!(r != 0, "{}", io::Error::last_os_error());

    // Assign our process to this job object. Note that if this fails, one very
    // likely reason is that we are ourselves already in a job object! This can
    // happen on the build bots that we've got for Windows, or if just anyone
    // else is instrumenting the build. In this case we just bail out
    // immediately and assume that they take care of it.
    //
    // Also note that nested jobs (why this might fail) are supported in recent
    // versions of Windows, but the version of Windows that our bots are running
    // at least don't support nested job objects.
    let r = AssignProcessToJobObject(job, GetCurrentProcess());
    if r == 0 {
        CloseHandle(job);
        return;
    }

    // If we've got a parent process (e.g., the python script that called us)
    // then move ownership of this job object up to them. That way if the python
    // script is killed (e.g., via ctrl-c) then we'll all be torn down.
    //
    // If we don't have a parent (e.g., this was run directly) then we
    // intentionally leak the job object handle. When our process exits
    // (normally or abnormally) it will close the handle implicitly, causing all
    // processes in the job to be cleaned up.
    let pid = match env::var("BOOTSTRAP_PARENT_ID") {
        Ok(s) => s,
        Err(..) => return,
    };

    let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());

    // If we get a null parent pointer here, it is possible that either
    // we have got an invalid pid or the parent process has been closed.
    // Since the first case rarely happens
    // (only when wrongly setting the environmental variable),
    // so it might be better to improve the experience of the second case
    // when users have interrupted the parent process and we don't finish
    // duplicating the handle yet.
    // We just need close the job object if that occurs.
    if parent.is_null() {
        CloseHandle(job);
        return;
    }

    let mut parent_handle = ptr::null_mut();
    let r = DuplicateHandle(
        GetCurrentProcess(),
        job,
        parent,
        &mut parent_handle,
        0,
        FALSE,
        DUPLICATE_SAME_ACCESS,
    );

    // If this failed, well at least we tried! An example of DuplicateHandle
    // failing in the past has been when the wrong python2 package spawned this
    // build system (e.g., the `python2` package in MSYS instead of
    // `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
    // mode" here is that we only clean everything up when the build system
    // dies, not when the python parent does, so not too bad.
    if r != 0 {
        CloseHandle(job);
    }
}
<|endoftext|>


<commit_before>use std::io::{File, Open, ReadWrite};
use std::io::IoResult;
use super::Position;
use super::Range;

pub struct Buffer {
    data: String,
    file: Option<File>,
    cursor: Position,
    selection: Option<Range>,
}

pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, ReadWrite) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    // Ensure that the data has enough room to grow without reallocating.
    let data_length = data.len();
    data.reserve(data_length * 2);

    // Create a new buffer using the loaded data, file, and other defaults.
    Ok(Buffer{ data: data, file: Some(file), cursor: Position{ line: 0, offset: 0 }, selection: None })
}

#[test]
fn from_file_loads_file_into_buffer() {
    match from_file(&Path::new("tests/sample/file")) {
        Ok(buffer) => assert_eq!(buffer.data, "it works!\n"),
        Err(error) => panic!(error),
    }
}
<commit_msg>Move buffer tests into a tests submodule.<commit_after>use std::io::{File, Open, ReadWrite};
use std::io::IoResult;
use super::Position;
use super::Range;

pub struct Buffer {
    data: String,
    file: Option<File>,
    cursor: Position,
    selection: Option<Range>,
}

pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, ReadWrite) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    // Ensure that the data has enough room to grow without reallocating.
    let data_length = data.len();
    data.reserve(data_length * 2);

    // Create a new buffer using the loaded data, file, and other defaults.
    Ok(Buffer{ data: data, file: Some(file), cursor: Position{ line: 0, offset: 0 }, selection: None })
}

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

    #[test]
    fn from_file_loads_file_into_buffer() {
        match from_file(&Path::new("tests/sample/file")) {
            Ok(buffer) => assert_eq!(buffer.data, "it works!\n"),
            Err(error) => panic!(error),
        }
    }
}
<|endoftext|>


<commit_before>use super::Options;
use toml::value::{Table, Value};

mod elaborate_workspace;
mod pkg_status;
mod temp_project;
pub use self::elaborate_workspace::ElaborateWorkspace;
pub use self::pkg_status::*;
pub use self::temp_project::TempProject;

/// A continent struct for quick parsing and manipulating manifest
#[derive(Debug, serde_derive::Serialize, serde_derive::Deserialize)]
struct Manifest {
    #[serde(
        rename = "cargo-features",
        skip_serializing_if = "Option::is_none"
    )]
    pub cargo_features: Option<Value>,
    #[serde(serialize_with = "::toml::ser::tables_last")]
    pub package: Table,
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub dependencies: Option<Table>,
    #[serde(
        rename = "dev-dependencies",
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub dev_dependencies: Option<Table>,
    #[serde(
        rename = "build-dependencies",
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub build_dependencies: Option<Table>,
    pub lib: Option<Table>,
    pub bin: Option<Vec<Table>>,
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub workspace: Option<Table>,
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub target: Option<Table>,
    pub features: Option<Value>,
}

impl Manifest {
    pub fn name(&self) -> String {
        match self.package["name"] {
            Value::String(ref name) => name.clone(),
            _ => unreachable!(),
        }
    }
}

pub fn opt_tables_last<S>(data: &Option<Table>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: ::serde::ser::Serializer,
{
    match *data {
        Some(ref d) => ::toml::ser::tables_last(d, serializer),
        None => unreachable!(),
    }
}
<commit_msg>Fix lint<commit_after>use super::Options;
use toml::value::{Table, Value};

mod elaborate_workspace;
mod pkg_status;
mod temp_project;
pub use self::elaborate_workspace::ElaborateWorkspace;
pub use self::pkg_status::*;
pub use self::temp_project::TempProject;

/// A continent struct for quick parsing and manipulating manifest
#[derive(Debug, serde_derive::Serialize, serde_derive::Deserialize)]
struct Manifest {
    #[serde(rename = "cargo-features", skip_serializing_if = "Option::is_none")]
    pub cargo_features: Option<Value>,
    #[serde(serialize_with = "::toml::ser::tables_last")]
    pub package: Table,
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub dependencies: Option<Table>,
    #[serde(
        rename = "dev-dependencies",
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub dev_dependencies: Option<Table>,
    #[serde(
        rename = "build-dependencies",
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub build_dependencies: Option<Table>,
    pub lib: Option<Table>,
    pub bin: Option<Vec<Table>>,
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub workspace: Option<Table>,
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "opt_tables_last"
    )]
    pub target: Option<Table>,
    pub features: Option<Value>,
}

impl Manifest {
    pub fn name(&self) -> String {
        match self.package["name"] {
            Value::String(ref name) => name.clone(),
            _ => unreachable!(),
        }
    }
}

pub fn opt_tables_last<S>(data: &Option<Table>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: ::serde::ser::Serializer,
{
    match *data {
        Some(ref d) => ::toml::ser::tables_last(d, serializer),
        None => unreachable!(),
    }
}
<|endoftext|>


<commit_before>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use physics::Dimensions;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3};
use specs;
use gfx_app::graphics::load_texture;
use character::gfx_macros::{pipe, VertexData, CharacterSheet, Position};
use game::gfx_macros::Projection;
use game::constants::{ASPECT_RATIO, VIEW_DISTANCE};
use terrain::controls::TerrainInputState;
use character::controls::CharacterInputState;
use data;
use character::orientation::Orientation;

pub mod gfx_macros;
pub mod character;
pub mod orientation;
pub mod controls;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

#[derive(Debug)]
pub struct CharacterData {
  data: [f32; 6]
}

impl CharacterData {
  pub fn new(data: [f32; 6]) -> CharacterData {
    CharacterData { data: data }
  }
}

impl VertexData {
  fn new(pos: [f32; 3], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos: pos,
      buf_pos: buf_pos,
    }
  }
}

#[derive(Debug)]
pub struct CharacterSprite {
  character_idx: usize
}

impl CharacterSprite {
  pub fn new() -> CharacterSprite {
    CharacterSprite {
      character_idx: 0,
    }
  }

  pub fn update(&mut self) {
    if self.character_idx < 12 {
      self.character_idx = self.character_idx + 1;
    } else {
      self.character_idx = 0;
    }
  }
}

impl specs::Component for CharacterSprite {
  type Storage = specs::VecStorage<CharacterSprite>;
}

#[derive(Debug)]
pub struct Drawable {
  projection: Projection,
  position: Position,
  orientation: Orientation,
}

impl Drawable {
  pub fn new() -> Drawable {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );

    let aspect_ratio: f32 = ASPECT_RATIO;

    Drawable {
      projection: Projection {
        model: Matrix4::from(view).into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(60.0f32), aspect_ratio, 0.1, 4000.0).into(),
      },
      position: Position {
        position: [0.0, 0.0],
      },
      orientation: Orientation::Right
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, position: &CharacterInputState) {
    self.projection = *world_to_clip;
    let new_position = Position {
      position: [position.x_movement, position.y_movement]
    };

    let dx = new_position.position[0] - self.position.position[0];
    let dy = new_position.position[1] - self.position.position[1];
    self.orientation =
    if dx == 0.0 && dy < 0.0       { Orientation::Up }
    else if dx > 0.0 && dy < 0.0   { Orientation::UpRight }
    else if dx < 0.0 && dy < 0.0   { Orientation::UpLeft }
    else if dx == 0.0 && dy == 0.0 { Orientation::Right }
    else if dx > 0.0 && dy == 0.0  { Orientation::Right }
    else if dx < 0.0 && dy == 0.0  { Orientation::Left }
    else if dx == 0.0 && dy > 0.0  { Orientation::Down }
    else if dx > 0.0 && dy > 0.0   { Orientation::DownRight }
    else if dx < 0.0 && dy > 0.0   { Orientation::DownLeft }
    else { unreachable!() };
    self.position = new_position;
  }
}

impl specs::Component for Drawable {
  type Storage = specs::VecStorage<Drawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-40.0, -64.0, 0.0], [0.0, 1.0]),
        VertexData::new([40.0, -64.0, 0.0], [1.0, 1.0]),
        VertexData::new([40.0, 64.0, 0.0], [1.0, 0.0]),
        VertexData::new([-40.0, -64.0, 0.0], [0.0, 1.0]),
        VertexData::new([40.0, 64.0, 0.0], [1.0, 0.0]),
        VertexData::new([-40.0, 64.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let char_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: data
    }
  }

  fn get_next_sprite(&self, character_idx: usize, orientation: &Orientation) -> CharacterSheet {
    let sprite_idx = (*orientation as usize * 28 + character_idx) as usize;
    let char_sprite = &self.data[sprite_idx];

    let charsheet_total_width = 11422f32;
    let offset = 2.0;
    let elements_x = charsheet_total_width / (char_sprite.data[2] + offset);
    let char = CharacterSheet {
      div: elements_x,
      index: sprite_idx as f32
    };
    println!("{:?}", char);
    char
  }

  pub fn draw<C>(&mut self,
                 drawable: &Drawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb, &mut self.get_next_sprite(character.character_idx, &drawable.orientation));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim, mut terrain_input, mut character_input) =
      arg.fetch(|w| (
        w.write::<Drawable>(),
        w.read_resource::<Dimensions>(),
        w.write::<TerrainInputState>(),
        w.write::<CharacterInputState>()));

    for (c, i, ci) in (&mut character, &mut terrain_input, &mut character_input).join() {
      let world_to_clip = dim.world_to_projection(i);
      c.update(&world_to_clip, ci);
    }
  }
}
<commit_msg>Update character orientations<commit_after>use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use physics::Dimensions;
use cgmath;
use cgmath::{Matrix4, Point3, Vector3};
use specs;
use gfx_app::graphics::load_texture;
use character::gfx_macros::{pipe, VertexData, CharacterSheet, Position};
use game::gfx_macros::Projection;
use game::constants::{ASPECT_RATIO, VIEW_DISTANCE};
use terrain::controls::TerrainInputState;
use character::controls::CharacterInputState;
use data;
use character::orientation::Orientation;

pub mod gfx_macros;
pub mod character;
pub mod orientation;
pub mod controls;

const SHADER_VERT: &'static [u8] = include_bytes!("character.v.glsl");
const SHADER_FRAG: &'static [u8] = include_bytes!("character.f.glsl");

#[derive(Debug)]
pub struct CharacterData {
  data: [f32; 6]
}

impl CharacterData {
  pub fn new(data: [f32; 6]) -> CharacterData {
    CharacterData { data: data }
  }
}

impl VertexData {
  fn new(pos: [f32; 3], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos: pos,
      buf_pos: buf_pos,
    }
  }
}

#[derive(Debug)]
pub struct CharacterSprite {
  character_idx: usize
}

impl CharacterSprite {
  pub fn new() -> CharacterSprite {
    CharacterSprite {
      character_idx: 0,
    }
  }

  pub fn update(&mut self) {
    if self.character_idx < 12 {
      self.character_idx = self.character_idx + 1;
    } else {
      self.character_idx = 0;
    }
  }
}

impl specs::Component for CharacterSprite {
  type Storage = specs::VecStorage<CharacterSprite>;
}

#[derive(Debug)]
pub struct Drawable {
  projection: Projection,
  position: Position,
  orientation: Orientation,
}

impl Drawable {
  pub fn new() -> Drawable {
    let view: Matrix4<f32> = Matrix4::look_at(
      Point3::new(0.0, 0.0, VIEW_DISTANCE),
      Point3::new(0.0, 0.0, 0.0),
      Vector3::unit_y(),
    );

    let aspect_ratio: f32 = ASPECT_RATIO;

    Drawable {
      projection: Projection {
        model: Matrix4::from(view).into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(60.0f32), aspect_ratio, 0.1, 4000.0).into(),
      },
      position: Position {
        position: [0.0, 0.0],
      },
      orientation: Orientation::Right
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, position: &CharacterInputState) {
    self.projection = *world_to_clip;
    let new_position = Position {
      position: [position.x_movement, position.y_movement]
    };

    let dx = new_position.position[0] - self.position.position[0];
    let dy = new_position.position[1] - self.position.position[1];
    self.orientation =
    if dx == 0.0 && dy < 0.0       { Orientation::Down }
    else if dx > 0.0 && dy < 0.0   { Orientation::DownRight }
    else if dx < 0.0 && dy < 0.0   { Orientation::DownLeft }
    else if dx == 0.0 && dy == 0.0 { Orientation::Right }
    else if dx > 0.0 && dy == 0.0  { Orientation::Right }
    else if dx < 0.0 && dy == 0.0  { Orientation::Left }
    else if dx == 0.0 && dy > 0.0  { Orientation::Up }
    else if dx > 0.0 && dy > 0.0   { Orientation::UpRight }
    else if dx < 0.0 && dy > 0.0   { Orientation::UpLeft }
    else { unreachable!() };
    self.position = new_position;
  }
}

impl specs::Component for Drawable {
  type Storage = specs::VecStorage<Drawable>;
}

pub struct DrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, pipe::Data<R>>,
  data: Vec<CharacterData>,
}

impl<R: gfx::Resources> DrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> DrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tilesheet_bytes = &include_bytes!("../../assets/character.png")[..];

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-40.0, -64.0, 0.0], [0.0, 1.0]),
        VertexData::new([40.0, -64.0, 0.0], [1.0, 1.0]),
        VertexData::new([40.0, 64.0, 0.0], [1.0, 0.0]),
        VertexData::new([-40.0, -64.0, 0.0], [0.0, 1.0]),
        VertexData::new([40.0, 64.0, 0.0], [1.0, 0.0]),
        VertexData::new([-40.0, 64.0, 0.0], [0.0, 0.0]),
      ];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let char_texture = load_texture(factory, tilesheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              pipe::new())
      .unwrap();

    let pipeline_data = pipe::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    DrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: data
    }
  }

  fn get_next_sprite(&self, character_idx: usize, orientation: &Orientation) -> CharacterSheet {
    let sprite_idx = (*orientation as usize * 28 + character_idx) as usize;
    let char_sprite = &self.data[sprite_idx];

    let charsheet_total_width = 11422f32;
    let offset = 2.0;
    let elements_x = charsheet_total_width / (char_sprite.data[2] + offset);
    let char = CharacterSheet {
      div: elements_x,
      index: sprite_idx as f32
    };
    println!("{:?}", char);
    char
  }

  pub fn draw<C>(&mut self,
                 drawable: &Drawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb, &mut self.get_next_sprite(character.character_idx, &drawable.orientation));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<C> specs::System<C> for PreDrawSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;
    let (mut character, dim, mut terrain_input, mut character_input) =
      arg.fetch(|w| (
        w.write::<Drawable>(),
        w.read_resource::<Dimensions>(),
        w.write::<TerrainInputState>(),
        w.write::<CharacterInputState>()));

    for (c, i, ci) in (&mut character, &mut terrain_input, &mut character_input).join() {
      let world_to_clip = dim.world_to_projection(i);
      c.update(&world_to_clip, ci);
    }
  }
}
<|endoftext|>