<commit_before>//! A one-shot, futures-aware channel

use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::error::Error;
use std::fmt;

use {Future, Poll, Async};
use lock::Lock;
use task::{self, Task};

/// A future representing the completion of a computation happening elsewhere in
/// memory.
///
/// This is created by the `oneshot::channel` function.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Receiver<T> {
    inner: Arc<Inner<T>>,
}

/// Represents the completion half of a oneshot through which the result of a
/// computation is signaled.
///
/// This is created by the `oneshot::channel` function.
#[derive(Debug)]
pub struct Sender<T> {
    inner: Arc<Inner<T>>,
}

/// Internal state of the `Receiver`/`Sender` pair above. This is all used as
/// the internal synchronization between the two for send/recv operations.
#[derive(Debug)]
struct Inner<T> {
    /// Indicates whether this oneshot is complete yet. This is filled in both
    /// by `Sender::drop` and by `Receiver::drop`, and both sides iterpret it
    /// appropriately.
    ///
    /// For `Receiver`, if this is `true`, then it's guaranteed that `data` is
    /// unlocked and ready to be inspected.
    ///
    /// For `Sender` if this is `true` then the oneshot has gone away and it
    /// can return ready from `poll_cancel`.
    complete: AtomicBool,

    /// The actual data being transferred as part of this `Receiver`. This is
    /// filled in by `Sender::complete` and read by `Receiver::poll`.
    ///
    /// Note that this is protected by `Lock`, but it is in theory safe to
    /// replace with an `UnsafeCell` as it's actually protected by `complete`
    /// above. I wouldn't recommend doing this, however, unless someone is
    /// supremely confident in the various atomic orderings here and there.
    data: Lock<Option<T>>,

    /// Field to store the task which is blocked in `Receiver::poll`.
    ///
    /// This is filled in when a oneshot is polled but not ready yet. Note that
    /// the `Lock` here, unlike in `data` above, is important to resolve races.
    /// Both the `Receiver` and the `Sender` halves understand that if they
    /// can't acquire the lock then some important interference is happening.
    rx_task: Lock<Option<Task>>,

    /// Like `rx_task` above, except for the task blocked in
    /// `Sender::poll_cancel`. Additionally, `Lock` cannot be `UnsafeCell`.
    tx_task: Lock<Option<Task>>,
}

/// Creates a new futures-aware, one-shot channel.
///
/// This function is similar to Rust's channels found in the standard library.
/// Two halves are returned, the first of which is a `Sender` handle, used to
/// signal the end of a computation and provide its value. The second half is a
/// `Receiver` which implements the `Future` trait, resolving to the value that
/// was given to the `Sender` handle.
///
/// Each half can be separately owned and sent across threads/tasks.
///
/// # Examples
///
/// ```
/// use std::thread;
/// use futures::sync::oneshot;
/// use futures::*;
///
/// let (c, p) = oneshot::channel::<i32>();
///
/// thread::spawn(|| {
///     p.map(|i| {
///         println!("got: {}", i);
///     }).wait();
/// });
///
/// c.send(3).unwrap();
/// ```
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let inner = Arc::new(Inner {
        complete: AtomicBool::new(false),
        data: Lock::new(None),
        rx_task: Lock::new(None),
        tx_task: Lock::new(None),
    });
    let receiver = Receiver {
        inner: inner.clone(),
    };
    let sender = Sender {
        inner: inner,
    };
    (sender, receiver)
}

impl<T> Sender<T> {
    #[deprecated(note = "renamed to `send`", since = "0.1.11")]
    #[doc(hidden)]
    #[cfg(feature = "with-deprecated")]
    pub fn complete(self, t: T) {
        drop(self.send(t));
    }

    /// Completes this oneshot with a successful result.
    ///
    /// This function will consume `self` and indicate to the other end, the
    /// `Receiver`, that the error provided is the result of the computation this
    /// represents.
    ///
    /// If the value is successfully enqueued for the remote end to receive,
    /// then `Ok(())` is returned. If the receiving end was deallocated before
    /// this function was called, however, then `Err` is returned with the value
    /// provided.
    pub fn send(self, t: T) -> Result<(), T> {
        if self.inner.complete.load(SeqCst) {
            return Err(t)
        }

        // Note that this lock acquisition should always succeed as it can only
        // interfere with `poll` in `Receiver` which is only called when the
        // `complete` flag is true, which we're setting here.
        let mut slot = self.inner.data.try_lock().unwrap();
        assert!(slot.is_none());
        *slot = Some(t);
        drop(slot);
        Ok(())
    }

    /// Polls this `Sender` half to detect whether the `Receiver` this has
    /// paired with has gone away.
    ///
    /// This function can be used to learn about when the `Receiver` (consumer)
    /// half has gone away and nothing will be able to receive a message sent
    /// from `complete`.
    ///
    /// Like `Future::poll`, this function will panic if it's not called from
    /// within the context of a task. In otherwords, this should only ever be
    /// called from inside another future.
    ///
    /// If `Ready` is returned then it means that the `Receiver` has disappeared
    /// and the result this `Sender` would otherwise produce should no longer
    /// be produced.
    ///
    /// If `NotReady` is returned then the `Receiver` is still alive and may be
    /// able to receive a message if sent. The current task, however, is
    /// scheduled to receive a notification if the corresponding `Receiver` goes
    /// away.
    pub fn poll_cancel(&mut self) -> Poll<(), ()> {
        // Fast path up first, just read the flag and see if our other half is
        // gone. This flag is set both in our destructor and the oneshot
        // destructor, but our destructor hasn't run yet so if it's set then the
        // oneshot is gone.
        if self.inner.complete.load(SeqCst) {
            return Ok(Async::Ready(()))
        }

        // If our other half is not gone then we need to park our current task
        // and move it into the `notify_cancel` slot to get notified when it's
        // actually gone.
        //
        // If `try_lock` fails, then the `Receiver` is in the process of using
        // it, so we can deduce that it's now in the process of going away and
        // hence we're canceled. If it succeeds then we just store our handle.
        //
        // Crucially we then check `oneshot_gone` *again* before we return.
        // While we were storing our handle inside `notify_cancel` the `Receiver`
        // may have been dropped. The first thing it does is set the flag, and
        // if it fails to acquire the lock it assumes that we'll see the flag
        // later on. So... we then try to see the flag later on!
        let handle = task::park();
        match self.inner.tx_task.try_lock() {
            Some(mut p) => *p = Some(handle),
            None => return Ok(Async::Ready(())),
        }
        if self.inner.complete.load(SeqCst) {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        // Flag that we're a completed `Sender` and try to wake up a receiver.
        // Whether or not we actually stored any data will get picked up and
        // translated to either an item or cancellation.
        //
        // Note that if we fail to acquire the `rx_task` lock then that means
        // we're in one of two situations:
        //
        // 1. The receiver is trying to block in `poll`
        // 2. The receiver is being dropped
        //
        // In the first case it'll check the `complete` flag after it's done
        // blocking to see if it succeeded. In the latter case we don't need to
        // wake up anyone anyway. So in both cases it's ok to ignore the `None`
        // case of `try_lock` and bail out.
        //
        // The first case crucially depends on `Lock` using `SeqCst` ordering
        // under the hood. If it instead used `Release` / `Acquire` ordering,
        // then it would not necessarily synchronize with `inner.complete`
        // and deadlock might be possible, as was observed in
        // https://github.com/alexcrichton/futures-rs/pull/219.
        self.inner.complete.store(true, SeqCst);
        if let Some(mut slot) = self.inner.rx_task.try_lock() {
            if let Some(task) = slot.take() {
                drop(slot);
                task.unpark();
            }
        }
    }
}

/// Error returned from a `Receiver<T>` whenever the correponding `Sender<T>`
/// is dropped.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Canceled;

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

impl Error for Canceled {
    fn description(&self) -> &str {
        "oneshot canceled"
    }
}

impl<T> Receiver<T> {
    /// Gracefully close this receiver, preventing sending any future messages.
    ///
    /// Any `send` operation which happens after this method returns is
    /// guaranteed to fail. Once this method is called the normal `poll` method
    /// can be used to determine whether a message was actually sent or not. If
    /// `Canceled` is returned from `poll` then no message was sent.
    pub fn close(&mut self) {
        // Flag our completion and then attempt to wake up the sender if it's
        // blocked. See comments in `drop` below for more info
        self.inner.complete.store(true, SeqCst);
        if let Some(mut handle) = self.inner.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.unpark()
            }
        }
    }
}

impl<T> Future for Receiver<T> {
    type Item = T;
    type Error = Canceled;

    fn poll(&mut self) -> Poll<T, Canceled> {
        let mut done = false;

        // Check to see if some data has arrived. If it hasn't then we need to
        // block our task.
        //
        // Note that the acquisition of the `rx_task` lock might fail below, but
        // the only situation where this can happen is during `Sender::drop`
        // when we are indeed completed already. If that's happening then we
        // know we're completed so keep going.
        if self.inner.complete.load(SeqCst) {
            done = true;
        } else {
            let task = task::park();
            match self.inner.rx_task.try_lock() {
                Some(mut slot) => *slot = Some(task),
                None => done = true,
            }
        }

        // If we're `done` via one of the paths above, then look at the data and
        // figure out what the answer is. If, however, we stored `rx_task`
        // successfully above we need to check again if we're completed in case
        // a message was sent while `rx_task` was locked and couldn't notify us
        // otherwise.
        //
        // If we're not done, and we're not complete, though, then we've
        // successfully blocked our task and we return `NotReady`.
        if done || self.inner.complete.load(SeqCst) {
            match self.inner.data.try_lock().unwrap().take() {
                Some(data) => Ok(data.into()),
                None => Err(Canceled),
            }
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl<T> Drop for Receiver<T> {
    fn drop(&mut self) {
        // Indicate to the `Sender` that we're done, so any future calls to
        // `poll_cancel` are weeded out.
        self.inner.complete.store(true, SeqCst);

        // If we've blocked a task then there's no need for it to stick around,
        // so we need to drop it. If this lock acquisition fails, though, then
        // it's just because our `Sender` is trying to take the task, so we
        // let them take care of that.
        if let Some(mut slot) = self.inner.rx_task.try_lock() {
            let task = slot.take();
            drop(slot);
            drop(task);
        }

        // Finally, if our `Sender` wants to get notified of us going away, it
        // would have stored something in `tx_task`. Here we try to peel that
        // out and unpark it.
        //
        // Note that the `try_lock` here may fail, but only if the `Sender` is
        // in the process of filling in the task. If that happens then we
        // already flagged `complete` and they'll pick that up above.
        if let Some(mut handle) = self.inner.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.unpark()
            }
        }
    }
}
<commit_msg>Fix confusing wording in oneshot::Sender docs<commit_after>//! A one-shot, futures-aware channel

use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::error::Error;
use std::fmt;

use {Future, Poll, Async};
use lock::Lock;
use task::{self, Task};

/// A future representing the completion of a computation happening elsewhere in
/// memory.
///
/// This is created by the `oneshot::channel` function.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct Receiver<T> {
    inner: Arc<Inner<T>>,
}

/// Represents the completion half of a oneshot through which the result of a
/// computation is signaled.
///
/// This is created by the `oneshot::channel` function.
#[derive(Debug)]
pub struct Sender<T> {
    inner: Arc<Inner<T>>,
}

/// Internal state of the `Receiver`/`Sender` pair above. This is all used as
/// the internal synchronization between the two for send/recv operations.
#[derive(Debug)]
struct Inner<T> {
    /// Indicates whether this oneshot is complete yet. This is filled in both
    /// by `Sender::drop` and by `Receiver::drop`, and both sides iterpret it
    /// appropriately.
    ///
    /// For `Receiver`, if this is `true`, then it's guaranteed that `data` is
    /// unlocked and ready to be inspected.
    ///
    /// For `Sender` if this is `true` then the oneshot has gone away and it
    /// can return ready from `poll_cancel`.
    complete: AtomicBool,

    /// The actual data being transferred as part of this `Receiver`. This is
    /// filled in by `Sender::complete` and read by `Receiver::poll`.
    ///
    /// Note that this is protected by `Lock`, but it is in theory safe to
    /// replace with an `UnsafeCell` as it's actually protected by `complete`
    /// above. I wouldn't recommend doing this, however, unless someone is
    /// supremely confident in the various atomic orderings here and there.
    data: Lock<Option<T>>,

    /// Field to store the task which is blocked in `Receiver::poll`.
    ///
    /// This is filled in when a oneshot is polled but not ready yet. Note that
    /// the `Lock` here, unlike in `data` above, is important to resolve races.
    /// Both the `Receiver` and the `Sender` halves understand that if they
    /// can't acquire the lock then some important interference is happening.
    rx_task: Lock<Option<Task>>,

    /// Like `rx_task` above, except for the task blocked in
    /// `Sender::poll_cancel`. Additionally, `Lock` cannot be `UnsafeCell`.
    tx_task: Lock<Option<Task>>,
}

/// Creates a new futures-aware, one-shot channel.
///
/// This function is similar to Rust's channels found in the standard library.
/// Two halves are returned, the first of which is a `Sender` handle, used to
/// signal the end of a computation and provide its value. The second half is a
/// `Receiver` which implements the `Future` trait, resolving to the value that
/// was given to the `Sender` handle.
///
/// Each half can be separately owned and sent across threads/tasks.
///
/// # Examples
///
/// ```
/// use std::thread;
/// use futures::sync::oneshot;
/// use futures::*;
///
/// let (c, p) = oneshot::channel::<i32>();
///
/// thread::spawn(|| {
///     p.map(|i| {
///         println!("got: {}", i);
///     }).wait();
/// });
///
/// c.send(3).unwrap();
/// ```
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let inner = Arc::new(Inner {
        complete: AtomicBool::new(false),
        data: Lock::new(None),
        rx_task: Lock::new(None),
        tx_task: Lock::new(None),
    });
    let receiver = Receiver {
        inner: inner.clone(),
    };
    let sender = Sender {
        inner: inner,
    };
    (sender, receiver)
}

impl<T> Sender<T> {
    #[deprecated(note = "renamed to `send`", since = "0.1.11")]
    #[doc(hidden)]
    #[cfg(feature = "with-deprecated")]
    pub fn complete(self, t: T) {
        drop(self.send(t));
    }

    /// Completes this oneshot with a successful result.
    ///
    /// This function will consume `self` and indicate to the other end, the
    /// `Receiver`, that the value provided is the result of the computation this
    /// represents.
    ///
    /// If the value is successfully enqueued for the remote end to receive,
    /// then `Ok(())` is returned. If the receiving end was deallocated before
    /// this function was called, however, then `Err` is returned with the value
    /// provided.
    pub fn send(self, t: T) -> Result<(), T> {
        if self.inner.complete.load(SeqCst) {
            return Err(t)
        }

        // Note that this lock acquisition should always succeed as it can only
        // interfere with `poll` in `Receiver` which is only called when the
        // `complete` flag is true, which we're setting here.
        let mut slot = self.inner.data.try_lock().unwrap();
        assert!(slot.is_none());
        *slot = Some(t);
        drop(slot);
        Ok(())
    }

    /// Polls this `Sender` half to detect whether the `Receiver` this has
    /// paired with has gone away.
    ///
    /// This function can be used to learn about when the `Receiver` (consumer)
    /// half has gone away and nothing will be able to receive a message sent
    /// from `complete`.
    ///
    /// Like `Future::poll`, this function will panic if it's not called from
    /// within the context of a task. In otherwords, this should only ever be
    /// called from inside another future.
    ///
    /// If `Ready` is returned then it means that the `Receiver` has disappeared
    /// and the result this `Sender` would otherwise produce should no longer
    /// be produced.
    ///
    /// If `NotReady` is returned then the `Receiver` is still alive and may be
    /// able to receive a message if sent. The current task, however, is
    /// scheduled to receive a notification if the corresponding `Receiver` goes
    /// away.
    pub fn poll_cancel(&mut self) -> Poll<(), ()> {
        // Fast path up first, just read the flag and see if our other half is
        // gone. This flag is set both in our destructor and the oneshot
        // destructor, but our destructor hasn't run yet so if it's set then the
        // oneshot is gone.
        if self.inner.complete.load(SeqCst) {
            return Ok(Async::Ready(()))
        }

        // If our other half is not gone then we need to park our current task
        // and move it into the `notify_cancel` slot to get notified when it's
        // actually gone.
        //
        // If `try_lock` fails, then the `Receiver` is in the process of using
        // it, so we can deduce that it's now in the process of going away and
        // hence we're canceled. If it succeeds then we just store our handle.
        //
        // Crucially we then check `oneshot_gone` *again* before we return.
        // While we were storing our handle inside `notify_cancel` the `Receiver`
        // may have been dropped. The first thing it does is set the flag, and
        // if it fails to acquire the lock it assumes that we'll see the flag
        // later on. So... we then try to see the flag later on!
        let handle = task::park();
        match self.inner.tx_task.try_lock() {
            Some(mut p) => *p = Some(handle),
            None => return Ok(Async::Ready(())),
        }
        if self.inner.complete.load(SeqCst) {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        // Flag that we're a completed `Sender` and try to wake up a receiver.
        // Whether or not we actually stored any data will get picked up and
        // translated to either an item or cancellation.
        //
        // Note that if we fail to acquire the `rx_task` lock then that means
        // we're in one of two situations:
        //
        // 1. The receiver is trying to block in `poll`
        // 2. The receiver is being dropped
        //
        // In the first case it'll check the `complete` flag after it's done
        // blocking to see if it succeeded. In the latter case we don't need to
        // wake up anyone anyway. So in both cases it's ok to ignore the `None`
        // case of `try_lock` and bail out.
        //
        // The first case crucially depends on `Lock` using `SeqCst` ordering
        // under the hood. If it instead used `Release` / `Acquire` ordering,
        // then it would not necessarily synchronize with `inner.complete`
        // and deadlock might be possible, as was observed in
        // https://github.com/alexcrichton/futures-rs/pull/219.
        self.inner.complete.store(true, SeqCst);
        if let Some(mut slot) = self.inner.rx_task.try_lock() {
            if let Some(task) = slot.take() {
                drop(slot);
                task.unpark();
            }
        }
    }
}

/// Error returned from a `Receiver<T>` whenever the correponding `Sender<T>`
/// is dropped.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Canceled;

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

impl Error for Canceled {
    fn description(&self) -> &str {
        "oneshot canceled"
    }
}

impl<T> Receiver<T> {
    /// Gracefully close this receiver, preventing sending any future messages.
    ///
    /// Any `send` operation which happens after this method returns is
    /// guaranteed to fail. Once this method is called the normal `poll` method
    /// can be used to determine whether a message was actually sent or not. If
    /// `Canceled` is returned from `poll` then no message was sent.
    pub fn close(&mut self) {
        // Flag our completion and then attempt to wake up the sender if it's
        // blocked. See comments in `drop` below for more info
        self.inner.complete.store(true, SeqCst);
        if let Some(mut handle) = self.inner.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.unpark()
            }
        }
    }
}

impl<T> Future for Receiver<T> {
    type Item = T;
    type Error = Canceled;

    fn poll(&mut self) -> Poll<T, Canceled> {
        let mut done = false;

        // Check to see if some data has arrived. If it hasn't then we need to
        // block our task.
        //
        // Note that the acquisition of the `rx_task` lock might fail below, but
        // the only situation where this can happen is during `Sender::drop`
        // when we are indeed completed already. If that's happening then we
        // know we're completed so keep going.
        if self.inner.complete.load(SeqCst) {
            done = true;
        } else {
            let task = task::park();
            match self.inner.rx_task.try_lock() {
                Some(mut slot) => *slot = Some(task),
                None => done = true,
            }
        }

        // If we're `done` via one of the paths above, then look at the data and
        // figure out what the answer is. If, however, we stored `rx_task`
        // successfully above we need to check again if we're completed in case
        // a message was sent while `rx_task` was locked and couldn't notify us
        // otherwise.
        //
        // If we're not done, and we're not complete, though, then we've
        // successfully blocked our task and we return `NotReady`.
        if done || self.inner.complete.load(SeqCst) {
            match self.inner.data.try_lock().unwrap().take() {
                Some(data) => Ok(data.into()),
                None => Err(Canceled),
            }
        } else {
            Ok(Async::NotReady)
        }
    }
}

impl<T> Drop for Receiver<T> {
    fn drop(&mut self) {
        // Indicate to the `Sender` that we're done, so any future calls to
        // `poll_cancel` are weeded out.
        self.inner.complete.store(true, SeqCst);

        // If we've blocked a task then there's no need for it to stick around,
        // so we need to drop it. If this lock acquisition fails, though, then
        // it's just because our `Sender` is trying to take the task, so we
        // let them take care of that.
        if let Some(mut slot) = self.inner.rx_task.try_lock() {
            let task = slot.take();
            drop(slot);
            drop(task);
        }

        // Finally, if our `Sender` wants to get notified of us going away, it
        // would have stored something in `tx_task`. Here we try to peel that
        // out and unpark it.
        //
        // Note that the `try_lock` here may fail, but only if the `Sender` is
        // in the process of filling in the task. If that happens then we
        // already flagged `complete` and they'll pick that up above.
        if let Some(mut handle) = self.inner.tx_task.try_lock() {
            if let Some(task) = handle.take() {
                drop(handle);
                task.unpark()
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! A File primitive wrapper for managing file templates.
//!
//! # Examples
//!
//! ```no_run
//! # use inapi::{MapBuilder, Template};
//! let template = Template::new("/path/to/template").unwrap();
//! let data = MapBuilder::new().insert_str("key", "value").build();
//! let file = template.render_data(&data).unwrap();
//! ```

pub mod ffi;

use error::Result;
use error::Error;
use mustache;
use rustc_serialize::Encodable;
use std::convert::Into;
use std::fs;
use std::io::{Seek, SeekFrom};
use std::path::Path;
use tempfile::tempfile;

/// Container for rendering and uploading templates.
pub struct Template {
    inner: mustache::Template,
}

impl Template {
    /// Create a new File struct.
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Template> {
        if !path.as_ref().exists() {
            return Err(Error::Generic("Template path does not exist".into()));
        }

        Ok(Template {
            inner: try!(mustache::compile_path(path.as_ref())),
        })
    }

    /// Render template to file using generic Encodable data.
    pub fn render<T: Encodable>(&self, data: &T) -> Result<fs::File> {
        let mut fh = try!(tempfile());
        try!(self.inner.render(&mut fh, data));

        // Reset cursor to beginning of file for reading
        try!(fh.seek(SeekFrom::Start(0)));
        Ok(fh)
    }

    /// Render template to file using a Data instance.
    pub fn render_data(&self, data: &mustache::Data) -> Result<fs::File> {
        let mut fh = try!(tempfile());
        self.inner.render_data(&mut fh, data);

        // Reset cursor to beginning of file for reading
        try!(fh.seek(SeekFrom::Start(0)));
        Ok(fh)
    }
}

#[cfg(test)]
mod tests {
    use mustache::MapBuilder;
    use std::fs;
    use std::io::{Read, Write};
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_new() {
        let tempdir = TempDir::new("template_test_render").unwrap();
        let template_path = format!("{}/template.mustache", tempdir.path().to_str().unwrap());

        assert!(Template::new(&template_path).is_err());

        fs::File::create(&template_path).unwrap();
        Template::new(&template_path).unwrap();
        assert!(Template::new(&template_path).is_ok());
    }

    #[test]
    fn test_render() {
        let tempdir = TempDir::new("template_test_render").unwrap();
        let template_path = format!("{}/template.mustache", tempdir.path().to_str().unwrap());

        let template_str = "Hello, {{name}}!".to_string();
        let data = TestData {
            name: "Jasper Beardly"
        };

        let mut fh = fs::File::create(&template_path).unwrap();
        fh.write_all(template_str.as_bytes()).unwrap();

        let template = Template::new(&template_path).unwrap();
        let mut fh = template.render(&data).unwrap();
        let mut content = String::new();
        fh.read_to_string(&mut content).unwrap();
        assert_eq!(content, "Hello, Jasper Beardly!");
    }

    #[test]
    fn test_render_data_to_file() {
        let tempdir = TempDir::new("template_test_render").unwrap();
        let template_path = format!("{}/template.mustache", tempdir.path().to_str().unwrap());

        let template_str = "Hello, {{name}}!".to_string();
        let data = MapBuilder::new().insert_str("name", "Jasper Beardly").build();

        let mut fh = fs::File::create(&template_path).unwrap();
        fh.write_all(template_str.as_bytes()).unwrap();

        let template = Template::new(&template_path).unwrap();
        let mut fh = template.render_data(&data).unwrap();
        let mut content = String::new();
        fh.read_to_string(&mut content).unwrap();
        assert_eq!(content, "Hello, Jasper Beardly!");
    }

    #[derive(RustcEncodable)]
    struct TestData {
        name: &'static str,
    }
}
<commit_msg>Added extra doc example for uploading rendered templates via File primitive<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! A File primitive wrapper for managing file templates.
//!
//! # Examples
//!
//! ```no_run
//! # use inapi::{MapBuilder, Template};
//! let template = Template::new("/path/to/template").unwrap();
//! let data = MapBuilder::new().insert_str("key", "value").build();
//! let rendered_file = template.render_data(&data).unwrap();
//! ```
//!
//! To upload the rendered file to your host, you can pass it
//! straight into the File primitive:
//!
//! ```no_run
//! # use inapi::{File, Host, MapBuilder, Template};
//! # let template = Template::new("/path/to/template").unwrap();
//! # let data = MapBuilder::new().insert_str("key", "value").build();
//! # let rendered_file = template.render_data(&data).unwrap();
//! let mut host = Host::new();
#![cfg_attr(feature = "remote-run", doc = "host.connect(\"myhost.example.com\", 7101, 7102).unwrap();")]
//!
//! let file = File::new(&mut host, "/path/to/remote/file").unwrap();
//! file.upload_file(&mut host, rendered_file, None).unwrap();
//! ```

pub mod ffi;

use error::Result;
use error::Error;
use mustache;
use rustc_serialize::Encodable;
use std::convert::Into;
use std::fs;
use std::io::{Seek, SeekFrom};
use std::path::Path;
use tempfile::tempfile;

/// Container for rendering and uploading templates.
pub struct Template {
    inner: mustache::Template,
}

impl Template {
    /// Create a new File struct.
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Template> {
        if !path.as_ref().exists() {
            return Err(Error::Generic("Template path does not exist".into()));
        }

        Ok(Template {
            inner: try!(mustache::compile_path(path.as_ref())),
        })
    }

    /// Render template to file using generic Encodable data.
    pub fn render<T: Encodable>(&self, data: &T) -> Result<fs::File> {
        let mut fh = try!(tempfile());
        try!(self.inner.render(&mut fh, data));

        // Reset cursor to beginning of file for reading
        try!(fh.seek(SeekFrom::Start(0)));
        Ok(fh)
    }

    /// Render template to file using a Data instance.
    pub fn render_data(&self, data: &mustache::Data) -> Result<fs::File> {
        let mut fh = try!(tempfile());
        self.inner.render_data(&mut fh, data);

        // Reset cursor to beginning of file for reading
        try!(fh.seek(SeekFrom::Start(0)));
        Ok(fh)
    }
}

#[cfg(test)]
mod tests {
    use mustache::MapBuilder;
    use std::fs;
    use std::io::{Read, Write};
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_new() {
        let tempdir = TempDir::new("template_test_render").unwrap();
        let template_path = format!("{}/template.mustache", tempdir.path().to_str().unwrap());

        assert!(Template::new(&template_path).is_err());

        fs::File::create(&template_path).unwrap();
        Template::new(&template_path).unwrap();
        assert!(Template::new(&template_path).is_ok());
    }

    #[test]
    fn test_render() {
        let tempdir = TempDir::new("template_test_render").unwrap();
        let template_path = format!("{}/template.mustache", tempdir.path().to_str().unwrap());

        let template_str = "Hello, {{name}}!".to_string();
        let data = TestData {
            name: "Jasper Beardly"
        };

        let mut fh = fs::File::create(&template_path).unwrap();
        fh.write_all(template_str.as_bytes()).unwrap();

        let template = Template::new(&template_path).unwrap();
        let mut fh = template.render(&data).unwrap();
        let mut content = String::new();
        fh.read_to_string(&mut content).unwrap();
        assert_eq!(content, "Hello, Jasper Beardly!");
    }

    #[test]
    fn test_render_data_to_file() {
        let tempdir = TempDir::new("template_test_render").unwrap();
        let template_path = format!("{}/template.mustache", tempdir.path().to_str().unwrap());

        let template_str = "Hello, {{name}}!".to_string();
        let data = MapBuilder::new().insert_str("name", "Jasper Beardly").build();

        let mut fh = fs::File::create(&template_path).unwrap();
        fh.write_all(template_str.as_bytes()).unwrap();

        let template = Template::new(&template_path).unwrap();
        let mut fh = template.render_data(&data).unwrap();
        let mut content = String::new();
        fh.read_to_string(&mut content).unwrap();
        assert_eq!(content, "Hello, Jasper Beardly!");
    }

    #[derive(RustcEncodable)]
    struct TestData {
        name: &'static str,
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::f64::consts::PI;

use cache::{GeneratedAsset, WebAsset};
use terrain::dem::{self, DemSource, DigitalElevationModelParams};

/// This file assumes that all coordinates are provided relative to the earth represented as a
/// perfect sphere. This isn't quite accurate: The coordinate system of the input datasets are
/// actually WGS84 or NAD83. However, for our purposes the difference should not be noticable.

pub struct TerrainFileParams {
    pub latitude: i16,
    pub longitude: i16,
    pub source: DemSource,
}
impl GeneratedAsset for TerrainFileParams {
    type Type = TerrainFile;

    fn filename(&self) -> String {
        let n_or_s = if self.latitude >= 0 { 'n' } else { 's' };
        let e_or_w = if self.longitude >= 0 { 'e' } else { 'w' };
        format!(
            "maps/{}{:02}_{}{:03}_{}m.data",
            n_or_s,
            self.latitude.abs(),
            e_or_w,
            self.longitude.abs(),
            self.source.resolution(),
        )
    }

    fn generate(&self) -> Result<Self::Type, Box<Error>> {
        let dem = DigitalElevationModelParams {
            latitude: self.latitude,
            longitude: self.longitude,
            source: self.source,
        }.load()?;
        Ok(Self::Type::from_digital_elevation_model(dem))
    }
}

/// The radius of the earth in meters.
const EARTH_RADIUS: f64 = 6371000.0;
const EARTH_CIRCUMFERENCE: f64 = 2.0 * PI * EARTH_RADIUS;

#[derive(Serialize, Deserialize)]
pub struct TerrainFile {
    width: usize,
    height: usize,
    cell_size: f32,

    elevations: Vec<f32>,
    slopes: Vec<(f32, f32)>,
    shadows: Vec<f32>,
}

impl TerrainFile {
    fn compute_slopes(
        width: usize,
        height: usize,
        cell_size: f32,
        elevations: &[f32],
    ) -> Vec<(f32, f32)> {
        let get_elevation = |x: usize, y: usize| {
            assert!(x < width);
            assert!(y < height);
            elevations[x + y * width]
        };

        let mut slopes = Vec::with_capacity(width * height);
        for y in 0..height {
            for x in 0..width {
                let xslope = if x == 0 {
                    (get_elevation(x + 1, y) - get_elevation(x, y)) / cell_size
                } else if x == width - 1 {
                    (get_elevation(x, y) - get_elevation(x - 1, y)) / cell_size
                } else {
                    (get_elevation(x + 1, y) - get_elevation(x - 1, y)) / (2.0 * cell_size)
                };

                let yslope = if y == 0 {
                    (get_elevation(x, y + 1) - get_elevation(x, y)) / cell_size
                } else if y == height - 1 {
                    (get_elevation(x, y) - get_elevation(x, y - 1)) / cell_size
                } else {
                    (get_elevation(x, y + 1) - get_elevation(x, y - 1)) / (2.0 * cell_size)
                };

                slopes.push((xslope, yslope));
            }
        }

        slopes
    }

    fn compute_shadows(
        width: usize,
        height: usize,
        cell_size: f32,
        elevations: &[f32],
    ) -> Vec<f32> {
        let get_elevation = |x: usize, y: usize| {
            assert!(x < width);
            assert!(y < height);
            elevations[x + y * width]
        };

        let ray_slope = 0.4 * cell_size;

        let mut shadows = Vec::with_capacity(width * height);
        for y in 0..height {
            let mut highest = None;
            for x in 0..width {
                let h = get_elevation(x, y);
                let shadow_height = highest
                    .as_ref()
                    .map(|&(sx, sh)| sh - ((x - sx) as f32) * ray_slope)
                    .unwrap_or(h - 1.0);

                if shadow_height < h {
                    highest = Some((x, h));
                }

                shadows.push(shadow_height);
            }
        }

        shadows
    }

    /// Construct a `TerrainFile` from a `DigitalElevationModel`.
    pub fn from_digital_elevation_model(dem: dem::DigitalElevationModel) -> Self {
        // Compute approximate cell size in meters.
        let ycenter = dem.yllcorner + 0.5 * dem.cell_size * dem.height as f64;
        let cell_size_x = (dem.cell_size / 360.0) * EARTH_CIRCUMFERENCE *
            ycenter.to_radians().cos();
        let cell_size_y = (dem.cell_size / 360.0) * EARTH_CIRCUMFERENCE;
        let cell_size = cell_size_y as f32;

        let cell_size_ratio = cell_size_y / cell_size_x;
        let width = (dem.width as f64 / cell_size_ratio).floor() as usize;
        let height = dem.height;
        let mut elevations = Vec::with_capacity(width * height);

        for y in 0..height {
            for x in 0..width {
                let fx = x as f64 * cell_size_ratio;
                let floor_fx = fx.floor() as usize;
                let ceil_fx = fx.ceil() as usize;
                assert!(floor_fx < dem.width);
                assert!(ceil_fx < dem.width);
                let t = fx.fract() as f32;
                let h = dem.elevations[floor_fx + y * dem.width] * (1.0 - t) +
                    dem.elevations[ceil_fx + y * dem.width] * t;
                elevations.push(h)
            }
        }

        let slopes = Self::compute_slopes(width, height, cell_size, &elevations[..]);
        let shadows = Self::compute_shadows(width, height, cell_size, &elevations[..]);
        TerrainFile {
            width,
            height,
            cell_size,
            elevations,
            slopes,
            shadows,
        }
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.width
    }

    pub fn elevation(&self, x: usize, y: usize) -> f32 {
        assert!(x < self.width);
        assert!(y < self.height);
        self.elevations[x + y * self.width]
    }

    pub fn slope(&self, x: usize, y: usize) -> (f32, f32) {
        assert!(x < self.width);
        assert!(y < self.height);
        self.slopes[x + y * self.width]
    }

    pub fn elevations(&self) -> &[f32] {
        &self.elevations[..]
    }

    pub fn slopes(&self) -> &[(f32, f32)] {
        &self.slopes[..]
    }

    pub fn shadows(&self) -> &[f32] {
        &self.shadows[..]
    }

    pub fn cell_size(&self) -> f32 {
        self.cell_size
    }
}
<commit_msg>Fix typo: width -> height<commit_after>use std::error::Error;
use std::f64::consts::PI;

use cache::{GeneratedAsset, WebAsset};
use terrain::dem::{self, DemSource, DigitalElevationModelParams};

/// This file assumes that all coordinates are provided relative to the earth represented as a
/// perfect sphere. This isn't quite accurate: The coordinate system of the input datasets are
/// actually WGS84 or NAD83. However, for our purposes the difference should not be noticable.

pub struct TerrainFileParams {
    pub latitude: i16,
    pub longitude: i16,
    pub source: DemSource,
}
impl GeneratedAsset for TerrainFileParams {
    type Type = TerrainFile;

    fn filename(&self) -> String {
        let n_or_s = if self.latitude >= 0 { 'n' } else { 's' };
        let e_or_w = if self.longitude >= 0 { 'e' } else { 'w' };
        format!(
            "maps/{}{:02}_{}{:03}_{}m.data",
            n_or_s,
            self.latitude.abs(),
            e_or_w,
            self.longitude.abs(),
            self.source.resolution(),
        )
    }

    fn generate(&self) -> Result<Self::Type, Box<Error>> {
        let dem = DigitalElevationModelParams {
            latitude: self.latitude,
            longitude: self.longitude,
            source: self.source,
        }.load()?;
        Ok(Self::Type::from_digital_elevation_model(dem))
    }
}

/// The radius of the earth in meters.
const EARTH_RADIUS: f64 = 6371000.0;
const EARTH_CIRCUMFERENCE: f64 = 2.0 * PI * EARTH_RADIUS;

#[derive(Serialize, Deserialize)]
pub struct TerrainFile {
    width: usize,
    height: usize,
    cell_size: f32,

    elevations: Vec<f32>,
    slopes: Vec<(f32, f32)>,
    shadows: Vec<f32>,
}

impl TerrainFile {
    fn compute_slopes(
        width: usize,
        height: usize,
        cell_size: f32,
        elevations: &[f32],
    ) -> Vec<(f32, f32)> {
        let get_elevation = |x: usize, y: usize| {
            assert!(x < width);
            assert!(y < height);
            elevations[x + y * width]
        };

        let mut slopes = Vec::with_capacity(width * height);
        for y in 0..height {
            for x in 0..width {
                let xslope = if x == 0 {
                    (get_elevation(x + 1, y) - get_elevation(x, y)) / cell_size
                } else if x == width - 1 {
                    (get_elevation(x, y) - get_elevation(x - 1, y)) / cell_size
                } else {
                    (get_elevation(x + 1, y) - get_elevation(x - 1, y)) / (2.0 * cell_size)
                };

                let yslope = if y == 0 {
                    (get_elevation(x, y + 1) - get_elevation(x, y)) / cell_size
                } else if y == height - 1 {
                    (get_elevation(x, y) - get_elevation(x, y - 1)) / cell_size
                } else {
                    (get_elevation(x, y + 1) - get_elevation(x, y - 1)) / (2.0 * cell_size)
                };

                slopes.push((xslope, yslope));
            }
        }

        slopes
    }

    fn compute_shadows(
        width: usize,
        height: usize,
        cell_size: f32,
        elevations: &[f32],
    ) -> Vec<f32> {
        let get_elevation = |x: usize, y: usize| {
            assert!(x < width);
            assert!(y < height);
            elevations[x + y * width]
        };

        let ray_slope = 0.4 * cell_size;

        let mut shadows = Vec::with_capacity(width * height);
        for y in 0..height {
            let mut highest = None;
            for x in 0..width {
                let h = get_elevation(x, y);
                let shadow_height = highest
                    .as_ref()
                    .map(|&(sx, sh)| sh - ((x - sx) as f32) * ray_slope)
                    .unwrap_or(h - 1.0);

                if shadow_height < h {
                    highest = Some((x, h));
                }

                shadows.push(shadow_height);
            }
        }

        shadows
    }

    /// Construct a `TerrainFile` from a `DigitalElevationModel`.
    pub fn from_digital_elevation_model(dem: dem::DigitalElevationModel) -> Self {
        // Compute approximate cell size in meters.
        let ycenter = dem.yllcorner + 0.5 * dem.cell_size * dem.height as f64;
        let cell_size_x = (dem.cell_size / 360.0) * EARTH_CIRCUMFERENCE *
            ycenter.to_radians().cos();
        let cell_size_y = (dem.cell_size / 360.0) * EARTH_CIRCUMFERENCE;
        let cell_size = cell_size_y as f32;

        let cell_size_ratio = cell_size_y / cell_size_x;
        let width = (dem.width as f64 / cell_size_ratio).floor() as usize;
        let height = dem.height;
        let mut elevations = Vec::with_capacity(width * height);

        for y in 0..height {
            for x in 0..width {
                let fx = x as f64 * cell_size_ratio;
                let floor_fx = fx.floor() as usize;
                let ceil_fx = fx.ceil() as usize;
                assert!(floor_fx < dem.width);
                assert!(ceil_fx < dem.width);
                let t = fx.fract() as f32;
                let h = dem.elevations[floor_fx + y * dem.width] * (1.0 - t) +
                    dem.elevations[ceil_fx + y * dem.width] * t;
                elevations.push(h)
            }
        }

        let slopes = Self::compute_slopes(width, height, cell_size, &elevations[..]);
        let shadows = Self::compute_shadows(width, height, cell_size, &elevations[..]);
        TerrainFile {
            width,
            height,
            cell_size,
            elevations,
            slopes,
            shadows,
        }
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }

    pub fn elevation(&self, x: usize, y: usize) -> f32 {
        assert!(x < self.width);
        assert!(y < self.height);
        self.elevations[x + y * self.width]
    }

    pub fn slope(&self, x: usize, y: usize) -> (f32, f32) {
        assert!(x < self.width);
        assert!(y < self.height);
        self.slopes[x + y * self.width]
    }

    pub fn elevations(&self) -> &[f32] {
        &self.elevations[..]
    }

    pub fn slopes(&self) -> &[(f32, f32)] {
        &self.slopes[..]
    }

    pub fn shadows(&self) -> &[f32] {
        &self.shadows[..]
    }

    pub fn cell_size(&self) -> f32 {
        self.cell_size
    }
}
<|endoftext|>


<commit_before>export fold;
export fold_crate, fold_mod, fold_fn, fold_modlist, fold_fnlist;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_mod;
export default_seq_fold_fn;
export default_seq_fold_fnlist;

enum fold<T> = t<T>;

type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
type fold_modlist<T> = fn~(fold: fold<T>,list: doc::modlist) -> doc::modlist;
type fold_fnlist<T> = fn~(fold: fold<T>,list: doc::fnlist) -> doc::fnlist;

type t<T> = {
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>
};

// This exists because fn types don't infer correctly as record
// initializers, but they do as function arguments
fn mk_fold<T:copy>(
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>
) -> fold<T> {
    fold({
        ctxt: ctxt,
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_modlist: fold_modlist,
        fold_fnlist: fold_fnlist
    })
}

fn default_seq_fold<T:copy>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_modlist(f, d)},
        {|f, d| default_seq_fold_fnlist(f, d)}
    )
}

fn default_seq_fold_crate<T>(
    fold: fold<T>,
    doc: doc::cratedoc
) -> doc::cratedoc {
    ~{
        topmod: fold.fold_mod(fold, doc.topmod)
    }
}

fn default_seq_fold_mod<T>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    ~{
        mods: fold.fold_modlist(fold, doc.mods),
        fns: fold.fold_fnlist(fold, doc.fns)
        with *doc
    }
}

fn default_seq_fold_fn<T>(
    _fold: fold<T>,
    doc: doc::fndoc
) -> doc::fndoc {
    doc
}

fn default_seq_fold_modlist<T>(
    fold: fold<T>,
    list: doc::modlist
) -> doc::modlist {
    doc::modlist(vec::map(*list) {|doc|
        fold.fold_mod(fold, doc)
    })
}

fn default_seq_fold_fnlist<T>(
    fold: fold<T>,
    list: doc::fnlist
) -> doc::fnlist {
    doc::fnlist(vec::map(*list) {|doc|
        fold.fold_fn(fold, doc)
    })
}

#[cfg(test)]
mod tests {
    #[test]
    fn default_fold_should_produce_same_doc() {
        let source = "mod a { fn b() { } mod c { fn d() { } } }";
        let ast = parse::from_str(source);
        let doc = extract::extract(ast, "");
        let fld = default_seq_fold(());
        let folded = fld.fold_crate(fld, doc);
        assert doc == folded;
    }
}<commit_msg>rustdoc: Add fold_const and fold_constlist to fold<commit_after>// FIXME: Random import to solve the mystery resolve bug
import std;

export fold;
export fold_crate, fold_mod, fold_fn, fold_modlist, fold_fnlist;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_mod;
export default_seq_fold_fn;
export default_seq_fold_fnlist;

enum fold<T> = t<T>;

type fold_crate<T> = fn~(fold: fold<T>, doc: doc::cratedoc) -> doc::cratedoc;
type fold_mod<T> = fn~(fold: fold<T>, doc: doc::moddoc) -> doc::moddoc;
type fold_fn<T> = fn~(fold: fold<T>, doc: doc::fndoc) -> doc::fndoc;
type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
type fold_modlist<T> = fn~(fold: fold<T>, list: doc::modlist) -> doc::modlist;
type fold_fnlist<T> = fn~(fold: fold<T>, list: doc::fnlist) -> doc::fnlist;
type fold_constlist<T> = fn~(
    fold: fold<T>,
    list: doc::constlist
) -> doc::constlist;

type t<T> = {
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>,
    fold_constlist: fold_constlist<T>
};

// This exists because fn types don't infer correctly as record
// initializers, but they do as function arguments
fn mk_fold<T:copy>(
    ctxt: T,
    fold_crate: fold_crate<T>,
    fold_mod: fold_mod<T>,
    fold_fn: fold_fn<T>,
    fold_const: fold_const<T>,
    fold_modlist: fold_modlist<T>,
    fold_fnlist: fold_fnlist<T>,
    fold_constlist: fold_constlist<T>
) -> fold<T> {
    fold({
        ctxt: ctxt,
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_modlist: fold_modlist,
        fold_fnlist: fold_fnlist,
        fold_constlist: fold_constlist
    })
}

fn default_seq_fold<T:copy>(ctxt: T) -> fold<T> {
    mk_fold(
        ctxt,
        {|f, d| default_seq_fold_crate(f, d)},
        {|f, d| default_seq_fold_mod(f, d)},
        {|f, d| default_seq_fold_fn(f, d)},
        {|f, d| default_seq_fold_const(f, d)},
        {|f, d| default_seq_fold_modlist(f, d)},
        {|f, d| default_seq_fold_fnlist(f, d)},
        {|f, d| default_seq_fold_constlist(f, d)}
    )
}

fn default_seq_fold_crate<T>(
    fold: fold<T>,
    doc: doc::cratedoc
) -> doc::cratedoc {
    ~{
        topmod: fold.fold_mod(fold, doc.topmod)
    }
}

fn default_seq_fold_mod<T>(
    fold: fold<T>,
    doc: doc::moddoc
) -> doc::moddoc {
    ~{
        mods: fold.fold_modlist(fold, doc.mods),
        fns: fold.fold_fnlist(fold, doc.fns)
        with *doc
    }
}

fn default_seq_fold_fn<T>(
    _fold: fold<T>,
    doc: doc::fndoc
) -> doc::fndoc {
    doc
}

fn default_seq_fold_const<T>(
    _fold: fold<T>,
    doc: doc::constdoc
) -> doc::constdoc {
    doc
}

fn default_seq_fold_modlist<T>(
    fold: fold<T>,
    list: doc::modlist
) -> doc::modlist {
    doc::modlist(vec::map(*list) {|doc|
        fold.fold_mod(fold, doc)
    })
}

fn default_seq_fold_fnlist<T>(
    fold: fold<T>,
    list: doc::fnlist
) -> doc::fnlist {
    doc::fnlist(vec::map(*list) {|doc|
        fold.fold_fn(fold, doc)
    })
}

fn default_seq_fold_constlist<T>(
    fold: fold<T>,
    list: doc::constlist
) -> doc::constlist {
    doc::constlist(vec::map(*list) {|doc|
        fold.fold_const(fold, doc)
    })
}

#[test]
fn default_fold_should_produce_same_doc() {
    let source = "mod a { fn b() { } mod c { fn d() { } } }";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}

#[test]
fn default_fold_should_produce_same_consts() {
    let source = "const a: int = 0;";
    let ast = parse::from_str(source);
    let doc = extract::extract(ast, "");
    let fld = default_seq_fold(());
    let folded = fld.fold_crate(fld, doc);
    assert doc == folded;
}<|endoftext|>


<commit_before>//! Code related to task scheduling and priorities.
use std::collections::{LinkedList, HashMap, HashSet};
//use std::sync;

use defs::Word;
use emulator::process;
use emulator::process::Process;
use emulator::gen_atoms;
use term::lterm::LTerm;

fn module() -> &'static str { "scheduler: " }

#[derive(Debug, Clone, Copy)]
pub enum Prio {
  /// Runs when no more jobs to take or at 8x disadvantage to normal
  Low = 0,
  /// Most of user processes run at this priority
  Normal = 1,
  /// Takes priority always over everything else
  High = 2,
}

/// Enum identifies current registration of the process
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Queue {
  None,
  //PendingTimers,
  High,
  Normal,
  Low,
  TimedWait,
  InfiniteWait,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SliceResult {
  None,
  /// Process willingly gave up run queue (ended the timeslice without events)
  Yield,
  /// Process entered infinite or timed wait during the last timeslice
  Wait,
  /// Process normally finished during the last timeslice
  Finished,
  /// Error, exit or throw occured during the last timeslice
  Exception,
}

/// How many Normal processes can be scheduled before Low gets to run.
const NORMAL_ADVANTAGE: Word = 8;

/// Maintains run queues for different priorities and allows queuing processes,
/// suspending processes, work balancing (TODO), etc.
pub struct Scheduler {
  // This is the naive implementation of run queues.
  // A better approach would be to build an intrusive double linked list through
  // every process in the queue (as done by the original ERTS).
  queue_low: LinkedList<LTerm>,
  queue_normal: LinkedList<LTerm>,
  queue_high: LinkedList<LTerm>,

  /// A counter used to skip some schedulings for low processes
  advantage_count: Word,

  /// Currently selected process
  current: Option<process::Ptr>,

  /// Wait set for infinitely suspended processes (in endless receive)
  wait_inf: HashSet<LTerm>,
  /// Wait set for timed suspended processes (waiting for a timer)
  wait_timed: HashSet<LTerm>,

  /// Dict of pids to process boxes. Owned by the scheduler
  processes: HashMap<LTerm, process::Ptr>,
}

impl Scheduler {
  pub fn new() -> Scheduler {
    Scheduler{
      queue_low: LinkedList::new(),
      queue_normal: LinkedList::new(),
      queue_high: LinkedList::new(),

      advantage_count: NORMAL_ADVANTAGE,
      current: None,

      wait_inf: HashSet::new(),
      wait_timed: HashSet::new(),

      processes: HashMap::new(),
    }
  }

  /// Register a process `proc_` in the process table and also queue it for
  /// execution. This is invoked by vm when a new process is spawned.
  pub fn add(&mut self, pid: LTerm, proc_: process::Ptr) {
    self.processes.insert(pid, proc_.clone());
    self.queue(pid);
  }

  /// Queue a process by its pid. Will `panic!` if the process doesn't exist
  /// or is already queued.
  pub fn queue(&mut self, pid: LTerm) {
    assert!(pid.is_local_pid());

    let prio = {
      // Lookup the pid
      let p_arc = self.lookup_pid(pid).unwrap();

      // Read-lock the rwlock inside Arc
      let p = p_arc.read().unwrap();

      assert_eq!(p.current_queue, Queue::None);
      p.prio
    };

    match prio {
      Prio::Normal => self.queue_normal.push_back(pid),
      Prio::Low => self.queue_low.push_back(pid),
      Prio::High => self.queue_high.push_back(pid),
    }
  }

  /// Get another process from the run queue for this scheduler.
  pub fn next(&mut self) {
    // FIXME: Ugly clone on self.current
    if let Some(curr_arc) = self.current.clone() {
      let curr = curr_arc.read().unwrap();
      assert_eq!(curr.current_queue, Queue::None);
      let curr_pid = curr.pid;

      match &curr.timeslice_result {
        &SliceResult::Yield => {
          self.queue(curr_pid);
          self.current = None
        },
        &SliceResult::None => {
          self.queue(curr_pid);
          self.current = None
        },
        &SliceResult::Finished => {
          self.exit_process(&curr, gen_atoms::NORMAL)
        },
        &SliceResult::Exception => {
          assert!(curr.is_failed());
          let fail_value = curr.fail_value;
          self.exit_process(&curr, fail_value);
          self.current = None
        },
        &SliceResult::Wait => {},
      }
    } // if self.current
  }

  /// Get a pointer to process, if it exists. Return `None` if we are sorry.
  pub fn lookup_pid(&self, pid: LTerm) -> Option<process::Ptr> {
    assert!(pid.is_local_pid());
    match self.processes.get(&pid) {
      Some(p) => Some(p.clone()),
      None => None
    }
  }

  pub fn exit_process(&mut self, p: &Process, reason: LTerm) {
    // assert that process is not in any queue
    assert_eq!(p.current_queue, Queue::None);

    // root process exits with halt()
    // assert!(p.get_registered_name() != atom::INIT);

    // TODO: ets tables
    // TODO: notify monitors
    // TODO: cancel known timers who target this process
    // TODO: notify links
    // TODO: unregister name if registered
    // TODO: if pending timers - become zombie and sit in pending timers queue
    let pid = p.pid;

    println!("{}Scheduler::exit_process {} reason={}, result x0=?",
             module(), pid, reason //, p.runtime_ctx.regs[0]
            );

    //  m_inf_wait.erase(p);
    //  m_timed_wait.erase(p);
    assert!(!self.queue_normal.contains(&pid));
    assert!(!self.queue_low.contains(&pid));
    assert!(!self.queue_high.contains(&pid));
    self.processes.remove(&pid);
  }
}
<commit_msg>Lifetime hell<commit_after>//! Code related to task scheduling and priorities.
use std::collections::{LinkedList, HashMap, HashSet};
//use std::sync;

use defs::Word;
use emulator::process;
use emulator::process::Process;
use emulator::gen_atoms;
use term::lterm::LTerm;

fn module() -> &'static str { "scheduler: " }

#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub enum Prio {
  /// Runs when no more jobs to take or at 8x disadvantage to normal
  Low = 0,
  /// Most of user processes run at this priority
  Normal = 1,
  /// Takes priority always over everything else
  High = 2,
}

/// Enum identifies current registration of the process
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(dead_code)]
pub enum Queue {
  None,
  //PendingTimers,
  High,
  Normal,
  Low,
  TimedWait,
  InfiniteWait,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(dead_code)]
pub enum SliceResult {
  None,
  /// Process willingly gave up run queue (ended the timeslice without events)
  Yield,
  /// Process entered infinite or timed wait during the last timeslice
  Wait,
  /// Process normally finished during the last timeslice
  Finished,
  /// Error, exit or throw occured during the last timeslice
  Exception,
}

/// How many Normal processes can be scheduled before Low gets to run.
const NORMAL_ADVANTAGE: Word = 8;

/// Maintains run queues for different priorities and allows queuing processes,
/// suspending processes, work balancing (TODO), etc.
pub struct Scheduler {
  // This is the naive implementation of run queues.
  // A better approach would be to build an intrusive double linked list through
  // every process in the queue (as done by the original ERTS).
  queue_low: LinkedList<LTerm>,
  queue_normal: LinkedList<LTerm>,
  queue_high: LinkedList<LTerm>,

  /// A counter used to skip some schedulings for low processes
  advantage_count: Word,

  /// Currently selected process
  current: Option<process::Ptr>,

  /// Wait set for infinitely suspended processes (in endless receive)
  wait_inf: HashSet<LTerm>,
  /// Wait set for timed suspended processes (waiting for a timer)
  wait_timed: HashSet<LTerm>,

  /// Dict of pids to process boxes. Owned by the scheduler
  processes: HashMap<LTerm, process::Ptr>,
}

impl Scheduler {
  pub fn new() -> Scheduler {
    Scheduler{
      queue_low: LinkedList::new(),
      queue_normal: LinkedList::new(),
      queue_high: LinkedList::new(),

      advantage_count: 0,
      current: None,

      wait_inf: HashSet::new(),
      wait_timed: HashSet::new(),

      processes: HashMap::new(),
    }
  }

  /// Register a process `proc_` in the process table and also queue it for
  /// execution. This is invoked by vm when a new process is spawned.
  pub fn add(&mut self, pid: LTerm, proc_: process::Ptr) {
    self.processes.insert(pid, proc_.clone());
    self.queue(pid);
  }

  /// Queue a process by its pid. Will `panic!` if the process doesn't exist
  /// or is already queued.
  pub fn queue(&mut self, pid: LTerm) {
    assert!(pid.is_local_pid());

    let prio = {
      // Lookup the pid
      let p_arc = self.lookup_pid(pid).unwrap();

      // Read-lock the rwlock inside Arc
      let p = p_arc.read().unwrap();

      assert_eq!(p.current_queue, Queue::None);
      p.prio
    };

    match prio {
      Prio::Normal => self.queue_normal.push_back(pid),
      Prio::Low => self.queue_low.push_back(pid),
      Prio::High => self.queue_high.push_back(pid),
    }
  }

  /// Get another process from the run queue for this scheduler.
  pub fn next(&mut self) -> Option<&Process> {
    // FIXME: Ugly clone on self.current
    if let Some(curr_arc) = self.current.clone() {
      let curr = curr_arc.read().unwrap();
      assert_eq!(curr.current_queue, Queue::None);
      let curr_pid = curr.pid;

      match &curr.timeslice_result {
        &SliceResult::Yield => {
          self.queue(curr_pid);
          self.current = None
        },
        &SliceResult::None => {
          self.queue(curr_pid);
          self.current = None
        },
        &SliceResult::Finished => {
          self.exit_process(&curr, gen_atoms::NORMAL)
        },
        &SliceResult::Exception => {
          assert!(curr.is_failed());
          let fail_value = curr.fail_value;
          self.exit_process(&curr, fail_value);
          self.current = None
        },
        &SliceResult::Wait => {},
      }
    } // if self.current

    // Now try and find another process to run
    while self.current.is_none() {
      // TODO: monotonic clock
      // TODO: wait lists
      // TODO: network checks

      // See if any are waiting in realtime (high) priority queue
      let mut next_pid: Option<LTerm> = None;
      if !self.queue_high.is_empty() {
        next_pid = self.queue_high.pop_front()
      } else if self.advantage_count < NORMAL_ADVANTAGE {
        if !self.queue_normal.is_empty() {
          next_pid = self.queue_normal.pop_front()
        } else if !self.queue_low.is_empty() {
          next_pid = self.queue_low.pop_front()
        }
        self.advantage_count += 1;
      } else {
        if !self.queue_low.is_empty() {
          next_pid = self.queue_low.pop_front()
        } else if !self.queue_normal.is_empty() {
          next_pid = self.queue_normal.pop_front()
        }
        self.advantage_count = 0;
      };

      if next_pid.is_some() {
        let next_pid1 = next_pid.unwrap();
        {
          let next_proc = self.borrow_pid_mut(next_pid1).unwrap();
          println!("{} next() queue {}", module(), next_proc.pid);
        }

        self.current = self.lookup_pid(next_pid1)
      }
    }

    self.current
  }

  /// Get a pointer to process, if it exists. Return `None` if we are sorry.
  pub fn lookup_pid(&self, pid: LTerm) -> Option<process::Ptr> {
    assert!(pid.is_local_pid());
    match self.processes.get(&pid) {
      Some(p) => Some(p.clone()),
      None => None
    }
  }

  /// Get a reference to process, if it exists. Return `None` if we are sorry.
  pub fn borrow_pid_mut(&self, pid: LTerm) -> Option<&mut process::Process> {
    assert!(pid.is_local_pid());
    match self.processes.get(&pid) {
      Some(p) => Some(&mut p.write().unwrap()),
      None => None
    }
  }

  pub fn exit_process(&mut self, p: &Process, reason: LTerm) {
    // assert that process is not in any queue
    assert_eq!(p.current_queue, Queue::None);

    // root process exits with halt()
    // assert!(p.get_registered_name() != atom::INIT);

    // TODO: ets tables
    // TODO: notify monitors
    // TODO: cancel known timers who target this process
    // TODO: notify links
    // TODO: unregister name if registered
    // TODO: if pending timers - become zombie and sit in pending timers queue
    let pid = p.pid;

    println!("{}Scheduler::exit_process {} reason={}, result x0=?",
             module(), pid, reason //, p.runtime_ctx.regs[0]
            );

    //  m_inf_wait.erase(p);
    //  m_timed_wait.erase(p);
    assert!(!self.queue_normal.contains(&pid));
    assert!(!self.queue_low.contains(&pid));
    assert!(!self.queue_high.contains(&pid));
    self.processes.remove(&pid);
  }
}
<|endoftext|>


<commit_before>//! Defines the render target for tray, where our image will be written too
//! during rendering
//! TODO: Reconstruction filters

use std::vec::Vec;
use std::iter;
use std::cmp;
use std::num::Float;

use linalg;
use film::Colorf;

/// RenderTarget is a RGBF render target to write our image too while rendering
#[derive(Clone)]
pub struct RenderTarget {
    width: usize,
    height: usize,
    pixels: Vec<Colorf>,
}

impl RenderTarget {
    /// Create a render target with `width * height` pixels
    pub fn new(width: usize, height: usize) -> RenderTarget {
        RenderTarget { width: width, height: height,
            pixels: iter::repeat(Colorf::broadcast(0.0)).take(width * height).collect(),
        }
    }
    /// Write a color value to the image at `(x, y)`
    pub fn write(&mut self, x: f32, y: f32, c: &Colorf) {
        // Compute the discrete pixel coordinates which the sample hits, no filtering for now
        let img_x = x - 0.5;
        let img_y = y - 0.5;
        // TODO: We're just pretending to be a single pixel box filter for now
        let x_range = (Float::max(Float::ceil(img_x - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_x + 0.5), self.width as f32 - 1.0) as usize);
        let y_range = (Float::max(Float::ceil(img_y - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_y + 0.5), self.height as f32 - 1.0) as usize);
        let ix = x_range.0;
        let iy = y_range.0;
        self.pixels[iy * self.width + ix] = *c;
        // Set the filter weight, currently just a box filter with single pixel extent
        self.pixels[iy * self.width + ix].a += 1.0;
    }
    /// Get the dimensions of the render target
    pub fn dimensions(&self) -> (usize, usize) {
        (self.width, self.height)
    }
    /// Convert the floating point color buffer to 24bpp sRGB for output to an image
    pub fn get_render(&self) -> Vec<u8> {
        let mut render: Vec<u8> = iter::repeat(0u8).take(self.width * self.height * 3).collect();
        for y in 0..self.height {
            for x in 0..self.width {
                let c = &self.pixels[y * self.width + x];
                if c.a != 0.0 {
                    let cn = (*c / c.a).clamp().to_srgb();
                    for i in 0..3us {
                        render[y * self.width * 3 + x * 3 + i] = (cn[i] * 255.0) as u8;
                    }
                }
            }
        }
        render
    }
}

<commit_msg>Sampling issue solved: I was replacing the color not adding!<commit_after>//! Defines the render target for tray, where our image will be written too
//! during rendering
//! TODO: Reconstruction filters

use std::vec::Vec;
use std::iter;
use std::cmp;
use std::num::Float;

use linalg;
use film::Colorf;

/// RenderTarget is a RGBF render target to write our image too while rendering
#[derive(Clone)]
pub struct RenderTarget {
    width: usize,
    height: usize,
    pixels: Vec<Colorf>,
}

impl RenderTarget {
    /// Create a render target with `width * height` pixels
    pub fn new(width: usize, height: usize) -> RenderTarget {
        RenderTarget { width: width, height: height,
            pixels: iter::repeat(Colorf::broadcast(0.0)).take(width * height).collect(),
        }
    }
    /// Write a color value to the image at `(x, y)`
    pub fn write(&mut self, x: f32, y: f32, c: &Colorf) {
        // Compute the discrete pixel coordinates which the sample hits, no filtering for now
        let img_x = x - 0.5;
        let img_y = y - 0.5;
        // TODO: We're just pretending to be a single pixel box filter for now
        let x_range = (Float::max(Float::ceil(img_x - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_x + 0.5), self.width as f32 - 1.0) as usize);
        let y_range = (Float::max(Float::ceil(img_y - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_y + 0.5), self.height as f32 - 1.0) as usize);
        let ix = x_range.0;
        let iy = y_range.0;
        self.pixels[iy * self.width + ix] = self.pixels[iy * self.width + ix] + *c;
        // Set the filter weight, currently just a box filter with single pixel extent
        self.pixels[iy * self.width + ix].a += 1.0;
    }
    /// Get the dimensions of the render target
    pub fn dimensions(&self) -> (usize, usize) {
        (self.width, self.height)
    }
    /// Convert the floating point color buffer to 24bpp sRGB for output to an image
    pub fn get_render(&self) -> Vec<u8> {
        let mut render: Vec<u8> = iter::repeat(0u8).take(self.width * self.height * 3).collect();
        for y in 0..self.height {
            for x in 0..self.width {
                let c = &self.pixels[y * self.width + x];
                if c.a != 0.0 {
                    let cn = (*c / c.a).clamp().to_srgb();
                    for i in 0..3us {
                        render[y * self.width * 3 + x * 3 + i] = (cn[i] * 255.0) as u8;
                    }
                }
            }
        }
        render
    }
}

<|endoftext|>


<commit_before>use driver::ctxt::Context;
use error::msg::Msg;

use parser::ast::*;
use parser::ast::Expr::*;
use parser::ast::Stmt::*;
use parser::ast::Type::*;
use parser::ast::visit::*;
use parser::interner::Name;
use parser::lexer::position::Position;

use sym::Sym::*;
use sym::BuiltinType;

pub fn check(ctxt: &Context, ast: &Ast) {
    GlobalDef::new(ctxt).visit_ast(ast);
    NameCheck::new(ctxt).visit_ast(ast);
}

struct GlobalDef<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>
}

impl<'a, 'ast> GlobalDef<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>) -> GlobalDef<'a, 'ast> {
        GlobalDef {
            ctxt: ctxt
        }
    }
}

impl<'a, 'ast> Visitor<'ast> for GlobalDef<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        let entry_type = self.ctxt.sym.borrow().get_entry_type(f.name);

        if entry_type.is_empty() {
            self.ctxt.sym.borrow_mut().insert(f.name, SymFunction(f.id));
        } else {
            let name = self.ctxt.interner.str(f.name).clone_string();
            let msg = if entry_type.is_type() {
                Msg::ShadowType(name)
            } else {
                Msg::ShadowFunction(name)
            };

            report(self.ctxt, f.pos, msg);
        }
    }
}

struct NameCheck<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>
}

impl<'a, 'ast> NameCheck<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>) -> NameCheck<'a, 'ast> {
        NameCheck {
            ctxt: ctxt
        }
    }
}

impl<'a, 'ast> Visitor<'ast> for NameCheck<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        self.ctxt.sym.borrow_mut().push_level();

        for p in &f.params { self.visit_param(p); }
        self.visit_stmt(&f.block);

        self.ctxt.sym.borrow_mut().pop_level();
    }

    fn visit_param(&mut self, p: &'ast Param) {
        // params are only allowed to replace functions,
        // types and vars cannot be replaced
        let entry_type = self.ctxt.sym.borrow().get_entry_type(p.name);

        if entry_type.is_empty() || entry_type.is_function() {
            self.ctxt.sym.borrow_mut().insert(p.name, SymVar(p.id));
        } else {
            let name = str(self.ctxt, p.name);
            let msg = if entry_type.is_type() {
                Msg::ShadowType(name)
            } else {
                Msg::ShadowParam(name)
            };

            report(self.ctxt, p.pos, msg);
        }
    }

    fn visit_stmt(&mut self, s: &'ast Stmt) {
        match *s {
            StmtVar(ref var) => {
                let redefinable = self.ctxt.sym.borrow().get(var.name)
                    .map_or(true, |sym| !sym.is_type());

                if redefinable {
                    self.ctxt.sym.borrow_mut().insert(var.name, SymVar(var.id));
                } else {
                    let name = str(self.ctxt, var.name);
                    report(self.ctxt, var.pos, Msg::ShadowType(name));
                }

                if let Some(ref expr) = var.expr {
                    self.visit_expr(expr);
                }
            }

            // no need to handle rest of statements
            _ => visit::walk_stmt(self, s)
        }
    }

    fn visit_expr(&mut self, e: &'ast Expr) {
        match *e {
            ExprIdent(ref ident) => {
                if let Some(id) = self.ctxt.sym.borrow().get_var(ident.name) {
                    self.ctxt.var_uses.borrow_mut().insert(ident.id, id);
                } else {
                    let name = str(self.ctxt, ident.name);
                    report(self.ctxt, ident.pos, Msg::UnknownIdentifier(name));
                }
            }

            ExprCall(ref call) => {
                if let Some(id) = self.ctxt.sym.borrow().get_function(call.name) {
                    self.ctxt.var_uses.borrow_mut().insert(call.id, id);
                } else {
                    let name = str(self.ctxt, call.name);
                    report(self.ctxt, call.pos, Msg::UnknownFunction(name));
                }
            }

            // no need to handle rest of expressions
            _ => visit::walk_expr(self, e)
        }
    }
}

fn report(ctxt: &Context, pos: Position, msg: Msg) {
    ctxt.diag.borrow_mut().report(pos, msg);
}

fn str(ctxt: &Context, name: Name) -> String {
    ctxt.interner.str(name).clone_string()
}

#[cfg(test)]
mod tests {
    use error::msg::Msg;
    use semck::tests::*;

    #[test]
    fn multiple_functions() {
        ok("fn f() {}\nfn g() {}");
    }

    #[test]
    fn redefine_function() {
        err("fn f() {}\nfn f() {}", pos(2, 1),
            Msg::ShadowFunction("f".into()));
    }

    #[test]
    fn shadow_type_with_function() {
        err("fn int() {}", pos(1, 1),
            Msg::ShadowType("int".into()));
    }

    #[test]
    fn shadow_type_with_param() {
        err("fn test(bool: str) {}", pos(1, 9),
            Msg::ShadowType("bool".into()));
    }

    #[test]
    fn shadow_type_with_var() {
        err("fn test() { var str = 3; }", pos(1, 13),
            Msg::ShadowType("str".into()));
    }

    #[test]
    fn shadow_function() {
        ok("fn f() { var f = 1; }");
        err("fn f() { var f = 1; f(); }", pos(1, 21),
            Msg::UnknownFunction("f".into()));
    }

    #[test]
    fn shadow_var() {
        ok("fn f() { var f = 1; var f = 2; }");
    }

    #[test]
    fn shadow_param() {
        err("fn f(a: int, b: int, a: str) {}", pos(1, 22),
            Msg::ShadowParam("a".into()));
    }

    #[test]
    fn multiple_params() {
        ok("fn f(a: int, b: int, c:str) {}");
    }

    #[test]
    fn undefined_variable() {
        err("fn f() { var b = a; }", pos(1, 18), Msg::UnknownIdentifier("a".into()));
        err("fn f() { a; }", pos(1, 10), Msg::UnknownIdentifier("a".into()));
    }

    #[test]
    fn undefined_function() {
        err("fn f() { foo(); }", pos(1, 10),
            Msg::UnknownFunction("foo".into()));
    }

    #[test]
    fn recursive_function_call() {
        ok("fn f() { f(); }");
    }

    #[test]
    fn function_call() {
        ok("fn a() {}\nfn b() { a(); }");

        // non-forward definition of functions
        ok("fn a() { b(); }\nfn b() {}");
    }
}
<commit_msg>nameck: use get_entry_type for var-stmt<commit_after>use driver::ctxt::Context;
use error::msg::Msg;

use parser::ast::*;
use parser::ast::Expr::*;
use parser::ast::Stmt::*;
use parser::ast::Type::*;
use parser::ast::visit::*;
use parser::interner::Name;
use parser::lexer::position::Position;

use sym::Sym::*;
use sym::BuiltinType;

pub fn check(ctxt: &Context, ast: &Ast) {
    GlobalDef::new(ctxt).visit_ast(ast);
    NameCheck::new(ctxt).visit_ast(ast);
}

struct GlobalDef<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>
}

impl<'a, 'ast> GlobalDef<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>) -> GlobalDef<'a, 'ast> {
        GlobalDef {
            ctxt: ctxt
        }
    }
}

impl<'a, 'ast> Visitor<'ast> for GlobalDef<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        let entry_type = self.ctxt.sym.borrow().get_entry_type(f.name);

        if entry_type.is_empty() {
            self.ctxt.sym.borrow_mut().insert(f.name, SymFunction(f.id));
        } else {
            let name = self.ctxt.interner.str(f.name).clone_string();
            let msg = if entry_type.is_type() {
                Msg::ShadowType(name)
            } else {
                Msg::ShadowFunction(name)
            };

            report(self.ctxt, f.pos, msg);
        }
    }
}

struct NameCheck<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>
}

impl<'a, 'ast> NameCheck<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>) -> NameCheck<'a, 'ast> {
        NameCheck {
            ctxt: ctxt
        }
    }
}

impl<'a, 'ast> Visitor<'ast> for NameCheck<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        self.ctxt.sym.borrow_mut().push_level();

        for p in &f.params { self.visit_param(p); }
        self.visit_stmt(&f.block);

        self.ctxt.sym.borrow_mut().pop_level();
    }

    fn visit_param(&mut self, p: &'ast Param) {
        // params are only allowed to replace functions,
        // types and vars cannot be replaced
        let entry_type = self.ctxt.sym.borrow().get_entry_type(p.name);

        if entry_type.is_empty() || entry_type.is_function() {
            self.ctxt.sym.borrow_mut().insert(p.name, SymVar(p.id));
        } else {
            let name = str(self.ctxt, p.name);
            let msg = if entry_type.is_type() {
                Msg::ShadowType(name)
            } else {
                Msg::ShadowParam(name)
            };

            report(self.ctxt, p.pos, msg);
        }
    }

    fn visit_stmt(&mut self, s: &'ast Stmt) {
        match *s {
            StmtVar(ref var) => {
                let entry_type = self.ctxt.sym.borrow().get_entry_type(var.name);

                if entry_type.is_type() {
                    let name = str(self.ctxt, var.name);
                    report(self.ctxt, var.pos, Msg::ShadowType(name));
                } else {
                    self.ctxt.sym.borrow_mut().insert(var.name, SymVar(var.id));
                }

                if let Some(ref expr) = var.expr {
                    self.visit_expr(expr);
                }
            }

            // no need to handle rest of statements
            _ => visit::walk_stmt(self, s)
        }
    }

    fn visit_expr(&mut self, e: &'ast Expr) {
        match *e {
            ExprIdent(ref ident) => {
                if let Some(id) = self.ctxt.sym.borrow().get_var(ident.name) {
                    self.ctxt.var_uses.borrow_mut().insert(ident.id, id);
                } else {
                    let name = str(self.ctxt, ident.name);
                    report(self.ctxt, ident.pos, Msg::UnknownIdentifier(name));
                }
            }

            ExprCall(ref call) => {
                if let Some(id) = self.ctxt.sym.borrow().get_function(call.name) {
                    self.ctxt.var_uses.borrow_mut().insert(call.id, id);
                } else {
                    let name = str(self.ctxt, call.name);
                    report(self.ctxt, call.pos, Msg::UnknownFunction(name));
                }
            }

            // no need to handle rest of expressions
            _ => visit::walk_expr(self, e)
        }
    }
}

fn report(ctxt: &Context, pos: Position, msg: Msg) {
    ctxt.diag.borrow_mut().report(pos, msg);
}

fn str(ctxt: &Context, name: Name) -> String {
    ctxt.interner.str(name).clone_string()
}

#[cfg(test)]
mod tests {
    use error::msg::Msg;
    use semck::tests::*;

    #[test]
    fn multiple_functions() {
        ok("fn f() {}\nfn g() {}");
    }

    #[test]
    fn redefine_function() {
        err("fn f() {}\nfn f() {}", pos(2, 1),
            Msg::ShadowFunction("f".into()));
    }

    #[test]
    fn shadow_type_with_function() {
        err("fn int() {}", pos(1, 1),
            Msg::ShadowType("int".into()));
    }

    #[test]
    fn shadow_type_with_param() {
        err("fn test(bool: str) {}", pos(1, 9),
            Msg::ShadowType("bool".into()));
    }

    #[test]
    fn shadow_type_with_var() {
        err("fn test() { var str = 3; }", pos(1, 13),
            Msg::ShadowType("str".into()));
    }

    #[test]
    fn shadow_function() {
        ok("fn f() { var f = 1; }");
        err("fn f() { var f = 1; f(); }", pos(1, 21),
            Msg::UnknownFunction("f".into()));
    }

    #[test]
    fn shadow_var() {
        ok("fn f() { var f = 1; var f = 2; }");
    }

    #[test]
    fn shadow_param() {
        err("fn f(a: int, b: int, a: str) {}", pos(1, 22),
            Msg::ShadowParam("a".into()));
    }

    #[test]
    fn multiple_params() {
        ok("fn f(a: int, b: int, c:str) {}");
    }

    #[test]
    fn undefined_variable() {
        err("fn f() { var b = a; }", pos(1, 18), Msg::UnknownIdentifier("a".into()));
        err("fn f() { a; }", pos(1, 10), Msg::UnknownIdentifier("a".into()));
    }

    #[test]
    fn undefined_function() {
        err("fn f() { foo(); }", pos(1, 10),
            Msg::UnknownFunction("foo".into()));
    }

    #[test]
    fn recursive_function_call() {
        ok("fn f() { f(); }");
    }

    #[test]
    fn function_call() {
        ok("fn a() {}\nfn b() { a(); }");

        // non-forward definition of functions
        ok("fn a() { b(); }\nfn b() {}");
    }
}
<|endoftext|>


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

extern crate unicase;
extern crate iron;
extern crate router;

use self::iron::{AfterMiddleware, headers, status};
use self::iron::method::Method::*;
use self::iron::prelude::*;
use self::router::Router;
use self::unicase::UniCase;

struct CORS;

impl AfterMiddleware for CORS {
    fn after(&self, _: &mut Request, mut res: Response)
        -> IronResult<Response> {
        res.headers.set(headers::AccessControlAllowOrigin::Any);
        res.headers.set(headers::AccessControlAllowHeaders(
                vec![UniCase("accept".to_string()),
                UniCase("content-type".to_string())]));
        res.headers.set(headers::AccessControlAllowMethods(
                vec![Get,Head,Post,Delete,Options,Put,Patch]));
        Ok(res)
    }
}

pub struct UsersRouter;

impl UsersRouter {
    fn not_implemented(_: &mut Request) -> IronResult<Response> {
        println!("Not implemented");
        Ok(Response::with(status::NotImplemented))
    }

    pub fn new() -> iron::middleware::Chain {
        let mut router = Router::new();

        router.post("/setup", UsersRouter::not_implemented);

        router.post("/invitation", UsersRouter::not_implemented);
        router.get("/invitation", UsersRouter::not_implemented);
        router.delete("invitation", UsersRouter::not_implemented);

        router.post("/users", UsersRouter::not_implemented);
        router.get("/users", UsersRouter::not_implemented);
        router.put("/users/:id", UsersRouter::not_implemented);
        router.post("/users/:id", UsersRouter::not_implemented);

        router.post("/recoveries/:user", UsersRouter::not_implemented);
        router.get("/recoveries/:user/:id", UsersRouter::not_implemented);

        router.get("/permissions", UsersRouter::not_implemented);
        router.get("/permissions/:user", UsersRouter::not_implemented);
        router.get("/permissions/:user/:taxon", UsersRouter::not_implemented);
        router.get("/permissions/_/:taxon", UsersRouter::not_implemented);
        router.put("/permissions/:user/:taxon", UsersRouter::not_implemented);

        let mut chain = Chain::new(router);
        chain.link_after(CORS);

        chain
    }
}
<commit_msg>#1 Restrict setup call to same-origin<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate unicase;
extern crate iron;
extern crate router;

use self::iron::{AfterMiddleware, headers, status};
use self::iron::method::Method::*;
use self::iron::prelude::*;
use self::router::Router;
use self::unicase::UniCase;

struct CORS;

impl AfterMiddleware for CORS {
    fn after(&self, req: &mut Request, mut res: Response)
        -> IronResult<Response> {

        // Endpoints listed here will be denied CORS.
        // Endpoints containing a variable path can use '*' like in:
        // &["users", "*"]
        const SAME_ORIGIN_ONLY_ENDPOINTS: &'static[&'static[&'static str]] =
            &[&["setup"]];

        let mut is_soo_endpoint = false;
        for endpoint in SAME_ORIGIN_ONLY_ENDPOINTS {
            if endpoint.len() != req.url.path.len() {
                continue;
            }
            for (i, path) in endpoint.iter().enumerate() {
                is_soo_endpoint = false;
                if req.url.path[i] != path.to_string() &&
                   "*".to_string() != path.to_string() {
                    break;
                }
                is_soo_endpoint = true;
            }
            if is_soo_endpoint {
                break;
            }
        }

        if is_soo_endpoint {
            return Ok(res);
        }

        res.headers.set(headers::AccessControlAllowOrigin::Any);
        res.headers.set(headers::AccessControlAllowHeaders(
                vec![UniCase("accept".to_string()),
                UniCase("content-type".to_string())]));
        res.headers.set(headers::AccessControlAllowMethods(
                vec![Get,Head,Post,Delete,Options,Put,Patch]));
        Ok(res)
    }
}

pub struct UsersRouter;

impl UsersRouter {
    fn not_implemented(_: &mut Request) -> IronResult<Response> {
        println!("Not implemented");
        Ok(Response::with(status::NotImplemented))
    }

    pub fn new() -> iron::middleware::Chain {
        let mut router = Router::new();

        router.post("/setup", UsersRouter::not_implemented);

        router.post("/invitations", UsersRouter::not_implemented);
        router.get("/invitations", UsersRouter::not_implemented);
        router.delete("invitations", UsersRouter::not_implemented);

        router.post("/users", UsersRouter::not_implemented);
        router.get("/users", UsersRouter::not_implemented);
        router.put("/users/:id", UsersRouter::not_implemented);
        router.post("/users/:id", UsersRouter::not_implemented);

        router.post("/recoveries/:user", UsersRouter::not_implemented);
        router.get("/recoveries/:user/:id", UsersRouter::not_implemented);

        router.get("/permissions", UsersRouter::not_implemented);
        router.get("/permissions/:user", UsersRouter::not_implemented);
        router.get("/permissions/:user/:taxon", UsersRouter::not_implemented);
        router.get("/permissions/_/:taxon", UsersRouter::not_implemented);
        router.put("/permissions/:user/:taxon", UsersRouter::not_implemented);

        let mut chain = Chain::new(router);
        chain.link_after(CORS);

        chain
    }
}
<|endoftext|>