<commit_before>use std::cell::{Cell, RefCell};
use std::io::{self, ErrorKind};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::sync::mpsc;
use std::time::Instant;

use mio;
use mio::channel::SendError;
use slab::Slab;
use futures::{Future, Task, TaskHandle, Poll};
use futures_io::Ready;

use slot::{self, Slot};

static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;
scoped_thread_local!(static CURRENT_LOOP: Loop);

const SLAB_CAPACITY: usize = 1024 * 64;

/// 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.
// TODO: expand this
pub struct Loop {
    id: usize,
    active: Cell<bool>,
    io: mio::Poll,
    tx: mio::channel::Sender<Message>,
    rx: mio::channel::Receiver<Message>,
    dispatch: RefCell<Slab<Scheduled, 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 LoopHandle {
    id: usize,
    tx: mio::channel::Sender<Message>,
}

struct Scheduled {
    source: IoSource,
    waiter: Option<TaskHandle>,
}

enum Message {
    AddSource(IoSource, Arc<Slot<io::Result<usize>>>),
    DropSource(usize),
    Schedule(usize, TaskHandle),
    Deschedule(usize),
    Shutdown,
}

pub struct Source<E: ?Sized> {
    readiness: AtomicUsize,
    io: E,
}

pub type IoSource = Arc<Source<mio::Evented + Sync + Send>>;

fn register(poll: &mio::Poll,
            token: usize,
            sched: &Scheduled) -> io::Result<()> {
    poll.register(&sched.source.io,
                  mio::Token(token),
                  mio::EventSet::readable() | mio::EventSet::writable(),
                  mio::PollOpt::edge())
}

fn deregister(poll: &mio::Poll, sched: &Scheduled) {
    // TODO: handle error
    poll.deregister(&sched.source.io).unwrap();
}

impl Loop {
    /// Creates a new event loop, returning any error that happened during the
    /// creation.
    pub fn new() -> io::Result<Loop> {
        let (tx, rx) = mio::channel::from_std_channel(mpsc::channel());
        let io = try!(mio::Poll::new());
        try!(io.register(&rx,
                         mio::Token(0),
                         mio::EventSet::readable(),
                         mio::PollOpt::edge()));
        Ok(Loop {
            id: NEXT_LOOP_ID.fetch_add(1, Ordering::Relaxed),
            active: Cell::new(true),
            io: io,
            tx: tx,
            rx: rx,
            dispatch: RefCell::new(Slab::new_starting_at(1, SLAB_CAPACITY)),
        })
    }

    /// Generates a handle to this event loop used to construct I/O objects and
    /// send messages.
    ///
    /// Handles to an event loop are cloneable as well and clones will always
    /// refer to the same event loop.
    pub fn handle(&self) -> LoopHandle {
        LoopHandle {
            id: self.id,
            tx: self.tx.clone(),
        }
    }

    /// Runs a future until completion, driving the event loop while we're
    /// otherwise waiting for the future to complete.
    ///
    /// Returns the value that the future resolves to.
    pub fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error> {
        let (tx_res, rx_res) = mpsc::channel();
        let handle = self.handle();
        f.then(move |res| {
            handle.shutdown();
            tx_res.send(res)
        }).forget();

        self._run();

        rx_res.recv().unwrap()
    }

    fn _run(&mut self) {
        let mut events = mio::Events::new();
        self.active.set(true);
        while self.active.get() {
            let amt;
            // On Linux, Poll::poll is epoll_wait, which may return EINTR if a
            // ptracer attaches. This retry loop prevents crashing when
            // attaching strace, or similar.
            let start = Instant::now();
            loop {
                match self.io.poll(&mut events, None) {
                    Ok(a) => {
                        amt = a;
                        break;
                    }
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                    err @ Err(_) => {
                        err.unwrap();
                    }
                }
            }
            debug!("loop poll - {:?}", start.elapsed());

            // TODO: coalesce token sets for a given Wake?
            let start = Instant::now();
            for i in 0..events.len() {
                let event = events.get(i).unwrap();
                let token = usize::from(event.token());

                if token == 0 {
                    debug!("consuming notification queue");
                    self.consume_queue();
                    continue
                }

                let mut waiter = None;

                if let Some(sched) = self.dispatch.borrow_mut().get_mut(token) {
                    waiter = sched.waiter.take();
                    if event.kind().is_readable() {
                        sched.source.readiness.fetch_or(1, Ordering::Relaxed);
                    }
                    if event.kind().is_writable() {
                        sched.source.readiness.fetch_or(2, Ordering::Relaxed);
                    }
                } else {
                    debug!("notified on {} which no longer exists", token);
                }
                debug!("dispatching {:?} {:?}", event.token(), event.kind());

                CURRENT_LOOP.set(&self, move || {
                    match waiter {
                        Some(waiter) => waiter.notify(),
                        None => debug!("no waiter"),
                    }
                });
            }

            debug!("loop process - {} events, {:?}", amt, start.elapsed());
        }

        debug!("loop is done!");
    }

    fn add_source(&self, source: IoSource) -> io::Result<usize> {
        let sched = Scheduled {
            source: source,
            waiter: None,
        };
        let mut dispatch = self.dispatch.borrow_mut();
        if dispatch.vacant_entry().is_none() {
            let amt = dispatch.count();
            dispatch.grow(amt);
        }
        let entry = dispatch.vacant_entry().unwrap();
        try!(register(&self.io, entry.index(), &sched));
        Ok(entry.insert(sched).index())
    }

    fn drop_source(&self, token: usize) {
        let sched = self.dispatch.borrow_mut().remove(token).unwrap();
        deregister(&self.io, &sched);
    }

    fn schedule(&self, token: usize, wake: TaskHandle) {
        let to_call = {
            let mut dispatch = self.dispatch.borrow_mut();
            let sched = dispatch.get_mut(token).unwrap();
            if sched.source.readiness.load(Ordering::Relaxed) != 0 {
                sched.waiter = None;
                Some(wake)
            } else {
                sched.waiter = Some(wake);
                None
            }
        };
        if let Some(to_call) = to_call {
            to_call.notify();
        }
    }

    fn deschedule(&self, token: usize) {
        let mut dispatch = self.dispatch.borrow_mut();
        dispatch.get_mut(token).unwrap();
        // TODO: was... this supposed to do something?
    }

    fn consume_queue(&self) {
        while let Ok(msg) = self.rx.try_recv() {
            self.notify(msg);
        }
    }

    fn notify(&self, msg: Message) {
        match msg {
            Message::AddSource(source, slot) => {
                // This unwrap() should always be ok as we're the only producer
                slot.try_produce(self.add_source(source))
                    .ok().expect("interference with try_produce");
            }
            Message::DropSource(tok) => self.drop_source(tok),
            Message::Schedule(tok, wake) => self.schedule(tok, wake),
            Message::Deschedule(tok) => self.deschedule(tok),
            Message::Shutdown => self.active.set(false),
        }
    }
}

impl LoopHandle {
    fn send(&self, msg: Message) {
        self.with_loop(|lp| {
            match lp {
                Some(lp) => {
                    // Need to execute all existing requests first, to ensure
                    // that our message is processed "in order"
                    lp.consume_queue();
                    lp.notify(msg);
                }
                None => {
                    match self.tx.send(msg) {
                        Ok(()) => {}

                        // This should only happen when there was an error
                        // writing to the pipe to wake up the event loop,
                        // hopefully that never happens
                        Err(SendError::Io(e)) => {
                            panic!("error sending message to event loop: {}", e)
                        }

                        // If we're still sending a message to the event loop
                        // after it's closed, then that's bad!
                        Err(SendError::Disconnected(_)) => {
                            panic!("event loop is no longer available")
                        }
                    }
                }
            }
        })
    }

    fn with_loop<F, R>(&self, f: F) -> R
        where F: FnOnce(Option<&Loop>) -> R
    {
        if CURRENT_LOOP.is_set() {
            CURRENT_LOOP.with(|lp| {
                if lp.id == self.id {
                    f(Some(lp))
                } else {
                    f(None)
                }
            })
        } else {
            f(None)
        }
    }

    /// Add a new source to an event loop, returning a future which will resolve
    /// to the token that can be used to identify this source.
    ///
    /// When a new I/O object is created it needs to be communicated to the
    /// event loop to ensure that it's registered and ready to receive
    /// notifications. The event loop with then respond with a unique token that
    /// this handle can be identified with (the resolved value of the returned
    /// future).
    ///
    /// This token is then passed in turn to each of the methods below to
    /// interact with notifications on the I/O object itself.
    ///
    /// # Panics
    ///
    /// The returned future will panic if the event loop this handle is
    /// associated with has gone away, or if there is an error communicating
    /// with the event loop.
    pub fn add_source(&self, source: IoSource) -> AddSource {
        AddSource {
            loop_handle: self.clone(),
            source: Some(source),
            result: None,
        }
    }

    fn add_source_(&self, source: IoSource, slot: Arc<Slot<io::Result<usize>>>) {
        self.send(Message::AddSource(source, slot));
    }

    /// Begin listening for events on an event loop.
    ///
    /// Once an I/O object has been registered with the event loop through the
    /// `add_source` method, this method can be used with the assigned token to
    /// begin awaiting notifications.
    ///
    /// The `dir` argument indicates how the I/O object is expected to be
    /// awaited on (either readable or writable) and the `wake` callback will be
    /// invoked. Note that one the `wake` callback is invoked once it will not
    /// be invoked again, it must be re-`schedule`d to continue receiving
    /// notifications.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn schedule(&self, tok: usize, task: &mut Task) {
        // TODO: plumb through `&mut Task` if we're on the event loop
        self.send(Message::Schedule(tok, task.handle().clone()));
    }

    /// Stop listening for events on an event loop.
    ///
    /// Once a callback has been scheduled with the `schedule` method, it can be
    /// unregistered from the event loop with this method. This method does not
    /// guarantee that the callback will not be invoked if it hasn't already,
    /// but a best effort will be made to ensure it is not called.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn deschedule(&self, tok: usize) {
        self.send(Message::Deschedule(tok));
    }

    /// Unregister all information associated with a token on an event loop,
    /// deallocating all internal resources assigned to the given token.
    ///
    /// This method should be called whenever a source of events is being
    /// destroyed. This will ensure that the event loop can reuse `tok` for
    /// another I/O object if necessary and also remove it from any poll
    /// notifications and callbacks.
    ///
    /// Note that wake callbacks may still be invoked after this method is
    /// called as it may take some time for the message to drop a source to
    /// reach the event loop. Despite this fact, this method will attempt to
    /// ensure that the callbacks are **not** invoked, so pending scheduled
    /// callbacks cannot be relied upon to get called.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn drop_source(&self, tok: usize) {
        self.send(Message::DropSource(tok));
    }

    /// Send a message to the associated event loop that it should shut down, or
    /// otherwise break out of its current loop of iteration.
    ///
    /// This method does not forcibly cause the event loop to shut down or
    /// perform an interrupt on whatever task is currently running, instead a
    /// message is simply enqueued to at a later date process the request to
    /// stop looping ASAP.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn shutdown(&self) {
        self.send(Message::Shutdown);
    }
}

/// A future which will resolve a unique `tok` token for an I/O object.
///
/// Created through the `LoopHandle::add_source` method, this future can also
/// resolve to an error if there's an issue communicating with the event loop.
pub struct AddSource {
    loop_handle: LoopHandle,
    source: Option<IoSource>,
    result: Option<(Arc<Slot<io::Result<usize>>>, slot::Token)>,
}

impl Future for AddSource {
    type Item = usize;
    type Error = io::Error;

    fn poll(&mut self, _task: &mut Task) -> Poll<usize, io::Error> {
        match self.result {
            Some((ref result, ref token)) => {
                result.cancel(*token);
                match result.try_consume() {
                    Ok(t) => t.into(),
                    Err(_) => Poll::NotReady,
                }
            }
            None => {
                let source = &mut self.source;
                self.loop_handle.with_loop(|lp| {
                    match lp {
                        Some(lp) => lp.add_source(source.take().unwrap()).into(),
                        None => Poll::NotReady,
                    }
                })
            }
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        if let Some((ref result, ref mut token)) = self.result {
            result.cancel(*token);
            let handle = task.handle().clone();
            *token = result.on_full(move |_| {
                handle.notify();
            });
            return
        }

        let handle = task.handle().clone();
        let result = Arc::new(Slot::new(None));
        let token = result.on_full(move |_| {
            handle.notify();
        });
        self.result = Some((result.clone(), token));
        self.loop_handle.add_source_(self.source.take().unwrap(), result);
    }
}

impl<E> Source<E> {
    pub fn new(e: E) -> Source<E> {
        Source {
            readiness: AtomicUsize::new(0),
            io: e,
        }
    }
}

impl<E: ?Sized> Source<E> {
    pub fn take_readiness(&self) -> Option<Ready> {
        match self.readiness.swap(0, Ordering::SeqCst) {
            0 => None,
            1 => Some(Ready::Read),
            2 => Some(Ready::Write),
            3 => Some(Ready::ReadWrite),
            _ => panic!(),
        }
    }

    pub fn io(&self) -> &E {
        &self.io
    }
}
<commit_msg>Actually do what EventLoop::deschedule says<commit_after>use std::cell::{Cell, RefCell};
use std::io::{self, ErrorKind};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::sync::mpsc;
use std::time::Instant;

use mio;
use mio::channel::SendError;
use slab::Slab;
use futures::{Future, Task, TaskHandle, Poll};
use futures_io::Ready;

use slot::{self, Slot};

static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;
scoped_thread_local!(static CURRENT_LOOP: Loop);

const SLAB_CAPACITY: usize = 1024 * 64;

/// 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.
// TODO: expand this
pub struct Loop {
    id: usize,
    active: Cell<bool>,
    io: mio::Poll,
    tx: mio::channel::Sender<Message>,
    rx: mio::channel::Receiver<Message>,
    dispatch: RefCell<Slab<Scheduled, 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 LoopHandle {
    id: usize,
    tx: mio::channel::Sender<Message>,
}

struct Scheduled {
    source: IoSource,
    waiter: Option<TaskHandle>,
}

enum Message {
    AddSource(IoSource, Arc<Slot<io::Result<usize>>>),
    DropSource(usize),
    Schedule(usize, TaskHandle),
    Deschedule(usize),
    Shutdown,
}

pub struct Source<E: ?Sized> {
    readiness: AtomicUsize,
    io: E,
}

pub type IoSource = Arc<Source<mio::Evented + Sync + Send>>;

fn register(poll: &mio::Poll,
            token: usize,
            sched: &Scheduled) -> io::Result<()> {
    poll.register(&sched.source.io,
                  mio::Token(token),
                  mio::EventSet::readable() | mio::EventSet::writable(),
                  mio::PollOpt::edge())
}

fn deregister(poll: &mio::Poll, sched: &Scheduled) {
    // TODO: handle error
    poll.deregister(&sched.source.io).unwrap();
}

impl Loop {
    /// Creates a new event loop, returning any error that happened during the
    /// creation.
    pub fn new() -> io::Result<Loop> {
        let (tx, rx) = mio::channel::from_std_channel(mpsc::channel());
        let io = try!(mio::Poll::new());
        try!(io.register(&rx,
                         mio::Token(0),
                         mio::EventSet::readable(),
                         mio::PollOpt::edge()));
        Ok(Loop {
            id: NEXT_LOOP_ID.fetch_add(1, Ordering::Relaxed),
            active: Cell::new(true),
            io: io,
            tx: tx,
            rx: rx,
            dispatch: RefCell::new(Slab::new_starting_at(1, SLAB_CAPACITY)),
        })
    }

    /// Generates a handle to this event loop used to construct I/O objects and
    /// send messages.
    ///
    /// Handles to an event loop are cloneable as well and clones will always
    /// refer to the same event loop.
    pub fn handle(&self) -> LoopHandle {
        LoopHandle {
            id: self.id,
            tx: self.tx.clone(),
        }
    }

    /// Runs a future until completion, driving the event loop while we're
    /// otherwise waiting for the future to complete.
    ///
    /// Returns the value that the future resolves to.
    pub fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error> {
        let (tx_res, rx_res) = mpsc::channel();
        let handle = self.handle();
        f.then(move |res| {
            handle.shutdown();
            tx_res.send(res)
        }).forget();

        self._run();

        rx_res.recv().unwrap()
    }

    fn _run(&mut self) {
        let mut events = mio::Events::new();
        self.active.set(true);
        while self.active.get() {
            let amt;
            // On Linux, Poll::poll is epoll_wait, which may return EINTR if a
            // ptracer attaches. This retry loop prevents crashing when
            // attaching strace, or similar.
            let start = Instant::now();
            loop {
                match self.io.poll(&mut events, None) {
                    Ok(a) => {
                        amt = a;
                        break;
                    }
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                    err @ Err(_) => {
                        err.unwrap();
                    }
                }
            }
            debug!("loop poll - {:?}", start.elapsed());

            // TODO: coalesce token sets for a given Wake?
            let start = Instant::now();
            for i in 0..events.len() {
                let event = events.get(i).unwrap();
                let token = usize::from(event.token());

                if token == 0 {
                    debug!("consuming notification queue");
                    self.consume_queue();
                    continue
                }

                let mut waiter = None;

                if let Some(sched) = self.dispatch.borrow_mut().get_mut(token) {
                    waiter = sched.waiter.take();
                    if event.kind().is_readable() {
                        sched.source.readiness.fetch_or(1, Ordering::Relaxed);
                    }
                    if event.kind().is_writable() {
                        sched.source.readiness.fetch_or(2, Ordering::Relaxed);
                    }
                } else {
                    debug!("notified on {} which no longer exists", token);
                }
                debug!("dispatching {:?} {:?}", event.token(), event.kind());

                CURRENT_LOOP.set(&self, move || {
                    match waiter {
                        Some(waiter) => waiter.notify(),
                        None => debug!("no waiter"),
                    }
                });
            }

            debug!("loop process - {} events, {:?}", amt, start.elapsed());
        }

        debug!("loop is done!");
    }

    fn add_source(&self, source: IoSource) -> io::Result<usize> {
        let sched = Scheduled {
            source: source,
            waiter: None,
        };
        let mut dispatch = self.dispatch.borrow_mut();
        if dispatch.vacant_entry().is_none() {
            let amt = dispatch.count();
            dispatch.grow(amt);
        }
        let entry = dispatch.vacant_entry().unwrap();
        try!(register(&self.io, entry.index(), &sched));
        Ok(entry.insert(sched).index())
    }

    fn drop_source(&self, token: usize) {
        let sched = self.dispatch.borrow_mut().remove(token).unwrap();
        deregister(&self.io, &sched);
    }

    fn schedule(&self, token: usize, wake: TaskHandle) {
        let to_call = {
            let mut dispatch = self.dispatch.borrow_mut();
            let sched = dispatch.get_mut(token).unwrap();
            if sched.source.readiness.load(Ordering::Relaxed) != 0 {
                sched.waiter = None;
                Some(wake)
            } else {
                sched.waiter = Some(wake);
                None
            }
        };
        if let Some(to_call) = to_call {
            to_call.notify();
        }
    }

    fn deschedule(&self, token: usize) {
        let mut dispatch = self.dispatch.borrow_mut();
        let sched = dispatch.get_mut(token).unwrap();
        sched.waiter = None;
    }

    fn consume_queue(&self) {
        while let Ok(msg) = self.rx.try_recv() {
            self.notify(msg);
        }
    }

    fn notify(&self, msg: Message) {
        match msg {
            Message::AddSource(source, slot) => {
                // This unwrap() should always be ok as we're the only producer
                slot.try_produce(self.add_source(source))
                    .ok().expect("interference with try_produce");
            }
            Message::DropSource(tok) => self.drop_source(tok),
            Message::Schedule(tok, wake) => self.schedule(tok, wake),
            Message::Deschedule(tok) => self.deschedule(tok),
            Message::Shutdown => self.active.set(false),
        }
    }
}

impl LoopHandle {
    fn send(&self, msg: Message) {
        self.with_loop(|lp| {
            match lp {
                Some(lp) => {
                    // Need to execute all existing requests first, to ensure
                    // that our message is processed "in order"
                    lp.consume_queue();
                    lp.notify(msg);
                }
                None => {
                    match self.tx.send(msg) {
                        Ok(()) => {}

                        // This should only happen when there was an error
                        // writing to the pipe to wake up the event loop,
                        // hopefully that never happens
                        Err(SendError::Io(e)) => {
                            panic!("error sending message to event loop: {}", e)
                        }

                        // If we're still sending a message to the event loop
                        // after it's closed, then that's bad!
                        Err(SendError::Disconnected(_)) => {
                            panic!("event loop is no longer available")
                        }
                    }
                }
            }
        })
    }

    fn with_loop<F, R>(&self, f: F) -> R
        where F: FnOnce(Option<&Loop>) -> R
    {
        if CURRENT_LOOP.is_set() {
            CURRENT_LOOP.with(|lp| {
                if lp.id == self.id {
                    f(Some(lp))
                } else {
                    f(None)
                }
            })
        } else {
            f(None)
        }
    }

    /// Add a new source to an event loop, returning a future which will resolve
    /// to the token that can be used to identify this source.
    ///
    /// When a new I/O object is created it needs to be communicated to the
    /// event loop to ensure that it's registered and ready to receive
    /// notifications. The event loop with then respond with a unique token that
    /// this handle can be identified with (the resolved value of the returned
    /// future).
    ///
    /// This token is then passed in turn to each of the methods below to
    /// interact with notifications on the I/O object itself.
    ///
    /// # Panics
    ///
    /// The returned future will panic if the event loop this handle is
    /// associated with has gone away, or if there is an error communicating
    /// with the event loop.
    pub fn add_source(&self, source: IoSource) -> AddSource {
        AddSource {
            loop_handle: self.clone(),
            source: Some(source),
            result: None,
        }
    }

    fn add_source_(&self, source: IoSource, slot: Arc<Slot<io::Result<usize>>>) {
        self.send(Message::AddSource(source, slot));
    }

    /// Begin listening for events on an event loop.
    ///
    /// Once an I/O object has been registered with the event loop through the
    /// `add_source` method, this method can be used with the assigned token to
    /// begin awaiting notifications.
    ///
    /// The `dir` argument indicates how the I/O object is expected to be
    /// awaited on (either readable or writable) and the `wake` callback will be
    /// invoked. Note that one the `wake` callback is invoked once it will not
    /// be invoked again, it must be re-`schedule`d to continue receiving
    /// notifications.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn schedule(&self, tok: usize, task: &mut Task) {
        // TODO: plumb through `&mut Task` if we're on the event loop
        self.send(Message::Schedule(tok, task.handle().clone()));
    }

    /// Stop listening for events on an event loop.
    ///
    /// Once a callback has been scheduled with the `schedule` method, it can be
    /// unregistered from the event loop with this method. This method does not
    /// guarantee that the callback will not be invoked if it hasn't already,
    /// but a best effort will be made to ensure it is not called.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn deschedule(&self, tok: usize) {
        self.send(Message::Deschedule(tok));
    }

    /// Unregister all information associated with a token on an event loop,
    /// deallocating all internal resources assigned to the given token.
    ///
    /// This method should be called whenever a source of events is being
    /// destroyed. This will ensure that the event loop can reuse `tok` for
    /// another I/O object if necessary and also remove it from any poll
    /// notifications and callbacks.
    ///
    /// Note that wake callbacks may still be invoked after this method is
    /// called as it may take some time for the message to drop a source to
    /// reach the event loop. Despite this fact, this method will attempt to
    /// ensure that the callbacks are **not** invoked, so pending scheduled
    /// callbacks cannot be relied upon to get called.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn drop_source(&self, tok: usize) {
        self.send(Message::DropSource(tok));
    }

    /// Send a message to the associated event loop that it should shut down, or
    /// otherwise break out of its current loop of iteration.
    ///
    /// This method does not forcibly cause the event loop to shut down or
    /// perform an interrupt on whatever task is currently running, instead a
    /// message is simply enqueued to at a later date process the request to
    /// stop looping ASAP.
    ///
    /// # Panics
    ///
    /// This function will panic if the event loop this handle is associated
    /// with has gone away, or if there is an error communicating with the event
    /// loop.
    pub fn shutdown(&self) {
        self.send(Message::Shutdown);
    }
}

/// A future which will resolve a unique `tok` token for an I/O object.
///
/// Created through the `LoopHandle::add_source` method, this future can also
/// resolve to an error if there's an issue communicating with the event loop.
pub struct AddSource {
    loop_handle: LoopHandle,
    source: Option<IoSource>,
    result: Option<(Arc<Slot<io::Result<usize>>>, slot::Token)>,
}

impl Future for AddSource {
    type Item = usize;
    type Error = io::Error;

    fn poll(&mut self, _task: &mut Task) -> Poll<usize, io::Error> {
        match self.result {
            Some((ref result, ref token)) => {
                result.cancel(*token);
                match result.try_consume() {
                    Ok(t) => t.into(),
                    Err(_) => Poll::NotReady,
                }
            }
            None => {
                let source = &mut self.source;
                self.loop_handle.with_loop(|lp| {
                    match lp {
                        Some(lp) => lp.add_source(source.take().unwrap()).into(),
                        None => Poll::NotReady,
                    }
                })
            }
        }
    }

    fn schedule(&mut self, task: &mut Task) {
        if let Some((ref result, ref mut token)) = self.result {
            result.cancel(*token);
            let handle = task.handle().clone();
            *token = result.on_full(move |_| {
                handle.notify();
            });
            return
        }

        let handle = task.handle().clone();
        let result = Arc::new(Slot::new(None));
        let token = result.on_full(move |_| {
            handle.notify();
        });
        self.result = Some((result.clone(), token));
        self.loop_handle.add_source_(self.source.take().unwrap(), result);
    }
}

impl<E> Source<E> {
    pub fn new(e: E) -> Source<E> {
        Source {
            readiness: AtomicUsize::new(0),
            io: e,
        }
    }
}

impl<E: ?Sized> Source<E> {
    pub fn take_readiness(&self) -> Option<Ready> {
        match self.readiness.swap(0, Ordering::SeqCst) {
            0 => None,
            1 => Some(Ready::Read),
            2 => Some(Ready::Write),
            3 => Some(Ready::ReadWrite),
            _ => panic!(),
        }
    }

    pub fn io(&self) -> &E {
        &self.io
    }
}
<|endoftext|>


<commit_before>use crate::{
    blockchain::index::TxManager,
    constants::TX_EXPIRY_TIME,
    prelude::{verify::*, AddressInfo, Blockchain, ScriptHash, TxPrecompData, TxVariant},
};
use std::{mem, sync::Arc};

const DEFAULT_TX_CAP: usize = 1024;

pub struct TxPool {
    chain: Arc<Blockchain>,
    manager: TxManager,
    txs: Vec<TxVariant>,
}

impl TxPool {
    pub fn new(chain: Arc<Blockchain>) -> Self {
        let manager = TxManager::new(chain.indexer());
        Self {
            chain,
            manager,
            txs: Vec::with_capacity(DEFAULT_TX_CAP),
        }
    }

    #[inline]
    pub fn get_address_info(&self, addr: &ScriptHash) -> Option<AddressInfo> {
        self.chain.get_address_info(addr, &self.txs)
    }

    pub fn push(&mut self, data: TxPrecompData, skip_flags: SkipFlags) -> Result<(), TxErr> {
        let current_time = crate::get_epoch_ms();

        let ts = data.tx().timestamp();
        if (ts < current_time - TX_EXPIRY_TIME) || (ts > current_time + 3000) {
            return Err(TxErr::TxExpired);
        } else if self.manager.has(data.txid()) {
            return Err(TxErr::TxDupe);
        }
        self.chain.verify_tx(&data, &self.txs, skip_flags)?;

        self.manager.insert(data.txid(), ts);
        self.txs.push(data.take());
        Ok(())
    }

    pub fn flush(&mut self) -> Vec<TxVariant> {
        let mut transactions = Vec::with_capacity(DEFAULT_TX_CAP);
        mem::swap(&mut transactions, &mut self.txs);
        self.manager.purge_expired();
        transactions
    }
}
<commit_msg>Use constant instead of hardcoded number for tx expiry checking<commit_after>use crate::{
    blockchain::index::TxManager,
    constants::{BLOCK_PROD_TIME, TX_EXPIRY_TIME},
    prelude::{verify::*, AddressInfo, Blockchain, ScriptHash, TxPrecompData, TxVariant},
};
use std::{mem, sync::Arc};

const DEFAULT_TX_CAP: usize = 1024;

pub struct TxPool {
    chain: Arc<Blockchain>,
    manager: TxManager,
    txs: Vec<TxVariant>,
}

impl TxPool {
    pub fn new(chain: Arc<Blockchain>) -> Self {
        let manager = TxManager::new(chain.indexer());
        Self {
            chain,
            manager,
            txs: Vec::with_capacity(DEFAULT_TX_CAP),
        }
    }

    #[inline]
    pub fn get_address_info(&self, addr: &ScriptHash) -> Option<AddressInfo> {
        self.chain.get_address_info(addr, &self.txs)
    }

    pub fn push(&mut self, data: TxPrecompData, skip_flags: SkipFlags) -> Result<(), TxErr> {
        let current_time = crate::get_epoch_ms();

        let ts = data.tx().timestamp();
        if (ts < current_time - TX_EXPIRY_TIME) || (ts > current_time + BLOCK_PROD_TIME) {
            return Err(TxErr::TxExpired);
        } else if self.manager.has(data.txid()) {
            return Err(TxErr::TxDupe);
        }
        self.chain.verify_tx(&data, &self.txs, skip_flags)?;

        self.manager.insert(data.txid(), ts);
        self.txs.push(data.take());
        Ok(())
    }

    pub fn flush(&mut self) -> Vec<TxVariant> {
        let mut transactions = Vec::with_capacity(DEFAULT_TX_CAP);
        mem::swap(&mut transactions, &mut self.txs);
        self.manager.purge_expired();
        transactions
    }
}
<|endoftext|>


<commit_before>//! See [`FamousDefs`].
use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};

use crate::RootDatabase;

/// Helps with finding well-know things inside the standard library. This is
/// somewhat similar to the known paths infra inside hir, but it different; We
/// want to make sure that IDE specific paths don't become interesting inside
/// the compiler itself as well.
///
/// Note that, by default, rust-analyzer tests **do not** include core or std
/// libraries. If you are writing tests for functionality using [`FamousDefs`],
/// you'd want to include minicore (see `test_utils::MiniCore`) declaration at
/// the start of your tests:
///
/// ```
/// //- minicore: iterator, ord, derive
/// ```
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);

#[allow(non_snake_case)]
impl FamousDefs<'_, '_> {
    pub fn std(&self) -> Option<Crate> {
        self.find_crate("std")
    }

    pub fn core(&self) -> Option<Crate> {
        self.find_crate("core")
    }

    pub fn core_cmp_Ord(&self) -> Option<Trait> {
        self.find_trait("core:cmp:Ord")
    }

    pub fn core_convert_From(&self) -> Option<Trait> {
        self.find_trait("core:convert:From")
    }

    pub fn core_convert_Into(&self) -> Option<Trait> {
        self.find_trait("core:convert:Into")
    }

    pub fn core_option_Option(&self) -> Option<Enum> {
        self.find_enum("core:option:Option")
    }

    pub fn core_result_Result(&self) -> Option<Enum> {
        self.find_enum("core:result:Result")
    }

    pub fn core_default_Default(&self) -> Option<Trait> {
        self.find_trait("core:default:Default")
    }

    pub fn core_iter_Iterator(&self) -> Option<Trait> {
        self.find_trait("core:iter:traits:iterator:Iterator")
    }

    pub fn core_iter_IntoIterator(&self) -> Option<Trait> {
        self.find_trait("core:iter:traits:collect:IntoIterator")
    }

    pub fn core_iter(&self) -> Option<Module> {
        self.find_module("core:iter")
    }

    pub fn core_ops_Deref(&self) -> Option<Trait> {
        self.find_trait("core:ops:Deref")
    }

    pub fn alloc(&self) -> Option<Crate> {
        self.find_crate("alloc")
    }

    pub fn test(&self) -> Option<Crate> {
        self.find_crate("test")
    }

    pub fn proc_macro(&self) -> Option<Crate> {
        self.find_crate("proc_macro")
    }

    pub fn builtin_crates(&self) -> Vec<Crate> {
        IntoIterator::into_iter([
            self.std(),
            self.core(),
            self.alloc(),
            self.test(),
            self.proc_macro(),
        ])
        .filter_map(|it| it)
        .collect()
    }

    fn find_trait(&self, path: &str) -> Option<Trait> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
            _ => None,
        }
    }

    fn find_enum(&self, path: &str) -> Option<Enum> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
            _ => None,
        }
    }

    fn find_module(&self, path: &str) -> Option<Module> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
            _ => None,
        }
    }

    fn find_crate(&self, name: &str) -> Option<Crate> {
        let krate = self.1?;
        let db = self.0.db;
        let res =
            krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
        Some(res)
    }

    fn find_def(&self, path: &str) -> Option<ScopeDef> {
        let db = self.0.db;
        let mut path = path.split(':');
        let trait_ = path.next_back()?;
        let std_crate = path.next()?;
        let std_crate = self.find_crate(std_crate)?;
        let mut module = std_crate.root_module(db);
        for segment in path {
            module = module.children(db).find_map(|child| {
                let name = child.name(db)?;
                if name.to_string() == segment {
                    Some(child)
                } else {
                    None
                }
            })?;
        }
        let def =
            module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
        Some(def)
    }
}
<commit_msg>Reduce allocation in builtin_crates<commit_after>//! See [`FamousDefs`].
use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};

use crate::RootDatabase;

/// Helps with finding well-know things inside the standard library. This is
/// somewhat similar to the known paths infra inside hir, but it different; We
/// want to make sure that IDE specific paths don't become interesting inside
/// the compiler itself as well.
///
/// Note that, by default, rust-analyzer tests **do not** include core or std
/// libraries. If you are writing tests for functionality using [`FamousDefs`],
/// you'd want to include minicore (see `test_utils::MiniCore`) declaration at
/// the start of your tests:
///
/// ```
/// //- minicore: iterator, ord, derive
/// ```
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);

#[allow(non_snake_case)]
impl FamousDefs<'_, '_> {
    pub fn std(&self) -> Option<Crate> {
        self.find_crate("std")
    }

    pub fn core(&self) -> Option<Crate> {
        self.find_crate("core")
    }

    pub fn core_cmp_Ord(&self) -> Option<Trait> {
        self.find_trait("core:cmp:Ord")
    }

    pub fn core_convert_From(&self) -> Option<Trait> {
        self.find_trait("core:convert:From")
    }

    pub fn core_convert_Into(&self) -> Option<Trait> {
        self.find_trait("core:convert:Into")
    }

    pub fn core_option_Option(&self) -> Option<Enum> {
        self.find_enum("core:option:Option")
    }

    pub fn core_result_Result(&self) -> Option<Enum> {
        self.find_enum("core:result:Result")
    }

    pub fn core_default_Default(&self) -> Option<Trait> {
        self.find_trait("core:default:Default")
    }

    pub fn core_iter_Iterator(&self) -> Option<Trait> {
        self.find_trait("core:iter:traits:iterator:Iterator")
    }

    pub fn core_iter_IntoIterator(&self) -> Option<Trait> {
        self.find_trait("core:iter:traits:collect:IntoIterator")
    }

    pub fn core_iter(&self) -> Option<Module> {
        self.find_module("core:iter")
    }

    pub fn core_ops_Deref(&self) -> Option<Trait> {
        self.find_trait("core:ops:Deref")
    }

    pub fn alloc(&self) -> Option<Crate> {
        self.find_crate("alloc")
    }

    pub fn test(&self) -> Option<Crate> {
        self.find_crate("test")
    }

    pub fn proc_macro(&self) -> Option<Crate> {
        self.find_crate("proc_macro")
    }

    pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
        IntoIterator::into_iter([
            self.std(),
            self.core(),
            self.alloc(),
            self.test(),
            self.proc_macro(),
        ])
        .filter_map(|it| it)
    }

    fn find_trait(&self, path: &str) -> Option<Trait> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
            _ => None,
        }
    }

    fn find_enum(&self, path: &str) -> Option<Enum> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
            _ => None,
        }
    }

    fn find_module(&self, path: &str) -> Option<Module> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
            _ => None,
        }
    }

    fn find_crate(&self, name: &str) -> Option<Crate> {
        let krate = self.1?;
        let db = self.0.db;
        let res =
            krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
        Some(res)
    }

    fn find_def(&self, path: &str) -> Option<ScopeDef> {
        let db = self.0.db;
        let mut path = path.split(':');
        let trait_ = path.next_back()?;
        let std_crate = path.next()?;
        let std_crate = self.find_crate(std_crate)?;
        let mut module = std_crate.root_module(db);
        for segment in path {
            module = module.children(db).find_map(|child| {
                let name = child.name(db)?;
                if name.to_string() == segment {
                    Some(child)
                } else {
                    None
                }
            })?;
        }
        let def =
            module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
        Some(def)
    }
}
<|endoftext|>


<commit_before>use super::*;

pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
    .union(paths::PATH_FIRST)
    .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE]);

pub(super) fn pattern(p: &mut Parser) {
    pattern_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
pub(super) fn pattern_list(p: &mut Parser) {
    pattern_list_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
    p.eat(PIPE);
    pattern_r(p, recovery_set);

    while p.eat(PIPE) {
        pattern_r(p, recovery_set);
    }
}

pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
    if let Some(lhs) = atom_pat(p, recovery_set) {
        // test range_pat
        // fn main() {
        //     match 92 {
        //         0 ... 100 => (),
        //         101 ..= 200 => (),
        //         200 .. 301=> (),
        //     }
        // }
        if p.at(DOTDOTDOT) || p.at(DOTDOTEQ) || p.at(DOTDOT) {
            let m = lhs.precede(p);
            p.bump();
            atom_pat(p, recovery_set);
            m.complete(p, RANGE_PAT);
        }
    }
}

const PAT_RECOVERY_SET: TokenSet =
    token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];

fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
    let la0 = p.nth(0);
    let la1 = p.nth(1);
    if la0 == REF_KW
        || la0 == MUT_KW
        || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
    {
        return Some(bind_pat(p, true));
    }
    if paths::is_path_start(p) {
        return Some(path_pat(p));
    }

    if is_literal_pat_start(p) {
        return Some(literal_pat(p));
    }

    let m = match la0 {
        UNDERSCORE => placeholder_pat(p),
        AMP => ref_pat(p),
        L_PAREN => tuple_pat(p),
        L_BRACK => slice_pat(p),
        _ => {
            p.err_recover("expected pattern", recovery_set);
            return None;
        }
    };
    Some(m)
}

fn is_literal_pat_start(p: &mut Parser) -> bool {
    p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
        || p.at_ts(expressions::LITERAL_FIRST)
}

// test literal_pattern
// fn main() {
//     match () {
//         -1 => (),
//         92 => (),
//         'c' => (),
//         "hello" => (),
//     }
// }
fn literal_pat(p: &mut Parser) -> CompletedMarker {
    assert!(is_literal_pat_start(p));
    let m = p.start();
    if p.at(MINUS) {
        p.bump();
    }
    expressions::literal(p);
    m.complete(p, LITERAL_PAT)
}

// test path_part
// fn foo() {
//     let foo::Bar = ();
//     let ::Bar = ();
//     let Bar { .. } = ();
//     let Bar(..) = ();
// }
fn path_pat(p: &mut Parser) -> CompletedMarker {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    let kind = match p.current() {
        L_PAREN => {
            tuple_pat_fields(p);
            TUPLE_STRUCT_PAT
        }
        L_CURLY => {
            field_pat_list(p);
            STRUCT_PAT
        }
        _ => PATH_PAT,
    };
    m.complete(p, kind)
}

// test tuple_pat_fields
// fn foo() {
//     let S() = ();
//     let S(_) = ();
//     let S(_,) = ();
//     let S(_, .. , x) = ();
// }
fn tuple_pat_fields(p: &mut Parser) {
    assert!(p.at(L_PAREN));
    p.bump();
    pat_list(p, R_PAREN);
    p.expect(R_PAREN);
}

// test field_pat_list
// fn foo() {
//     let S {} = ();
//     let S { f, ref mut g } = ();
//     let S { h: _, ..} = ();
//     let S { h: _, } = ();
// }
fn field_pat_list(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    let m = p.start();
    p.bump();
    while !p.at(EOF) && !p.at(R_CURLY) {
        match p.current() {
            DOTDOT => p.bump(),
            IDENT if p.nth(1) == COLON => field_pat(p),
            L_CURLY => error_block(p, "expected ident"),
            _ => {
                bind_pat(p, false);
            }
        }
        if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);
    m.complete(p, FIELD_PAT_LIST);
}

fn field_pat(p: &mut Parser) {
    assert!(p.at(IDENT));
    assert!(p.nth(1) == COLON);

    let m = p.start();
    name(p);
    p.bump();
    pattern(p);
    m.complete(p, FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(UNDERSCORE));
    let m = p.start();
    p.bump();
    m.complete(p, PLACEHOLDER_PAT)
}

// test ref_pat
// fn main() {
//     let &a = ();
//     let &mut b = ();
// }
fn ref_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(AMP));
    let m = p.start();
    p.bump();
    p.eat(MUT_KW);
    pattern(p);
    m.complete(p, REF_PAT)
}

// test tuple_pat
// fn main() {
//     let (a, b, ..) = ();
// }
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_PAREN));
    let m = p.start();
    tuple_pat_fields(p);
    m.complete(p, TUPLE_PAT)
}

// test slice_pat
// fn main() {
//     let [a, b, ..] = [];
// }
fn slice_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_BRACK));
    let m = p.start();
    p.bump();
    pat_list(p, R_BRACK);
    p.expect(R_BRACK);
    m.complete(p, SLICE_PAT)
}

fn pat_list(p: &mut Parser, ket: SyntaxKind) {
    while !p.at(EOF) && !p.at(ket) {
        match p.current() {
            DOTDOT => p.bump(),
            _ => {
                if !p.at_ts(PATTERN_FIRST) {
                    p.error("expected a pattern");
                    break;
                }
                pattern(p)
            }
        }
        if !p.at(ket) {
            p.expect(COMMA);
        }
    }
}

// test bind_pat
// fn main() {
//     let a = ();
//     let mut b = ();
//     let ref c = ();
//     let ref mut d = ();
//     let e @ _ = ();
//     let ref mut f @ g @ _ = ();
// }
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
    let m = p.start();
    p.eat(REF_KW);
    p.eat(MUT_KW);
    name(p);
    if with_at && p.eat(AT) {
        pattern(p);
    }
    m.complete(p, BIND_PAT)
}
<commit_msg>Allow MINUS at the start of a pattern.<commit_after>use super::*;

pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
    .union(paths::PATH_FIRST)
    .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);

pub(super) fn pattern(p: &mut Parser) {
    pattern_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
pub(super) fn pattern_list(p: &mut Parser) {
    pattern_list_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
    p.eat(PIPE);
    pattern_r(p, recovery_set);

    while p.eat(PIPE) {
        pattern_r(p, recovery_set);
    }
}

pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
    if let Some(lhs) = atom_pat(p, recovery_set) {
        // test range_pat
        // fn main() {
        //     match 92 {
        //         0 ... 100 => (),
        //         101 ..= 200 => (),
        //         200 .. 301=> (),
        //     }
        // }
        if p.at(DOTDOTDOT) || p.at(DOTDOTEQ) || p.at(DOTDOT) {
            let m = lhs.precede(p);
            p.bump();
            atom_pat(p, recovery_set);
            m.complete(p, RANGE_PAT);
        }
    }
}

const PAT_RECOVERY_SET: TokenSet =
    token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];

fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
    let la0 = p.nth(0);
    let la1 = p.nth(1);
    if la0 == REF_KW
        || la0 == MUT_KW
        || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY))
    {
        return Some(bind_pat(p, true));
    }
    if paths::is_path_start(p) {
        return Some(path_pat(p));
    }

    if is_literal_pat_start(p) {
        return Some(literal_pat(p));
    }

    let m = match la0 {
        UNDERSCORE => placeholder_pat(p),
        AMP => ref_pat(p),
        L_PAREN => tuple_pat(p),
        L_BRACK => slice_pat(p),
        _ => {
            p.err_recover("expected pattern", recovery_set);
            return None;
        }
    };
    Some(m)
}

fn is_literal_pat_start(p: &mut Parser) -> bool {
    p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
        || p.at_ts(expressions::LITERAL_FIRST)
}

// test literal_pattern
// fn main() {
//     match () {
//         -1 => (),
//         92 => (),
//         'c' => (),
//         "hello" => (),
//     }
// }
fn literal_pat(p: &mut Parser) -> CompletedMarker {
    assert!(is_literal_pat_start(p));
    let m = p.start();
    if p.at(MINUS) {
        p.bump();
    }
    expressions::literal(p);
    m.complete(p, LITERAL_PAT)
}

// test path_part
// fn foo() {
//     let foo::Bar = ();
//     let ::Bar = ();
//     let Bar { .. } = ();
//     let Bar(..) = ();
// }
fn path_pat(p: &mut Parser) -> CompletedMarker {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    let kind = match p.current() {
        L_PAREN => {
            tuple_pat_fields(p);
            TUPLE_STRUCT_PAT
        }
        L_CURLY => {
            field_pat_list(p);
            STRUCT_PAT
        }
        _ => PATH_PAT,
    };
    m.complete(p, kind)
}

// test tuple_pat_fields
// fn foo() {
//     let S() = ();
//     let S(_) = ();
//     let S(_,) = ();
//     let S(_, .. , x) = ();
// }
fn tuple_pat_fields(p: &mut Parser) {
    assert!(p.at(L_PAREN));
    p.bump();
    pat_list(p, R_PAREN);
    p.expect(R_PAREN);
}

// test field_pat_list
// fn foo() {
//     let S {} = ();
//     let S { f, ref mut g } = ();
//     let S { h: _, ..} = ();
//     let S { h: _, } = ();
// }
fn field_pat_list(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    let m = p.start();
    p.bump();
    while !p.at(EOF) && !p.at(R_CURLY) {
        match p.current() {
            DOTDOT => p.bump(),
            IDENT if p.nth(1) == COLON => field_pat(p),
            L_CURLY => error_block(p, "expected ident"),
            _ => {
                bind_pat(p, false);
            }
        }
        if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);
    m.complete(p, FIELD_PAT_LIST);
}

fn field_pat(p: &mut Parser) {
    assert!(p.at(IDENT));
    assert!(p.nth(1) == COLON);

    let m = p.start();
    name(p);
    p.bump();
    pattern(p);
    m.complete(p, FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(UNDERSCORE));
    let m = p.start();
    p.bump();
    m.complete(p, PLACEHOLDER_PAT)
}

// test ref_pat
// fn main() {
//     let &a = ();
//     let &mut b = ();
// }
fn ref_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(AMP));
    let m = p.start();
    p.bump();
    p.eat(MUT_KW);
    pattern(p);
    m.complete(p, REF_PAT)
}

// test tuple_pat
// fn main() {
//     let (a, b, ..) = ();
// }
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_PAREN));
    let m = p.start();
    tuple_pat_fields(p);
    m.complete(p, TUPLE_PAT)
}

// test slice_pat
// fn main() {
//     let [a, b, ..] = [];
// }
fn slice_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(L_BRACK));
    let m = p.start();
    p.bump();
    pat_list(p, R_BRACK);
    p.expect(R_BRACK);
    m.complete(p, SLICE_PAT)
}

fn pat_list(p: &mut Parser, ket: SyntaxKind) {
    while !p.at(EOF) && !p.at(ket) {
        match p.current() {
            DOTDOT => p.bump(),
            _ => {
                if !p.at_ts(PATTERN_FIRST) {
                    p.error("expected a pattern");
                    break;
                }
                pattern(p)
            }
        }
        if !p.at(ket) {
            p.expect(COMMA);
        }
    }
}

// test bind_pat
// fn main() {
//     let a = ();
//     let mut b = ();
//     let ref c = ();
//     let ref mut d = ();
//     let e @ _ = ();
//     let ref mut f @ g @ _ = ();
// }
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
    let m = p.start();
    p.eat(REF_KW);
    p.eat(MUT_KW);
    name(p);
    if with_at && p.eat(AT) {
        pattern(p);
    }
    m.complete(p, BIND_PAT)
}
<|endoftext|>


<commit_before>//! Provides a simple RGBA_F32 image, used by the distributed master to store results
//! from the worker processes

use std::iter;

use film::Colorf;

pub struct Image {
    dim: (usize, usize),
    pixels: Vec<Colorf>,
}

impl Image {
    pub fn new(dimensions: (usize, usize)) -> Image {
        let pixels = iter::repeat(Colorf::broadcast(0.0)).take(dimensions.0 * dimensions.1).collect();
        Image { dim: dimensions, pixels: pixels }
    }
    /// Add the floating point RGBA_F32 pixels to the image. It is assumed that `pixels` contains
    /// a `dim.0` by `dim.1` pixel image.
    pub fn add_pixels(&mut self, pixels: &Vec<f32>) {
        for y in 0..self.dim.1 {
            for x in 0..self.dim.0 {
                let mut c = &mut self.pixels[y * self.dim.0 + x];
                let px = y * self.dim.0 * 4 + x * 4;
                for i in 0..4 {
                    c[i] = pixels[px + i];
                }
            }
        }
    }
    /// Convert the Image to sRGB8 format and return it
    pub fn get_srgb8(&self) -> Vec<u8> {
        let mut render: Vec<u8> = iter::repeat(0u8).take(self.dim.0 * self.dim.1 * 3).collect();
        for y in 0..self.dim.1 {
            for x in 0..self.dim.0 {
                let c = &self.pixels[y * self.dim.0 + x];
                if c.a > 0.0 {
                    let cn = (*c / c.a).clamp().to_srgb();
                    let px = y  * self.dim.0 * 3 + x * 3;
                    for i in 0..3 {
                        render[px + i] = (cn[i] * 255.0) as u8;
                    }
                }
            }
        }
        render
    }
    pub fn dimensions(&self) -> (usize, usize) {
        self.dim
    }
}

<commit_msg>We need ot add not overwrite heh<commit_after>//! Provides a simple RGBA_F32 image, used by the distributed master to store results
//! from the worker processes

use std::iter;

use film::Colorf;

pub struct Image {
    dim: (usize, usize),
    pixels: Vec<Colorf>,
}

impl Image {
    pub fn new(dimensions: (usize, usize)) -> Image {
        let pixels = iter::repeat(Colorf::broadcast(0.0)).take(dimensions.0 * dimensions.1).collect();
        Image { dim: dimensions, pixels: pixels }
    }
    /// Add the floating point RGBA_F32 pixels to the image. It is assumed that `pixels` contains
    /// a `dim.0` by `dim.1` pixel image.
    pub fn add_pixels(&mut self, pixels: &Vec<f32>) {
        for y in 0..self.dim.1 {
            for x in 0..self.dim.0 {
                let mut c = &mut self.pixels[y * self.dim.0 + x];
                let px = y * self.dim.0 * 4 + x * 4;
                for i in 0..4 {
                    c[i] += pixels[px + i];
                }
            }
        }
    }
    /// Convert the Image to sRGB8 format and return it
    pub fn get_srgb8(&self) -> Vec<u8> {
        let mut render: Vec<u8> = iter::repeat(0u8).take(self.dim.0 * self.dim.1 * 3).collect();
        for y in 0..self.dim.1 {
            for x in 0..self.dim.0 {
                let c = &self.pixels[y * self.dim.0 + x];
                if c.a > 0.0 {
                    let cn = (*c / c.a).clamp().to_srgb();
                    let px = y  * self.dim.0 * 3 + x * 3;
                    for i in 0..3 {
                        render[px + i] = (cn[i] * 255.0) as u8;
                    }
                }
            }
        }
        render
    }
    pub fn dimensions(&self) -> (usize, usize) {
        self.dim
    }
}

<|endoftext|>


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

use std::collections::HashSet;

use log::trace;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use ra_ap_cfg::CfgExpr;
use ra_ap_hir::{self as hir, HasAttrs};
use ra_ap_ide_db::RootDatabase;

use crate::graph::{
    edge::{Edge, EdgeKind},
    walker::GraphWalker,
    Graph, NodeIndex,
};

pub fn shrink_graph<'a, I>(graph: &mut Graph, focus_node_idxs: I, max_depth: usize)
where
    I: 'a + IntoIterator<Item = &'a NodeIndex>,
{
    trace!(
        "Shrinking graph from focus nodes up to depth {} ...",
        max_depth
    );

    // This stuff is essentially asking to be implemented using some kind of datalog.
    // Alas the datafrog turned out to be a bit too unergonomic for my liking,
    // requiring to many intermediary rules, etc. So here we are, doing it in pure Rust.
    // It's not pretty, but it works, I guess?

    let nodes_to_keep = select_nodes_to_keep(graph, focus_node_idxs, max_depth);

    redirect_uses_edges(graph, |node_idx| nodes_to_keep.contains(&node_idx));

    graph.retain_nodes(|_graph, node_idx| nodes_to_keep.contains(&node_idx));
}

fn select_nodes_to_keep<'a, I>(
    graph: &Graph,
    focus_node_idxs: I,
    max_depth: usize,
) -> HashSet<NodeIndex>
where
    I: 'a + IntoIterator<Item = &'a NodeIndex>,
{
    let mut nodes_to_keep: HashSet<NodeIndex> = HashSet::default();

    // Walk graph, collecting visited nodes:
    for focus_node_idx in focus_node_idxs {
        // Walks from a node to its descendants in the graph (i.e. sub-items & dependencies):
        let mut descendants_walker = GraphWalker::new(petgraph::Direction::Outgoing);
        descendants_walker.walk_graph(graph, *focus_node_idx, |_edge, _node, depth| {
            depth <= max_depth
        });
        nodes_to_keep.extend(descendants_walker.nodes_visited);

        // Walks from a node to its ascendants in the graph (i.e. super-items & dependents):
        let mut ascendants_walker = GraphWalker::new(petgraph::Direction::Incoming);
        ascendants_walker.walk_graph(graph, *focus_node_idx, |edge, _node, depth| {
            (edge.kind == EdgeKind::Owns) || (depth <= max_depth)
        });
        nodes_to_keep.extend(ascendants_walker.nodes_visited);
    }
    nodes_to_keep
}

// Re-attach any "uses" edges of unvisited nodes with the node associated
// with their nearest parent module that will remain alive after shrinking:
fn redirect_uses_edges<F>(graph: &mut Graph, predicate: F) -> bool
where
    F: Fn(NodeIndex) -> bool,
{
    let mut pending_edges: Vec<_> = vec![];
    let mut retired_edges: Vec<_> = vec![];

    let predicate = &predicate;

    for edge_ref in graph.edge_references() {
        let edge_idx = edge_ref.id();

        if edge_ref.weight().kind != EdgeKind::Uses {
            // We're only caring about "uses" edges here:
            continue;
        }

        let mut source_idx: NodeIndex = edge_ref.source();
        let mut target_idx: NodeIndex = edge_ref.target();

        let source_is_alive = predicate(source_idx);
        let target_is_alive = predicate(target_idx);

        if !source_is_alive {
            // Source node is not alive, so find its nearest parent module that is:
            let node_idx = nearest_matching_parent(graph, source_idx, predicate);
            match node_idx {
                Some(node_idx) => {
                    source_idx = node_idx;
                }
                None => continue,
            }
        } else if !target_is_alive {
            // Target node is not alive, so find its nearest parent module that is:
            let node_idx = nearest_matching_parent(graph, target_idx, predicate);
            match node_idx {
                Some(node_idx) => target_idx = node_idx,
                None => continue,
            }
        } else {
            // Both nodes are alive, nothing to do!
            continue;
        }

        let edge = Edge {
            kind: EdgeKind::Uses,
        };

        retired_edges.push(edge_idx);
        pending_edges.push((source_idx, target_idx, edge));
    }

    if pending_edges.is_empty() {
        return false;
    }

    // Remove edges
    for edge_idx in retired_edges {
        graph.remove_edge(edge_idx);
    }

    for (source_idx, target_idx, edge) in pending_edges {
        graph.update_edge(source_idx, target_idx, edge);
    }

    true
}

fn nearest_matching_parent<F>(graph: &Graph, node_idx: NodeIndex, predicate: F) -> Option<NodeIndex>
where
    F: Fn(NodeIndex) -> bool,
{
    graph
        .edges_directed(node_idx, petgraph::Direction::Incoming)
        .find_map(|edge_ref| {
            let edge = edge_ref.weight();
            match edge.kind {
                EdgeKind::Uses => None,
                EdgeKind::Owns => {
                    let source_idx = edge_ref.source();
                    if predicate(source_idx) {
                        Some(edge_ref.source())
                    } else {
                        None
                    }
                }
            }
        })
}

pub(crate) fn krate_name(krate: hir::Crate, db: &RootDatabase) -> String {
    // Obtain the crate's declaration name:
    let display_name = &krate.display_name(db).unwrap();

    // Since a crate's name may contain `-` we canonicalize it by replacing with `_`:
    display_name.replace('-', "_")
}

pub(crate) fn krate(module_def: hir::ModuleDef, db: &RootDatabase) -> Option<hir::Crate> {
    module(module_def, db).map(|module| module.krate())
}

pub(crate) fn module(module_def: hir::ModuleDef, db: &RootDatabase) -> Option<hir::Module> {
    match module_def {
        hir::ModuleDef::Module(module) => Some(module),
        module_def => module_def.module(db),
    }
}

pub(crate) fn path(module_def: hir::ModuleDef, db: &RootDatabase) -> String {
    let mut path = String::new();

    let krate = krate(module_def, db);

    // Obtain the module's krate's name (unless it's a builtin type, which have no crate):
    if let Some(krate_name) = krate.map(|krate| krate_name(krate, db)) {
        path.push_str(krate_name.as_str());
    }

    // Obtain the module's canonicalized name:
    if let Some(relative_canonical_path) = module_def.canonical_path(db) {
        path.push_str("::");
        path.push_str(relative_canonical_path.as_str());
    }

    assert!(!path.is_empty());

    path
}

// #[test] fn
// it_works() { … }
pub(crate) fn is_test_function(function: hir::Function, db: &RootDatabase) -> bool {
    let attrs = function.attrs(db);
    attrs.by_key("test").exists()
}

pub fn cfgs(hir: hir::ModuleDef, db: &RootDatabase) -> Vec<CfgExpr> {
    let cfg = match cfg(hir, db) {
        Some(cfg) => cfg,
        None => return vec![],
    };

    match cfg {
        CfgExpr::Invalid => vec![],
        cfg @ CfgExpr::Atom(_) => vec![cfg],
        CfgExpr::All(cfgs) => cfgs,
        cfg @ CfgExpr::Any(_) => vec![cfg],
        cfg @ CfgExpr::Not(_) => vec![cfg],
    }
}

pub fn cfg(hir: hir::ModuleDef, db: &RootDatabase) -> Option<CfgExpr> {
    match hir {
        hir::ModuleDef::Module(r#mod) => r#mod.attrs(db).cfg(),
        hir::ModuleDef::Function(r#fn) => r#fn.attrs(db).cfg(),
        hir::ModuleDef::Adt(r#adt) => r#adt.attrs(db).cfg(),
        hir::ModuleDef::Variant(r#variant) => r#variant.attrs(db).cfg(),
        hir::ModuleDef::Const(r#const) => r#const.attrs(db).cfg(),
        hir::ModuleDef::Static(r#static) => r#static.attrs(db).cfg(),
        hir::ModuleDef::Trait(r#trait) => r#trait.attrs(db).cfg(),
        hir::ModuleDef::TypeAlias(r#type) => r#type.attrs(db).cfg(),
        hir::ModuleDef::BuiltinType(_) => None,
        hir::ModuleDef::Macro(_) => None,
    }
}
<commit_msg>Improve support for builtin types<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::collections::HashSet;

use log::trace;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use ra_ap_cfg::CfgExpr;
use ra_ap_hir::{self as hir, HasAttrs};
use ra_ap_ide_db::RootDatabase;

use crate::graph::{
    edge::{Edge, EdgeKind},
    walker::GraphWalker,
    Graph, NodeIndex,
};

pub fn shrink_graph<'a, I>(graph: &mut Graph, focus_node_idxs: I, max_depth: usize)
where
    I: 'a + IntoIterator<Item = &'a NodeIndex>,
{
    trace!(
        "Shrinking graph from focus nodes up to depth {} ...",
        max_depth
    );

    // This stuff is essentially asking to be implemented using some kind of datalog.
    // Alas the datafrog turned out to be a bit too unergonomic for my liking,
    // requiring to many intermediary rules, etc. So here we are, doing it in pure Rust.
    // It's not pretty, but it works, I guess?

    let nodes_to_keep = select_nodes_to_keep(graph, focus_node_idxs, max_depth);

    redirect_uses_edges(graph, |node_idx| nodes_to_keep.contains(&node_idx));

    graph.retain_nodes(|_graph, node_idx| nodes_to_keep.contains(&node_idx));
}

fn select_nodes_to_keep<'a, I>(
    graph: &Graph,
    focus_node_idxs: I,
    max_depth: usize,
) -> HashSet<NodeIndex>
where
    I: 'a + IntoIterator<Item = &'a NodeIndex>,
{
    let mut nodes_to_keep: HashSet<NodeIndex> = HashSet::default();

    // Walk graph, collecting visited nodes:
    for focus_node_idx in focus_node_idxs {
        // Walks from a node to its descendants in the graph (i.e. sub-items & dependencies):
        let mut descendants_walker = GraphWalker::new(petgraph::Direction::Outgoing);
        descendants_walker.walk_graph(graph, *focus_node_idx, |_edge, _node, depth| {
            depth <= max_depth
        });
        nodes_to_keep.extend(descendants_walker.nodes_visited);

        // Walks from a node to its ascendants in the graph (i.e. super-items & dependents):
        let mut ascendants_walker = GraphWalker::new(petgraph::Direction::Incoming);
        ascendants_walker.walk_graph(graph, *focus_node_idx, |edge, _node, depth| {
            (edge.kind == EdgeKind::Owns) || (depth <= max_depth)
        });
        nodes_to_keep.extend(ascendants_walker.nodes_visited);
    }
    nodes_to_keep
}

// Re-attach any "uses" edges of unvisited nodes with the node associated
// with their nearest parent module that will remain alive after shrinking:
fn redirect_uses_edges<F>(graph: &mut Graph, predicate: F) -> bool
where
    F: Fn(NodeIndex) -> bool,
{
    let mut pending_edges: Vec<_> = vec![];
    let mut retired_edges: Vec<_> = vec![];

    let predicate = &predicate;

    for edge_ref in graph.edge_references() {
        let edge_idx = edge_ref.id();

        if edge_ref.weight().kind != EdgeKind::Uses {
            // We're only caring about "uses" edges here:
            continue;
        }

        let mut source_idx: NodeIndex = edge_ref.source();
        let mut target_idx: NodeIndex = edge_ref.target();

        let source_is_alive = predicate(source_idx);
        let target_is_alive = predicate(target_idx);

        if !source_is_alive {
            // Source node is not alive, so find its nearest parent module that is:
            let node_idx = nearest_matching_parent(graph, source_idx, predicate);
            match node_idx {
                Some(node_idx) => {
                    source_idx = node_idx;
                }
                None => continue,
            }
        } else if !target_is_alive {
            // Target node is not alive, so find its nearest parent module that is:
            let node_idx = nearest_matching_parent(graph, target_idx, predicate);
            match node_idx {
                Some(node_idx) => target_idx = node_idx,
                None => continue,
            }
        } else {
            // Both nodes are alive, nothing to do!
            continue;
        }

        let edge = Edge {
            kind: EdgeKind::Uses,
        };

        retired_edges.push(edge_idx);
        pending_edges.push((source_idx, target_idx, edge));
    }

    if pending_edges.is_empty() {
        return false;
    }

    // Remove edges
    for edge_idx in retired_edges {
        graph.remove_edge(edge_idx);
    }

    for (source_idx, target_idx, edge) in pending_edges {
        graph.update_edge(source_idx, target_idx, edge);
    }

    true
}

fn nearest_matching_parent<F>(graph: &Graph, node_idx: NodeIndex, predicate: F) -> Option<NodeIndex>
where
    F: Fn(NodeIndex) -> bool,
{
    graph
        .edges_directed(node_idx, petgraph::Direction::Incoming)
        .find_map(|edge_ref| {
            let edge = edge_ref.weight();
            match edge.kind {
                EdgeKind::Uses => None,
                EdgeKind::Owns => {
                    let source_idx = edge_ref.source();
                    if predicate(source_idx) {
                        Some(edge_ref.source())
                    } else {
                        None
                    }
                }
            }
        })
}

pub(crate) fn krate_name(krate: hir::Crate, db: &RootDatabase) -> String {
    // Obtain the crate's declaration name:
    let display_name = &krate.display_name(db).unwrap();

    // Since a crate's name may contain `-` we canonicalize it by replacing with `_`:
    display_name.replace('-', "_")
}

pub(crate) fn krate(module_def: hir::ModuleDef, db: &RootDatabase) -> Option<hir::Crate> {
    module(module_def, db).map(|module| module.krate())
}

pub(crate) fn module(module_def: hir::ModuleDef, db: &RootDatabase) -> Option<hir::Module> {
    match module_def {
        hir::ModuleDef::Module(module) => Some(module),
        module_def => module_def.module(db),
    }
}

pub(crate) fn path(module_def: hir::ModuleDef, db: &RootDatabase) -> String {
    if let hir::ModuleDef::BuiltinType(builtin) = module_def {
        return builtin.name().to_string();
    }

    let mut path = String::new();

    let krate = krate(module_def, db);

    // Obtain the module's krate's name (unless it's a builtin type, which have no crate):
    if let Some(krate_name) = krate.map(|krate| krate_name(krate, db)) {
        path.push_str(krate_name.as_str());
    }

    // Obtain the module's canonicalized name:
    if let Some(relative_canonical_path) = module_def.canonical_path(db) {
        path.push_str("::");
        path.push_str(relative_canonical_path.as_str());
    }

    assert!(!path.is_empty());

    path
}

// #[test] fn
// it_works() { … }
pub(crate) fn is_test_function(function: hir::Function, db: &RootDatabase) -> bool {
    let attrs = function.attrs(db);
    attrs.by_key("test").exists()
}

pub fn cfgs(hir: hir::ModuleDef, db: &RootDatabase) -> Vec<CfgExpr> {
    let cfg = match cfg(hir, db) {
        Some(cfg) => cfg,
        None => return vec![],
    };

    match cfg {
        CfgExpr::Invalid => vec![],
        cfg @ CfgExpr::Atom(_) => vec![cfg],
        CfgExpr::All(cfgs) => cfgs,
        cfg @ CfgExpr::Any(_) => vec![cfg],
        cfg @ CfgExpr::Not(_) => vec![cfg],
    }
}

pub fn cfg(hir: hir::ModuleDef, db: &RootDatabase) -> Option<CfgExpr> {
    match hir {
        hir::ModuleDef::Module(r#mod) => r#mod.attrs(db).cfg(),
        hir::ModuleDef::Function(r#fn) => r#fn.attrs(db).cfg(),
        hir::ModuleDef::Adt(r#adt) => r#adt.attrs(db).cfg(),
        hir::ModuleDef::Variant(r#variant) => r#variant.attrs(db).cfg(),
        hir::ModuleDef::Const(r#const) => r#const.attrs(db).cfg(),
        hir::ModuleDef::Static(r#static) => r#static.attrs(db).cfg(),
        hir::ModuleDef::Trait(r#trait) => r#trait.attrs(db).cfg(),
        hir::ModuleDef::TypeAlias(r#type) => r#type.attrs(db).cfg(),
        hir::ModuleDef::BuiltinType(_) => None,
        hir::ModuleDef::Macro(_) => None,
    }
}
<|endoftext|>


<commit_before>use image::GrayAlphaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;
use codec::Codec;

pub struct GrayAlphaCodec;

impl Codec for GrayAlphaCodec
{
    type Input = GrayAlphaImage;
    type Mode = GrayAlphaMode;

    fn encode<R: Rng>(
        source: &mut GrayAlphaImage,
        payload: &[u8],
        mode: GrayAlphaMode,
        rng: R)
    {
        unimplemented!()
    }

    fn decode(
        source: &GrayAlphaImage,
        payload: &mut [u8],
        len: usize,
        mode: GrayAlphaMode)
    {
        unimplemented!()
    }

    fn estimate(
        source: &GrayAlphaImage,
        mode: GrayAlphaMode) -> Option<usize>
    {
        Some(match mode
        {
            GrayAlphaMode::Alpha =>
                source.height() as usize * source.width() as usize / 8,
            GrayAlphaMode::All =>
                source.height() as usize * source.width() as usize / 4,
        })
    }
}

#[derive(Copy, Clone)]
pub enum GrayAlphaMode
{
    Alpha,
    All,
}

use std::default::Default;

impl Default for GrayAlphaMode
{
    fn default() -> GrayAlphaMode
    {
        GrayAlphaMode::Alpha
    }
}

use std::str::FromStr;

impl FromStr for GrayAlphaMode
{
    type Err = ();

    fn from_str(s: &str) -> Result<GrayAlphaMode, ()>
    {
        if s == "alpha"
        {
            Ok(GrayAlphaMode::Alpha)
        }
        else if s == "all"
        {
            Ok(GrayAlphaMode::All)
        }
        else
        {
            Err(())
        }
    }
}
<commit_msg>Implemented gray alpha encoding<commit_after>use image::GrayAlphaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;
use codec::Codec;

pub struct GrayAlphaCodec;

impl Codec for GrayAlphaCodec
{
    type Input = GrayAlphaImage;
    type Mode = GrayAlphaMode;

    fn encode<R: Rng>(
        source: &mut GrayAlphaImage,
        payload: &[u8],
        mode: GrayAlphaMode,
        mut rng: R)
    {
        // pixels per bytes
        let ppb = match mode
        {
            GrayAlphaMode::Alpha => 8,
            GrayAlphaMode::All => 4,
        };

        for (pixels, byte) in source.pixels_mut()
            .chunks(ppb).into_iter()
            .map(|ch| ch.collect::<Vec<_>>())
            .zip(payload.iter().map(|x| *x))
        {
            if pixels.len() != ppb
            {
                return;
            }

            match mode
            {
                GrayAlphaMode::Alpha =>
                {
                    for (i, px) in pixels.into_iter()
                        .enumerate()
                    {
                        fix_u8(&mut px.data[1],
                               get_bit(byte, i as u8), &mut rng);
                    }
                },
                GrayAlphaMode::All =>
                {
                    for (i, px) in pixels.into_iter()
                        .enumerate()
                    {
                        fix_u8(&mut px.data[0],
                               get_bit(byte, i as u8 * 2), &mut rng);
                        fix_u8(&mut px.data[1],
                               get_bit(byte, i as u8 * 2 + 1), &mut rng);
                    }
                },
            }
        }
    }

    fn decode(
        source: &GrayAlphaImage,
        payload: &mut [u8],
        len: usize,
        mode: GrayAlphaMode)
    {
        unimplemented!()
    }

    fn estimate(
        source: &GrayAlphaImage,
        mode: GrayAlphaMode) -> Option<usize>
    {
        Some(match mode
        {
            GrayAlphaMode::Alpha =>
                source.height() as usize * source.width() as usize / 8,
            GrayAlphaMode::All =>
                source.height() as usize * source.width() as usize / 4,
        })
    }
}

#[derive(Copy, Clone)]
pub enum GrayAlphaMode
{
    Alpha,
    All,
}

use std::default::Default;

impl Default for GrayAlphaMode
{
    fn default() -> GrayAlphaMode
    {
        GrayAlphaMode::Alpha
    }
}

use std::str::FromStr;

impl FromStr for GrayAlphaMode
{
    type Err = ();

    fn from_str(s: &str) -> Result<GrayAlphaMode, ()>
    {
        if s == "alpha"
        {
            Ok(GrayAlphaMode::Alpha)
        }
        else if s == "all"
        {
            Ok(GrayAlphaMode::All)
        }
        else
        {
            Err(())
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::fmt::{Error, Debug};
use std::ffi::CStr;

#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Status {
    Success = 0,

    NoMemory,
    InvalidRestore,
    InvalidPopGroup,
    NoCurrentPoint,
    InvalidMatrix,
    InvalidStatus,
    NullPointer,
    InvalidString,
    InvalidPathData,
    ReadError,
    WriteError,
    SurfaceFinished,
    SurfaceTypeMismatch,
    PatternTypeMismatch,
    InvalidContent,
    InvalidFormat,
    InvalidVisual,
    FileNotFound,
    InvalidDash,
    InvalidDscComment,
    InvalidIndex,
    ClipNotRepresentable,
    TempFileError,
    InvalidStride,
    FontTypeMismatch,
    UserFontImmutable,
    UserFontError,
    NegativeCount,
    InvalidClusters,
    InvalidSlant,
    InvalidWeight,
    InvalidSize,
    UserFontNotImplemented,
    DeviceTypeMismatch,
    DeviceError,
    InvalidMeshConstruction,
    DeviceFinished,
    // CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID has been used on at least one image but no
    // image provided `JBig2Global` (Since 1.14)
    // JBig2GlobalMissing,
    LastStatus
}

impl Debug for Status {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), Error> {
        unsafe {
            let char_ptr = super::cairo_status_to_string(*self);
            let tmp = String::from_utf8_lossy(CStr::from_ptr(char_ptr).to_bytes()).into_owned();

            tmp.fmt(formatter)
        }
    }
}

impl Status {
    pub fn ensure_valid(&self) {
        if *self != Status::Success {
            panic!("Cairo error {:?}", *self)
        }
    }
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Antialias {
    Default,

    /* method */
    None,
    Gray,
    Subpixel,

    /* hints */
    Fast,
    Good,
    Best
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FillRule {
    Winding,
    EvenOdd
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum LineCap {
    Butt,
    Round,
    Square
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum LineJoin {
    Miter,
    Round,
    Bevel
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Operator {
    Clear,

    Source,
    Over,
    In,
    Out,
    Atop,

    Dest,
    DestOver,
    DestIn,
    DestOut,
    DestAtop,

    Xor,
    Add,
    Saturate,

    Multiply,
    Screen,
    Overlay,
    Darken,
    Lighten,
    ColorDodge,
    ColorBurn,
    HardLight,
    SoftLight,
    Difference,
    Exclusion,
    HslHue,
    HslSaturation,
    HslColor,
    HslLuminosity
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum PathDataType {
    MoveTo,
    LineTo,
    CurveTo,
    ClosePath
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Content {
    Color      = 0x1000,
    Alpha      = 0x2000,
    ColorAlpha = 0x3000
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Extend {
    None,
    Repeat,
    Reflect,
    Pad
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Filter {
    Fast,
    Good,
    Best,
    Nearest,
    Bilinear,
    Gaussian
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum PatternType {
    Solid,
    Surface,
    LinearGradient,
    RadialGradient,
    #[cfg(feature = "v1_12")]
    Mesh,
    #[cfg(feature = "v1_12")]
    RasterSource
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FontSlant {
    Normal,
    Italic,
    Oblique
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FontWeight {
    Normal,
    Bold
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum TextClusterFlags {
    None     = 0x00000000,
    Backward = 0x00000001
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FontType {
    FontTypeToy,
    FontTypeFt,
    FontTypeWin32,
    FontTypeQuartz,
    FontTypeUser
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum SubpixelOrder {
    Default,
    Rgb,
    Bgr,
    Vrgb,
    Vbgr
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum HintStyle {
    Default,
    None,
    Slight,
    Medium,
    Full
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum HintMetrics {
    Default,
    Off,
    On
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SurfaceType {
    Image,
    Pdf,
    Ps,
    Xlib,
    Xcb,
    Glitz,
    Quartz,
    Win32,
    BeOs,
    DirectFb,
    Svg,
    Os2,
    Win32Printing,
    QuartzImage,
    Script,
    Qt,
    Recording,
    Vg,
    Gl,
    Drm,
    Tee,
    Xml,
    Skia,
    Subsurface,
    Cogl,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Format {
    Invalid = -1,
    ARgb32 = 0,
    Rgb24 = 1,
    A8 = 2,
    A1 = 3,
    Rgb16_565 = 4,
    Rgb30 = 5,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RegionOverlap {
    In,
    Out,
    Part,
}
<commit_msg>Status: add missing error statuses from Cairo<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::fmt::{Error, Debug};
use std::ffi::CStr;

#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Status {
    Success = 0,

    NoMemory,
    InvalidRestore,
    InvalidPopGroup,
    NoCurrentPoint,
    InvalidMatrix,
    InvalidStatus,
    NullPointer,
    InvalidString,
    InvalidPathData,
    ReadError,
    WriteError,
    SurfaceFinished,
    SurfaceTypeMismatch,
    PatternTypeMismatch,
    InvalidContent,
    InvalidFormat,
    InvalidVisual,
    FileNotFound,
    InvalidDash,
    InvalidDscComment,
    InvalidIndex,
    ClipNotRepresentable,
    TempFileError,
    InvalidStride,
    FontTypeMismatch,
    UserFontImmutable,
    UserFontError,
    NegativeCount,
    InvalidClusters,
    InvalidSlant,
    InvalidWeight,
    InvalidSize,
    UserFontNotImplemented,
    DeviceTypeMismatch,
    DeviceError,
    InvalidMeshConstruction,
    DeviceFinished,
    // CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID has been used on at least one image but no
    // image provided `JBig2Global` (Since 1.14)
    JBig2GlobalMissing,
    PngError,
    FreetypeError,
    Win32GdiError,
    LastStatus
}

impl Debug for Status {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), Error> {
        unsafe {
            let char_ptr = super::cairo_status_to_string(*self);
            let tmp = String::from_utf8_lossy(CStr::from_ptr(char_ptr).to_bytes()).into_owned();

            tmp.fmt(formatter)
        }
    }
}

impl Status {
    pub fn ensure_valid(&self) {
        if *self != Status::Success {
            panic!("Cairo error {:?}", *self)
        }
    }
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Antialias {
    Default,

    /* method */
    None,
    Gray,
    Subpixel,

    /* hints */
    Fast,
    Good,
    Best
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FillRule {
    Winding,
    EvenOdd
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum LineCap {
    Butt,
    Round,
    Square
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum LineJoin {
    Miter,
    Round,
    Bevel
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Operator {
    Clear,

    Source,
    Over,
    In,
    Out,
    Atop,

    Dest,
    DestOver,
    DestIn,
    DestOut,
    DestAtop,

    Xor,
    Add,
    Saturate,

    Multiply,
    Screen,
    Overlay,
    Darken,
    Lighten,
    ColorDodge,
    ColorBurn,
    HardLight,
    SoftLight,
    Difference,
    Exclusion,
    HslHue,
    HslSaturation,
    HslColor,
    HslLuminosity
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum PathDataType {
    MoveTo,
    LineTo,
    CurveTo,
    ClosePath
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Content {
    Color      = 0x1000,
    Alpha      = 0x2000,
    ColorAlpha = 0x3000
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Extend {
    None,
    Repeat,
    Reflect,
    Pad
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum Filter {
    Fast,
    Good,
    Best,
    Nearest,
    Bilinear,
    Gaussian
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum PatternType {
    Solid,
    Surface,
    LinearGradient,
    RadialGradient,
    #[cfg(feature = "v1_12")]
    Mesh,
    #[cfg(feature = "v1_12")]
    RasterSource
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FontSlant {
    Normal,
    Italic,
    Oblique
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FontWeight {
    Normal,
    Bold
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum TextClusterFlags {
    None     = 0x00000000,
    Backward = 0x00000001
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum FontType {
    FontTypeToy,
    FontTypeFt,
    FontTypeWin32,
    FontTypeQuartz,
    FontTypeUser
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum SubpixelOrder {
    Default,
    Rgb,
    Bgr,
    Vrgb,
    Vbgr
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum HintStyle {
    Default,
    None,
    Slight,
    Medium,
    Full
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Debug, Copy)]
pub enum HintMetrics {
    Default,
    Off,
    On
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SurfaceType {
    Image,
    Pdf,
    Ps,
    Xlib,
    Xcb,
    Glitz,
    Quartz,
    Win32,
    BeOs,
    DirectFb,
    Svg,
    Os2,
    Win32Printing,
    QuartzImage,
    Script,
    Qt,
    Recording,
    Vg,
    Gl,
    Drm,
    Tee,
    Xml,
    Skia,
    Subsurface,
    Cogl,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Format {
    Invalid = -1,
    ARgb32 = 0,
    Rgb24 = 1,
    A8 = 2,
    A1 = 3,
    Rgb16_565 = 4,
    Rgb30 = 5,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RegionOverlap {
    In,
    Out,
    Part,
}
<|endoftext|>


<commit_before>//! Functions for managing and acquiring engine configuration
use error::DeucalionError;
use scripting::{execute_script, Lua};
// TODO: Make this work with the Lua subsystem.

/// A datastructure containing configuration details for the engine
#[derive(PartialEq, Eq, Debug)]
pub struct EngineConfig {
    /// The width of the window in which the engine will run.
    pub screen_width: u32,
    /// The height of the window in which the engine will run.
    pub screen_height: u32,
    /// The maximum framerate at which the engine should attempt to run.
    pub maximum_framerate: u32,
}

/// Acquire the engine's configuration. If acquiring it from data/engine_config.lua fails,
/// this function will return the default configuration, which will typically work for every
/// configuration.
pub fn get_engine_config(environment: &mut Lua) -> EngineConfig {
    let path = "data/engine_config.lua";
    match execute_script(environment, path) {
        Ok(v) => {
            match get_engine_config_from_environment(environment) {
                Ok(w) => {
                    info!("Succesfully acquired engine config at {}", path);
                    trace!("Engine config is {:?}", w);
                    w // This is the valid EngineConfig struct built from the script
                }
                Err(e) => {
                    error!("Failed to acquire engine config from script at {}: {}",
                           path,
                           e);
                    get_default_engine_config()
                }
            }
        }
        Err(e) => {
            error!("Failed to run engine config script at {}: {}", path, e);
            get_default_engine_config()
        }
    }
}

/// Check variables in the Lua environment, bringing their values into an EngineConfig struct
fn get_engine_config_from_environment(environment: &mut Lua) -> Result<EngineConfig, DeucalionError> {
    // Here, we have a set of match expressions that attempt to fetch the global config variables.
    // At some point, this action (extract Lua global or error) should be abstracted into a macro
    let screen_width = match environment.get("SCREEN_WIDTH") {
        Some(v) => v,
        None => {
            return Err(DeucalionError::from("SCREEN_WIDTH is not defined or is the wrong type"));
        }
    };
    let screen_height = match environment.get("SCREEN_HEIGHT") {
        Some(v) => v,
        None => {
            return Err(DeucalionError::from("SCREEN_HEIGHT is not defined or is the wrong type"));
        }
    };
    let maximum_framerate = match environment.get("MAXIMUM_FRAMERATE") {
        Some(v) => v,
        None => {
            return Err(DeucalionError::from("MAXIMUM_FRAMERATE is not defined or is the wrong \
                                             type"));
        }
    };
    // Simply build the EngineConfig struct. Making it to this point means the config is O.K.
    Ok(EngineConfig {
        screen_height: screen_height,
        screen_width: screen_width,
        maximum_framerate: maximum_framerate,
    })
}

/// Get the engine's default configuration state. This cannot fail.
fn get_default_engine_config() -> EngineConfig {
    EngineConfig {
        screen_width: 640,
        screen_height: 480,
        maximum_framerate: 60,
    }
}
<commit_msg>Change get_engine_config to use resource module.<commit_after>//! Functions for managing and acquiring engine configuration
use error::DeucalionError;
use scripting::{execute_script, Lua};
use resource;
// TODO: Make this work with the Lua subsystem.

/// A datastructure containing configuration details for the engine
#[derive(PartialEq, Eq, Debug)]
pub struct EngineConfig {
    /// The width of the window in which the engine will run.
    pub screen_width: u32,
    /// The height of the window in which the engine will run.
    pub screen_height: u32,
    /// The maximum framerate at which the engine should attempt to run.
    pub maximum_framerate: u32,
}

/// Acquire the engine's configuration. If acquiring it from data/engine_config.lua fails,
/// this function will return the default configuration, which will typically work for every
/// configuration.
pub fn get_engine_config(environment: &mut Lua) -> EngineConfig {
    let path =
        match resource::loading::get_resource_path_by_name(resource::ResourceKind::EngineConfig,
                                                           "") {
            Ok(v) => v,
            Err(e) => {
                // If the engine config's path can't be generated, it certainly can't be loaded.
                error!("Failed to generate the path for the engine configuration script: {}",
                       e);
                return get_default_engine_config();
            }
        };

    // Syntax monster explaination for the &* in the second argument to execute_script:
    //  to_string_lossy returns a Cow<str>, which we dereference to str and then borrow to &str
    match execute_script(environment, &*path.to_string_lossy()) {
        Ok(_) => {
            match get_engine_config_from_environment(environment) {
                Ok(w) => {
                    info!("Succesfully acquired engine config at {}",
                          path.to_string_lossy());
                    trace!("Engine config is {:?}", w);
                    w // This is the valid EngineConfig struct built from the script
                }
                Err(e) => {
                    error!("Failed to acquire engine config from script at {}: {}",
                           path.to_string_lossy(),
                           e);
                    get_default_engine_config()
                }
            }
        }
        Err(e) => {
            error!("Failed to run engine config script at {}: {}",
                   path.to_string_lossy(),
                   e);
            get_default_engine_config()
        }
    }
}

/// Check variables in the Lua environment, bringing their values into an EngineConfig struct
fn get_engine_config_from_environment(environment: &mut Lua) -> Result<EngineConfig, DeucalionError> {
    // Here, we have a set of match expressions that attempt to fetch the global config variables.
    // At some point, this action (extract Lua global or error) should be abstracted into a macro
    let screen_width = match environment.get("SCREEN_WIDTH") {
        Some(v) => v,
        None => {
            return Err(DeucalionError::from("SCREEN_WIDTH is not defined or is the wrong type"));
        }
    };
    let screen_height = match environment.get("SCREEN_HEIGHT") {
        Some(v) => v,
        None => {
            return Err(DeucalionError::from("SCREEN_HEIGHT is not defined or is the wrong type"));
        }
    };
    let maximum_framerate = match environment.get("MAXIMUM_FRAMERATE") {
        Some(v) => v,
        None => {
            return Err(DeucalionError::from("MAXIMUM_FRAMERATE is not defined or is the wrong \
                                             type"));
        }
    };
    // Simply build the EngineConfig struct. Making it to this point means the config is O.K.
    Ok(EngineConfig {
        screen_height: screen_height,
        screen_width: screen_width,
        maximum_framerate: maximum_framerate,
    })
}

/// Get the engine's default configuration state. This cannot fail.
fn get_default_engine_config() -> EngineConfig {
    EngineConfig {
        screen_width: 640,
        screen_height: 480,
        maximum_framerate: 60,
    }
}
<|endoftext|>