<commit_before>use futures_channel::oneshot;
use futures_util::future;
use tokio::sync::mpsc;

use crate::common::{task, Future, Pin, Poll};

pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>;
pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;

pub fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {
    let (tx, rx) = mpsc::unbounded_channel();
    let (giver, taker) = want::new();
    let tx = Sender {
        buffered_once: false,
        giver,
        inner: tx,
    };
    let rx = Receiver { inner: rx, taker };
    (tx, rx)
}

/// A bounded sender of requests and callbacks for when responses are ready.
///
/// While the inner sender is unbounded, the Giver is used to determine
/// if the Receiver is ready for another request.
pub struct Sender<T, U> {
    /// One message is always allowed, even if the Receiver hasn't asked
    /// for it yet. This boolean keeps track of whether we've sent one
    /// without notice.
    buffered_once: bool,
    /// The Giver helps watch that the the Receiver side has been polled
    /// when the queue is empty. This helps us know when a request and
    /// response have been fully processed, and a connection is ready
    /// for more.
    giver: want::Giver,
    /// Actually bounded by the Giver, plus `buffered_once`.
    inner: mpsc::UnboundedSender<Envelope<T, U>>,
}

/// An unbounded version.
///
/// Cannot poll the Giver, but can still use it to determine if the Receiver
/// has been dropped. However, this version can be cloned.
pub struct UnboundedSender<T, U> {
    /// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked.
    giver: want::SharedGiver,
    inner: mpsc::UnboundedSender<Envelope<T, U>>,
}

impl<T, U> Sender<T, U> {
    pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
        self.giver
            .poll_want(cx)
            .map_err(|_| crate::Error::new_closed())
    }

    pub fn is_ready(&self) -> bool {
        self.giver.is_wanting()
    }

    pub fn is_closed(&self) -> bool {
        self.giver.is_canceled()
    }

    fn can_send(&mut self) -> bool {
        if self.giver.give() || !self.buffered_once {
            // If the receiver is ready *now*, then of course we can send.
            //
            // If the receiver isn't ready yet, but we don't have anything
            // in the channel yet, then allow one message.
            self.buffered_once = true;
            true
        } else {
            false
        }
    }

    pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
        if !self.can_send() {
            return Err(val);
        }
        let (tx, rx) = oneshot::channel();
        self.inner
            .send(Envelope(Some((val, Callback::Retry(tx)))))
            .map(move |_| rx)
            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
    }

    pub fn send(&mut self, val: T) -> Result<Promise<U>, T> {
        if !self.can_send() {
            return Err(val);
        }
        let (tx, rx) = oneshot::channel();
        self.inner
            .send(Envelope(Some((val, Callback::NoRetry(tx)))))
            .map(move |_| rx)
            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
    }

    pub fn unbound(self) -> UnboundedSender<T, U> {
        UnboundedSender {
            giver: self.giver.shared(),
            inner: self.inner,
        }
    }
}

impl<T, U> UnboundedSender<T, U> {
    pub fn is_ready(&self) -> bool {
        !self.giver.is_canceled()
    }

    pub fn is_closed(&self) -> bool {
        self.giver.is_canceled()
    }

    pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
        let (tx, rx) = oneshot::channel();
        self.inner
            .send(Envelope(Some((val, Callback::Retry(tx)))))
            .map(move |_| rx)
            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
    }
}

impl<T, U> Clone for UnboundedSender<T, U> {
    fn clone(&self) -> Self {
        UnboundedSender {
            giver: self.giver.clone(),
            inner: self.inner.clone(),
        }
    }
}

pub struct Receiver<T, U> {
    inner: mpsc::UnboundedReceiver<Envelope<T, U>>,
    taker: want::Taker,
}

impl<T, U> Receiver<T, U> {
    pub(crate) fn poll_next(
        &mut self,
        cx: &mut task::Context<'_>,
    ) -> Poll<Option<(T, Callback<T, U>)>> {
        match self.inner.poll_recv(cx) {
            Poll::Ready(item) => {
                Poll::Ready(item.map(|mut env| env.0.take().expect("envelope not dropped")))
            }
            Poll::Pending => {
                self.taker.want();
                Poll::Pending
            }
        }
    }

    pub(crate) fn close(&mut self) {
        self.taker.cancel();
        self.inner.close();
    }

    pub(crate) fn try_recv(&mut self) -> Option<(T, Callback<T, U>)> {
        match self.inner.try_recv() {
            Ok(mut env) => env.0.take(),
            Err(_) => None,
        }
    }
}

impl<T, U> Drop for Receiver<T, U> {
    fn drop(&mut self) {
        // Notify the giver about the closure first, before dropping
        // the mpsc::Receiver.
        self.taker.cancel();
    }
}

struct Envelope<T, U>(Option<(T, Callback<T, U>)>);

impl<T, U> Drop for Envelope<T, U> {
    fn drop(&mut self) {
        if let Some((val, cb)) = self.0.take() {
            cb.send(Err((
                crate::Error::new_canceled().with("connection closed"),
                Some(val),
            )));
        }
    }
}

pub enum Callback<T, U> {
    Retry(oneshot::Sender<Result<U, (crate::Error, Option<T>)>>),
    NoRetry(oneshot::Sender<Result<U, crate::Error>>),
}

impl<T, U> Callback<T, U> {
    pub(crate) fn is_canceled(&self) -> bool {
        match *self {
            Callback::Retry(ref tx) => tx.is_canceled(),
            Callback::NoRetry(ref tx) => tx.is_canceled(),
        }
    }

    pub(crate) fn poll_canceled(&mut self, cx: &mut task::Context<'_>) -> Poll<()> {
        match *self {
            Callback::Retry(ref mut tx) => tx.poll_canceled(cx),
            Callback::NoRetry(ref mut tx) => tx.poll_canceled(cx),
        }
    }

    pub(crate) fn send(self, val: Result<U, (crate::Error, Option<T>)>) {
        match self {
            Callback::Retry(tx) => {
                let _ = tx.send(val);
            }
            Callback::NoRetry(tx) => {
                let _ = tx.send(val.map_err(|e| e.0));
            }
        }
    }

    pub(crate) fn send_when(
        self,
        mut when: impl Future<Output = Result<U, (crate::Error, Option<T>)>> + Unpin,
    ) -> impl Future<Output = ()> {
        let mut cb = Some(self);

        // "select" on this callback being canceled, and the future completing
        future::poll_fn(move |cx| {
            match Pin::new(&mut when).poll(cx) {
                Poll::Ready(Ok(res)) => {
                    cb.take().expect("polled after complete").send(Ok(res));
                    Poll::Ready(())
                }
                Poll::Pending => {
                    // check if the callback is canceled
                    ready!(cb.as_mut().unwrap().poll_canceled(cx));
                    trace!("send_when canceled");
                    Poll::Ready(())
                }
                Poll::Ready(Err(err)) => {
                    cb.take().expect("polled after complete").send(Err(err));
                    Poll::Ready(())
                }
            }
        })
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "nightly")]
    extern crate test;

    use std::future::Future;
    use std::pin::Pin;
    use std::task::{Context, Poll};

    use super::{channel, Callback, Receiver};

    #[derive(Debug)]
    struct Custom(i32);

    impl<T, U> Future for Receiver<T, U> {
        type Output = Option<(T, Callback<T, U>)>;

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            self.poll_next(cx)
        }
    }

    /// Helper to check if the future is ready after polling once.
    struct PollOnce<'a, F>(&'a mut F);

    impl<F, T> Future for PollOnce<'_, F>
    where
        F: Future<Output = T> + Unpin,
    {
        type Output = Option<()>;

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            match Pin::new(&mut self.0).poll(cx) {
                Poll::Ready(_) => Poll::Ready(Some(())),
                Poll::Pending => Poll::Ready(None),
            }
        }
    }

    #[tokio::test]
    async fn drop_receiver_sends_cancel_errors() {
        let _ = pretty_env_logger::try_init();

        let (mut tx, mut rx) = channel::<Custom, ()>();

        // must poll once for try_send to succeed
        assert!(PollOnce(&mut rx).await.is_none(), "rx empty");

        let promise = tx.try_send(Custom(43)).unwrap();
        drop(rx);

        let fulfilled = promise.await;
        let err = fulfilled
            .expect("fulfilled")
            .expect_err("promise should error");
        match (err.0.kind(), err.1) {
            (&crate::error::Kind::Canceled, Some(_)) => (),
            e => panic!("expected Error::Cancel(_), found {:?}", e),
        }
    }

    #[tokio::test]
    async fn sender_checks_for_want_on_send() {
        let (mut tx, mut rx) = channel::<Custom, ()>();

        // one is allowed to buffer, second is rejected
        let _ = tx.try_send(Custom(1)).expect("1 buffered");
        tx.try_send(Custom(2)).expect_err("2 not ready");

        assert!(PollOnce(&mut rx).await.is_some(), "rx once");

        // Even though 1 has been popped, only 1 could be buffered for the
        // lifetime of the channel.
        tx.try_send(Custom(2)).expect_err("2 still not ready");

        assert!(PollOnce(&mut rx).await.is_none(), "rx empty");

        let _ = tx.try_send(Custom(2)).expect("2 ready");
    }

    #[test]
    fn unbounded_sender_doesnt_bound_on_want() {
        let (tx, rx) = channel::<Custom, ()>();
        let mut tx = tx.unbound();

        let _ = tx.try_send(Custom(1)).unwrap();
        let _ = tx.try_send(Custom(2)).unwrap();
        let _ = tx.try_send(Custom(3)).unwrap();

        drop(rx);

        let _ = tx.try_send(Custom(4)).unwrap_err();
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn giver_queue_throughput(b: &mut test::Bencher) {
        use crate::{Body, Request, Response};

        let mut rt = tokio::runtime::Builder::new()
            .enable_all()
            .basic_scheduler()
            .build()
            .unwrap();
        let (mut tx, mut rx) = channel::<Request<Body>, Response<Body>>();

        b.iter(move || {
            let _ = tx.send(Request::default()).unwrap();
            rt.block_on(async {
                loop {
                    let poll_once = PollOnce(&mut rx);
                    let opt = poll_once.await;
                    if opt.is_none() {
                        break;
                    }
                }
            });
        })
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn giver_queue_not_ready(b: &mut test::Bencher) {
        let mut rt = tokio::runtime::Builder::new()
            .enable_all()
            .basic_scheduler()
            .build()
            .unwrap();
        let (_tx, mut rx) = channel::<i32, ()>();
        b.iter(move || {
            rt.block_on(async {
                let poll_once = PollOnce(&mut rx);
                assert!(poll_once.await.is_none());
            });
        })
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn giver_queue_cancel(b: &mut test::Bencher) {
        let (_tx, mut rx) = channel::<i32, ()>();

        b.iter(move || {
            rx.taker.cancel();
        })
    }
}
<commit_msg>refactor(client): replace futures oneshot with tokio in dispatcher<commit_after>use futures_util::future;
use tokio::sync::{mpsc, oneshot};

use crate::common::{task, Future, Pin, Poll};

pub type RetryPromise<T, U> = oneshot::Receiver<Result<U, (crate::Error, Option<T>)>>;
pub type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;

pub fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {
    let (tx, rx) = mpsc::unbounded_channel();
    let (giver, taker) = want::new();
    let tx = Sender {
        buffered_once: false,
        giver,
        inner: tx,
    };
    let rx = Receiver { inner: rx, taker };
    (tx, rx)
}

/// A bounded sender of requests and callbacks for when responses are ready.
///
/// While the inner sender is unbounded, the Giver is used to determine
/// if the Receiver is ready for another request.
pub struct Sender<T, U> {
    /// One message is always allowed, even if the Receiver hasn't asked
    /// for it yet. This boolean keeps track of whether we've sent one
    /// without notice.
    buffered_once: bool,
    /// The Giver helps watch that the the Receiver side has been polled
    /// when the queue is empty. This helps us know when a request and
    /// response have been fully processed, and a connection is ready
    /// for more.
    giver: want::Giver,
    /// Actually bounded by the Giver, plus `buffered_once`.
    inner: mpsc::UnboundedSender<Envelope<T, U>>,
}

/// An unbounded version.
///
/// Cannot poll the Giver, but can still use it to determine if the Receiver
/// has been dropped. However, this version can be cloned.
pub struct UnboundedSender<T, U> {
    /// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked.
    giver: want::SharedGiver,
    inner: mpsc::UnboundedSender<Envelope<T, U>>,
}

impl<T, U> Sender<T, U> {
    pub fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
        self.giver
            .poll_want(cx)
            .map_err(|_| crate::Error::new_closed())
    }

    pub fn is_ready(&self) -> bool {
        self.giver.is_wanting()
    }

    pub fn is_closed(&self) -> bool {
        self.giver.is_canceled()
    }

    fn can_send(&mut self) -> bool {
        if self.giver.give() || !self.buffered_once {
            // If the receiver is ready *now*, then of course we can send.
            //
            // If the receiver isn't ready yet, but we don't have anything
            // in the channel yet, then allow one message.
            self.buffered_once = true;
            true
        } else {
            false
        }
    }

    pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
        if !self.can_send() {
            return Err(val);
        }
        let (tx, rx) = oneshot::channel();
        self.inner
            .send(Envelope(Some((val, Callback::Retry(tx)))))
            .map(move |_| rx)
            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
    }

    pub fn send(&mut self, val: T) -> Result<Promise<U>, T> {
        if !self.can_send() {
            return Err(val);
        }
        let (tx, rx) = oneshot::channel();
        self.inner
            .send(Envelope(Some((val, Callback::NoRetry(tx)))))
            .map(move |_| rx)
            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
    }

    pub fn unbound(self) -> UnboundedSender<T, U> {
        UnboundedSender {
            giver: self.giver.shared(),
            inner: self.inner,
        }
    }
}

impl<T, U> UnboundedSender<T, U> {
    pub fn is_ready(&self) -> bool {
        !self.giver.is_canceled()
    }

    pub fn is_closed(&self) -> bool {
        self.giver.is_canceled()
    }

    pub fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {
        let (tx, rx) = oneshot::channel();
        self.inner
            .send(Envelope(Some((val, Callback::Retry(tx)))))
            .map(move |_| rx)
            .map_err(|mut e| (e.0).0.take().expect("envelope not dropped").0)
    }
}

impl<T, U> Clone for UnboundedSender<T, U> {
    fn clone(&self) -> Self {
        UnboundedSender {
            giver: self.giver.clone(),
            inner: self.inner.clone(),
        }
    }
}

pub struct Receiver<T, U> {
    inner: mpsc::UnboundedReceiver<Envelope<T, U>>,
    taker: want::Taker,
}

impl<T, U> Receiver<T, U> {
    pub(crate) fn poll_next(
        &mut self,
        cx: &mut task::Context<'_>,
    ) -> Poll<Option<(T, Callback<T, U>)>> {
        match self.inner.poll_recv(cx) {
            Poll::Ready(item) => {
                Poll::Ready(item.map(|mut env| env.0.take().expect("envelope not dropped")))
            }
            Poll::Pending => {
                self.taker.want();
                Poll::Pending
            }
        }
    }

    pub(crate) fn close(&mut self) {
        self.taker.cancel();
        self.inner.close();
    }

    pub(crate) fn try_recv(&mut self) -> Option<(T, Callback<T, U>)> {
        match self.inner.try_recv() {
            Ok(mut env) => env.0.take(),
            Err(_) => None,
        }
    }
}

impl<T, U> Drop for Receiver<T, U> {
    fn drop(&mut self) {
        // Notify the giver about the closure first, before dropping
        // the mpsc::Receiver.
        self.taker.cancel();
    }
}

struct Envelope<T, U>(Option<(T, Callback<T, U>)>);

impl<T, U> Drop for Envelope<T, U> {
    fn drop(&mut self) {
        if let Some((val, cb)) = self.0.take() {
            cb.send(Err((
                crate::Error::new_canceled().with("connection closed"),
                Some(val),
            )));
        }
    }
}

pub enum Callback<T, U> {
    Retry(oneshot::Sender<Result<U, (crate::Error, Option<T>)>>),
    NoRetry(oneshot::Sender<Result<U, crate::Error>>),
}

impl<T, U> Callback<T, U> {
    pub(crate) fn is_canceled(&self) -> bool {
        match *self {
            Callback::Retry(ref tx) => tx.is_closed(),
            Callback::NoRetry(ref tx) => tx.is_closed(),
        }
    }

    pub(crate) fn poll_canceled(&mut self, cx: &mut task::Context<'_>) -> Poll<()> {
        match *self {
            Callback::Retry(ref mut tx) => tx.poll_closed(cx),
            Callback::NoRetry(ref mut tx) => tx.poll_closed(cx),
        }
    }

    pub(crate) fn send(self, val: Result<U, (crate::Error, Option<T>)>) {
        match self {
            Callback::Retry(tx) => {
                let _ = tx.send(val);
            }
            Callback::NoRetry(tx) => {
                let _ = tx.send(val.map_err(|e| e.0));
            }
        }
    }

    pub(crate) fn send_when(
        self,
        mut when: impl Future<Output = Result<U, (crate::Error, Option<T>)>> + Unpin,
    ) -> impl Future<Output = ()> {
        let mut cb = Some(self);

        // "select" on this callback being canceled, and the future completing
        future::poll_fn(move |cx| {
            match Pin::new(&mut when).poll(cx) {
                Poll::Ready(Ok(res)) => {
                    cb.take().expect("polled after complete").send(Ok(res));
                    Poll::Ready(())
                }
                Poll::Pending => {
                    // check if the callback is canceled
                    ready!(cb.as_mut().unwrap().poll_canceled(cx));
                    trace!("send_when canceled");
                    Poll::Ready(())
                }
                Poll::Ready(Err(err)) => {
                    cb.take().expect("polled after complete").send(Err(err));
                    Poll::Ready(())
                }
            }
        })
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "nightly")]
    extern crate test;

    use std::future::Future;
    use std::pin::Pin;
    use std::task::{Context, Poll};

    use super::{channel, Callback, Receiver};

    #[derive(Debug)]
    struct Custom(i32);

    impl<T, U> Future for Receiver<T, U> {
        type Output = Option<(T, Callback<T, U>)>;

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            self.poll_next(cx)
        }
    }

    /// Helper to check if the future is ready after polling once.
    struct PollOnce<'a, F>(&'a mut F);

    impl<F, T> Future for PollOnce<'_, F>
    where
        F: Future<Output = T> + Unpin,
    {
        type Output = Option<()>;

        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            match Pin::new(&mut self.0).poll(cx) {
                Poll::Ready(_) => Poll::Ready(Some(())),
                Poll::Pending => Poll::Ready(None),
            }
        }
    }

    #[tokio::test]
    async fn drop_receiver_sends_cancel_errors() {
        let _ = pretty_env_logger::try_init();

        let (mut tx, mut rx) = channel::<Custom, ()>();

        // must poll once for try_send to succeed
        assert!(PollOnce(&mut rx).await.is_none(), "rx empty");

        let promise = tx.try_send(Custom(43)).unwrap();
        drop(rx);

        let fulfilled = promise.await;
        let err = fulfilled
            .expect("fulfilled")
            .expect_err("promise should error");
        match (err.0.kind(), err.1) {
            (&crate::error::Kind::Canceled, Some(_)) => (),
            e => panic!("expected Error::Cancel(_), found {:?}", e),
        }
    }

    #[tokio::test]
    async fn sender_checks_for_want_on_send() {
        let (mut tx, mut rx) = channel::<Custom, ()>();

        // one is allowed to buffer, second is rejected
        let _ = tx.try_send(Custom(1)).expect("1 buffered");
        tx.try_send(Custom(2)).expect_err("2 not ready");

        assert!(PollOnce(&mut rx).await.is_some(), "rx once");

        // Even though 1 has been popped, only 1 could be buffered for the
        // lifetime of the channel.
        tx.try_send(Custom(2)).expect_err("2 still not ready");

        assert!(PollOnce(&mut rx).await.is_none(), "rx empty");

        let _ = tx.try_send(Custom(2)).expect("2 ready");
    }

    #[test]
    fn unbounded_sender_doesnt_bound_on_want() {
        let (tx, rx) = channel::<Custom, ()>();
        let mut tx = tx.unbound();

        let _ = tx.try_send(Custom(1)).unwrap();
        let _ = tx.try_send(Custom(2)).unwrap();
        let _ = tx.try_send(Custom(3)).unwrap();

        drop(rx);

        let _ = tx.try_send(Custom(4)).unwrap_err();
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn giver_queue_throughput(b: &mut test::Bencher) {
        use crate::{Body, Request, Response};

        let mut rt = tokio::runtime::Builder::new()
            .enable_all()
            .basic_scheduler()
            .build()
            .unwrap();
        let (mut tx, mut rx) = channel::<Request<Body>, Response<Body>>();

        b.iter(move || {
            let _ = tx.send(Request::default()).unwrap();
            rt.block_on(async {
                loop {
                    let poll_once = PollOnce(&mut rx);
                    let opt = poll_once.await;
                    if opt.is_none() {
                        break;
                    }
                }
            });
        })
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn giver_queue_not_ready(b: &mut test::Bencher) {
        let mut rt = tokio::runtime::Builder::new()
            .enable_all()
            .basic_scheduler()
            .build()
            .unwrap();
        let (_tx, mut rx) = channel::<i32, ()>();
        b.iter(move || {
            rt.block_on(async {
                let poll_once = PollOnce(&mut rx);
                assert!(poll_once.await.is_none());
            });
        })
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn giver_queue_cancel(b: &mut test::Bencher) {
        let (_tx, mut rx) = channel::<i32, ()>();

        b.iter(move || {
            rx.taker.cancel();
        })
    }
}
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use std::cell::RefCell;

use utils;
use cursor::{Direction, Cursor};

pub struct Buffer {
    pub file_path: String,
    pub lines: Vec<RefCell<Line>>,

    pub cursor: Cursor,
}

impl Buffer {
    /// Create a new buffer instance
    pub fn new() -> Buffer {
        Buffer {
            file_path: String::new(),
            lines: Vec::new(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        buffer.file_path = path.as_str().unwrap().to_string();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            let mut data = line.clone();
            // remove \n chars
            data.pop();
            buffer.lines.push(RefCell::new(Line::new(data)));
        }

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.lines.iter().enumerate() {
            let ln = line.borrow();
            utils::draw(index, ln.data.clone());
        }
    }

    pub fn draw_status(&self) {
        let height = utils::get_term_height();
        let (cursor_x, cursor_y) = self.cursor.get_position();
        let data = self.file_path.clone();
        let line_count = self.lines.len();
        utils::draw(
            height - 1,
            format!("{}, cursor: {}-{}, termwidth: {}, termheight: {}, lines: {}",
                    data, cursor_x, cursor_y, utils::get_term_height(), utils::get_term_width(), line_count));
    }

    pub fn adjust_cursor(&mut self, dir: Direction) {
        let (mut x, mut y) = self.cursor.get_position();
        match dir {
            Direction::Up => {
                let line = self.get_line_at(y-1);
                if line.is_some() {
                    y -= 1;
                    // if the current cursor offset is after the end of the
                    // previous line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Down => {
                let line = self.get_line_at(y+1);
                if line.is_some() {
                    y += 1;
                    // if the current cursor offset is after the end of the
                    // next line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Right => {
                let line = &self.get_line_at(y);
                if line.is_some() && line.unwrap().borrow().len() > x {
                    x += 1
                }
            }
            Direction::Left => {
                let line = &self.get_line_at(y);
                if line.is_some() && x > 0 {
                    x -= 1
                }
            }
        }
        self.cursor.set_position(x, y);
    }

    pub fn delete_char(&mut self) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 {
            return self.join_line_with_previous(line_num);
        }

        let bits = self.split_line();
        let mut data = bits[0].clone();
        data.pop();

        let new_data = format!("{}{}", data, bits[1]);

        {
            let line = self.get_line_at(line_num);
            line.unwrap().borrow_mut().data = new_data;
        }
        self.cursor.set_position(offset - 1, line_num);
    }

    pub fn insert_char(&mut self, ch: char) {
       let (mut x, y) = self.cursor.get_position();
       {
           let line = &self.get_line_at(y);

           // get Vec<u8> from the current line contents
           let mut data = line.unwrap().borrow().data.clone().into_bytes();

           // add the new character to the Vec at the cursors `x` position
           data.insert(x, ch as u8);

           // convert to Vec back into a string
           let new_data = String::from_utf8(data);

           if new_data.is_ok() {
               // update the line
               line.unwrap().borrow_mut().data = new_data.unwrap();
           }
           x += 1;
       }
       self.cursor.set_position(x, y);

    }

    pub fn insert_new_line(&mut self) {
        let line_num = self.cursor.get_linenum();

        // split the current line at the cursor position
        let bits = &self.split_line();
        self.update_line(bits.clone());

        // move the cursor down and to the start of the next line
        self.cursor.set_position(0, line_num + 1);
    }

    /// Join the line identified by `line_num` with the one at `line_num - 1 `.
    fn join_line_with_previous(&mut self, line_num: uint) {
        let mut current_line_data: String;
        let mut prev_line_data: String;
        let line_len: uint;
        {
            let prev_line = self.get_line_at(line_num - 1);
            if prev_line.is_none() {
                return
            }
            prev_line_data = prev_line.unwrap().borrow().data.clone();
            line_len = prev_line_data.len();
        }
        {
            // get current line data
            let current_line = self.get_line_at(line_num);
            current_line_data = current_line.unwrap().borrow().data.clone();
        }
        {
            // append current line data to prev line
            // FIXME: this is duplicated above in a different scope...
            let prev_line = self.get_line_at(line_num - 1).unwrap();

            let new_data = format!("{}{}", prev_line_data, current_line_data);
            prev_line.borrow_mut().data = new_data;
        }

        // clear the line
        utils::clear_line(line_num);
        // remove current line
        self.lines.remove(line_num);
        // move the cursor
        self.cursor.set_position(line_len, line_num - 1);
    }

    fn update_line(&mut self, mut bits: Vec<String>) {
        let line_num = self.cursor.get_linenum();
        {
            // truncate the current line
            let line = &self.get_line_at(line_num);
            line.unwrap().borrow_mut().data = bits.remove(0).unwrap();
        }

        // add new line below current
        utils::clear_line(line_num+1);
        self.lines.insert(line_num+1, RefCell::new(Line::new(bits.remove(0).unwrap())));
    }

    fn split_line(&mut self) -> Vec<String> {
        let (x, y) = self.cursor.get_position();
        let line = &self.get_line_at(y);

        let data = line.unwrap().borrow().data.clone().into_bytes();
        let old_data = data.slice_to(x);
        let new_data = data.slice_from(x);

        vec!(
            String::from_utf8_lossy(old_data).into_string(),
            String::from_utf8_lossy(new_data).into_string(),
        )
    }

    fn get_line_at(&mut self, line_num: uint) -> Option<&RefCell<Line>> {
        for (index, line) in self.lines.iter().enumerate() {
            if index == line_num {
                return Some(line)
            }
        }
        None
    }

}

pub struct Line {
    pub data: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(data: String) -> Line {
        Line{
            data: data,
        }
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.data.len()
    }
}

<commit_msg>Refactor character removal<commit_after>use std::io::{File, BufferedReader};
use std::cell::RefCell;

use utils;
use cursor::{Direction, Cursor};

pub struct Buffer {
    pub file_path: String,
    pub lines: Vec<RefCell<Line>>,

    pub cursor: Cursor,
}

impl Buffer {
    /// Create a new buffer instance
    pub fn new() -> Buffer {
        Buffer {
            file_path: String::new(),
            lines: Vec::new(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        buffer.file_path = path.as_str().unwrap().to_string();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            let mut data = line.clone();
            // remove \n chars
            data.pop();
            buffer.lines.push(RefCell::new(Line::new(data)));
        }

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.lines.iter().enumerate() {
            let ln = line.borrow();
            utils::draw(index, ln.data.clone());
        }
    }

    pub fn draw_status(&self) {
        let height = utils::get_term_height();
        let (cursor_x, cursor_y) = self.cursor.get_position();
        let data = self.file_path.clone();
        let line_count = self.lines.len();
        utils::draw(
            height - 1,
            format!("{}, cursor: {}-{}, termwidth: {}, termheight: {}, lines: {}",
                    data, cursor_x, cursor_y, utils::get_term_height(), utils::get_term_width(), line_count));
    }

    pub fn adjust_cursor(&mut self, dir: Direction) {
        let (mut x, mut y) = self.cursor.get_position();
        match dir {
            Direction::Up => {
                let line = self.get_line_at(y-1);
                if line.is_some() {
                    y -= 1;
                    // if the current cursor offset is after the end of the
                    // previous line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Down => {
                let line = self.get_line_at(y+1);
                if line.is_some() {
                    y += 1;
                    // if the current cursor offset is after the end of the
                    // next line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Right => {
                let line = &self.get_line_at(y);
                if line.is_some() && line.unwrap().borrow().len() > x {
                    x += 1
                }
            }
            Direction::Left => {
                let line = &self.get_line_at(y);
                if line.is_some() && x > 0 {
                    x -= 1
                }
            }
        }
        self.cursor.set_position(x, y);
    }

    pub fn delete_char(&mut self) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 {
            return self.join_line_with_previous(line_num);
        }

        {
            let line = self.get_line_at(line_num);
            line.unwrap().borrow_mut().data.remove(offset);
        }
        self.cursor.set_position(offset - 1, line_num);
    }

    pub fn insert_char(&mut self, ch: char) {
       let (mut x, y) = self.cursor.get_position();
       {
           let line = &self.get_line_at(y);

           // get Vec<u8> from the current line contents
           let mut data = line.unwrap().borrow().data.clone().into_bytes();

           // add the new character to the Vec at the cursors `x` position
           data.insert(x, ch as u8);

           // convert to Vec back into a string
           let new_data = String::from_utf8(data);

           if new_data.is_ok() {
               // update the line
               line.unwrap().borrow_mut().data = new_data.unwrap();
           }
           x += 1;
       }
       self.cursor.set_position(x, y);

    }

    pub fn insert_new_line(&mut self) {
        let line_num = self.cursor.get_linenum();

        // split the current line at the cursor position
        let bits = &self.split_line();
        self.update_line(bits.clone());

        // move the cursor down and to the start of the next line
        self.cursor.set_position(0, line_num + 1);
    }

    /// Join the line identified by `line_num` with the one at `line_num - 1 `.
    fn join_line_with_previous(&mut self, line_num: uint) {
        let mut current_line_data: String;
        let mut prev_line_data: String;
        let line_len: uint;
        {
            let prev_line = self.get_line_at(line_num - 1);
            if prev_line.is_none() {
                return
            }
            prev_line_data = prev_line.unwrap().borrow().data.clone();
            line_len = prev_line_data.len();
        }
        {
            // get current line data
            let current_line = self.get_line_at(line_num);
            current_line_data = current_line.unwrap().borrow().data.clone();
        }
        {
            // append current line data to prev line
            // FIXME: this is duplicated above in a different scope...
            let prev_line = self.get_line_at(line_num - 1).unwrap();

            let new_data = format!("{}{}", prev_line_data, current_line_data);
            prev_line.borrow_mut().data = new_data;
        }

        // clear the line
        utils::clear_line(line_num);
        // remove current line
        self.lines.remove(line_num);
        // move the cursor
        self.cursor.set_position(line_len, line_num - 1);
    }

    fn update_line(&mut self, mut bits: Vec<String>) {
        let line_num = self.cursor.get_linenum();
        {
            // truncate the current line
            let line = &self.get_line_at(line_num);
            line.unwrap().borrow_mut().data = bits.remove(0).unwrap();
        }

        // add new line below current
        utils::clear_line(line_num+1);
        self.lines.insert(line_num+1, RefCell::new(Line::new(bits.remove(0).unwrap())));
    }

    fn split_line(&mut self) -> Vec<String> {
        let (x, y) = self.cursor.get_position();
        let line = &self.get_line_at(y);

        let data = line.unwrap().borrow().data.clone().into_bytes();
        let old_data = data.slice_to(x);
        let new_data = data.slice_from(x);

        vec!(
            String::from_utf8_lossy(old_data).into_string(),
            String::from_utf8_lossy(new_data).into_string(),
        )
    }

    fn get_line_at(&mut self, line_num: uint) -> Option<&RefCell<Line>> {
        for (index, line) in self.lines.iter().enumerate() {
            if index == line_num {
                return Some(line)
            }
        }
        None
    }

}

pub struct Line {
    pub data: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(data: String) -> Line {
        Line{
            data: data,
        }
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.data.len()
    }
}

<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
//use std::collections::DList;
use std::cell::RefCell;

use utils;
use cursor::{Direction, Cursor};

pub struct Buffer {
    pub file_path: String,
    pub lines: Vec<RefCell<Line>>,

    pub cursor: Cursor,
}

impl Buffer {
    /// Create a new buffer instance
    pub fn new() -> Buffer {
        Buffer {
            file_path: String::new(),
            lines: Vec::new(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        buffer.file_path = path.as_str().unwrap().to_string();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            let mut data = line.clone();
            // remove \n chars
            data.pop();
            buffer.lines.push(RefCell::new(Line::new(data)));
        }

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.lines.iter().enumerate() {
            let ln = line.borrow();
            utils::draw(index, ln.data.clone());
        }
    }

    pub fn draw_status(&self) {
        let height = utils::get_term_height();
        let (cursor_x, cursor_y) = self.cursor.get_position();
        let data = self.file_path.clone();
        let line_count = self.lines.len();
        utils::draw(
            height - 1,
            format!("{}, cursor: {}-{}, termwidth: {}, termheight: {}, lines: {}",
                    data, cursor_x, cursor_y, utils::get_term_height(), utils::get_term_width(), line_count));
    }

    pub fn adjust_cursor(&mut self, dir: Direction) {
        let (mut x, mut y) = self.cursor.get_position();
        match dir {
            Direction::Up => {
                let line = self.get_line_at(y-1);
                if line.is_some() {
                    y -= 1;
                    // if the current cursor offset is after the end of the
                    // next line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Down => {
                let line = self.get_line_at(y+1);
                if line.is_some() {
                    y += 1;
                    // if the current cursor offset is after the end of the
                    // next line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Right => {
                let line = &self.get_line_at(y);
                if line.is_some() && line.unwrap().borrow().len() > x {
                    x += 1
                }
            }
            Direction::Left => {
                let line = &self.get_line_at(y);
                if line.is_some() && x > 0 {
                    x -= 1
                }
            }
        }
        self.cursor.set_position(x, y);
    }

    pub fn insert_char(&mut self, ch: char) {
       let (mut x, y) = self.cursor.get_position();
       {
           let line = &self.get_line_at(y);

           // get Vec<u8> from the current line contents
           let mut data = line.unwrap().borrow().data.clone().into_bytes();

           // add the new character to the Vec at the cursors `x` position
           data.insert(x, ch as u8);

           // convert to Vec back into a string
           let new_data = String::from_utf8(data);

           if new_data.is_ok() {
               // update the line
               line.unwrap().borrow_mut().data = new_data.unwrap();
           }
           x += 1;
       }
       self.cursor.set_position(x, y);

    }

    pub fn insert_new_line(&mut self) {
        let line_num = self.cursor.get_linenum();

        // split the current line at the cursor position
        let bits = &self.split_line();
        self.update_line(bits.clone());

        // move the cursor down and to the start of the next line
        self.cursor.set_position(0, line_num + 1);
    }

    fn update_line(&mut self, mut bits: Vec<String>) {
        let line_num = self.cursor.get_linenum();
        {
            // truncate the current line
            let line = &self.get_line_at(line_num);
            line.unwrap().borrow_mut().data = bits.remove(0).unwrap();
        }

        // add new line below current
        utils::clear_line(line_num+1);
        self.lines.insert(line_num+1, RefCell::new(Line::new(bits.remove(0).unwrap())));
    }

    fn split_line(&mut self) -> Vec<String> {
        let (x, y) = self.cursor.get_position();
        let line = &self.get_line_at(y);

        let data = line.unwrap().borrow().data.clone().into_bytes();
        let old_data = data.slice_to(x);
        let new_data = data.slice_from(x);

        vec!(
            String::from_utf8_lossy(old_data).into_string(),
            String::from_utf8_lossy(new_data).into_string(),
        )
    }

    fn get_line_at(&mut self, line_num: uint) -> Option<&RefCell<Line>> {
        for (index, line) in self.lines.iter().enumerate() {
            if index == line_num {
                return Some(line)
            }
        }
        None
    }

}

pub struct Line {
    data: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(data: String) -> Line {
        Line{
            data: data,
        }
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.data.len()
    }
}

<commit_msg>Fix incorrect comment<commit_after>use std::io::{File, BufferedReader};
//use std::collections::DList;
use std::cell::RefCell;

use utils;
use cursor::{Direction, Cursor};

pub struct Buffer {
    pub file_path: String,
    pub lines: Vec<RefCell<Line>>,

    pub cursor: Cursor,
}

impl Buffer {
    /// Create a new buffer instance
    pub fn new() -> Buffer {
        Buffer {
            file_path: String::new(),
            lines: Vec::new(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        buffer.file_path = path.as_str().unwrap().to_string();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            let mut data = line.clone();
            // remove \n chars
            data.pop();
            buffer.lines.push(RefCell::new(Line::new(data)));
        }

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.lines.iter().enumerate() {
            let ln = line.borrow();
            utils::draw(index, ln.data.clone());
        }
    }

    pub fn draw_status(&self) {
        let height = utils::get_term_height();
        let (cursor_x, cursor_y) = self.cursor.get_position();
        let data = self.file_path.clone();
        let line_count = self.lines.len();
        utils::draw(
            height - 1,
            format!("{}, cursor: {}-{}, termwidth: {}, termheight: {}, lines: {}",
                    data, cursor_x, cursor_y, utils::get_term_height(), utils::get_term_width(), line_count));
    }

    pub fn adjust_cursor(&mut self, dir: Direction) {
        let (mut x, mut y) = self.cursor.get_position();
        match dir {
            Direction::Up => {
                let line = self.get_line_at(y-1);
                if line.is_some() {
                    y -= 1;
                    // if the current cursor offset is after the end of the
                    // previous line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Down => {
                let line = self.get_line_at(y+1);
                if line.is_some() {
                    y += 1;
                    // if the current cursor offset is after the end of the
                    // next line, move the offset back to the end of the line
                    let line_len = line.unwrap().borrow().data.len();
                    if x > line_len {
                        x = line_len;
                    }
                }
            }
            Direction::Right => {
                let line = &self.get_line_at(y);
                if line.is_some() && line.unwrap().borrow().len() > x {
                    x += 1
                }
            }
            Direction::Left => {
                let line = &self.get_line_at(y);
                if line.is_some() && x > 0 {
                    x -= 1
                }
            }
        }
        self.cursor.set_position(x, y);
    }

    pub fn insert_char(&mut self, ch: char) {
       let (mut x, y) = self.cursor.get_position();
       {
           let line = &self.get_line_at(y);

           // get Vec<u8> from the current line contents
           let mut data = line.unwrap().borrow().data.clone().into_bytes();

           // add the new character to the Vec at the cursors `x` position
           data.insert(x, ch as u8);

           // convert to Vec back into a string
           let new_data = String::from_utf8(data);

           if new_data.is_ok() {
               // update the line
               line.unwrap().borrow_mut().data = new_data.unwrap();
           }
           x += 1;
       }
       self.cursor.set_position(x, y);

    }

    pub fn insert_new_line(&mut self) {
        let line_num = self.cursor.get_linenum();

        // split the current line at the cursor position
        let bits = &self.split_line();
        self.update_line(bits.clone());

        // move the cursor down and to the start of the next line
        self.cursor.set_position(0, line_num + 1);
    }

    fn update_line(&mut self, mut bits: Vec<String>) {
        let line_num = self.cursor.get_linenum();
        {
            // truncate the current line
            let line = &self.get_line_at(line_num);
            line.unwrap().borrow_mut().data = bits.remove(0).unwrap();
        }

        // add new line below current
        utils::clear_line(line_num+1);
        self.lines.insert(line_num+1, RefCell::new(Line::new(bits.remove(0).unwrap())));
    }

    fn split_line(&mut self) -> Vec<String> {
        let (x, y) = self.cursor.get_position();
        let line = &self.get_line_at(y);

        let data = line.unwrap().borrow().data.clone().into_bytes();
        let old_data = data.slice_to(x);
        let new_data = data.slice_from(x);

        vec!(
            String::from_utf8_lossy(old_data).into_string(),
            String::from_utf8_lossy(new_data).into_string(),
        )
    }

    fn get_line_at(&mut self, line_num: uint) -> Option<&RefCell<Line>> {
        for (index, line) in self.lines.iter().enumerate() {
            if index == line_num {
                return Some(line)
            }
        }
        None
    }

}

pub struct Line {
    data: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(data: String) -> Line {
        Line{
            data: data,
        }
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.data.len()
    }
}

<|endoftext|>


<commit_before>use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf};

pub mod models;

pub mod key_map;
pub use key_map::{DesktopKeyMap, Error as KeyMapError, MobileKeyMap};
mod modes;
pub use modes::{Desktop, Mobile};

mod loading;
pub use loading::{Error as LoadError, Load};
mod saving;
pub use saving::{Error as SaveError, Save};

// TODO: Implement proper escaping rules
//
// - [x] \u{0} <-> None
// - [ ] escpae unicode categories "C", "Z", "M"
// - [ ] proptests
pub(crate) mod keys;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Targets {
    android: Option<models::TargetAndroid>,
    i_os: Option<models::TargetIOS>,
    mac_os: Option<models::TargetMacOS>,
    windows: Option<models::TargetWindows>,
    chrome: Option<models::TargetChrome>,
    x11: Option<models::TargetX11>,
}

/// A project bundle consists of a `project.yaml` file, a `targets/` directory
/// and a `layouts/` directory.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct ProjectBundle {
    pub path: Option<PathBuf>,
    pub project: models::Project,
    pub layouts: HashMap<String, models::Layout>,
    pub targets: Targets,
}
<commit_msg>Remove obsolete TODO comment<commit_after>use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf};

pub mod models;

pub mod key_map;
pub use key_map::{DesktopKeyMap, Error as KeyMapError, MobileKeyMap};
mod modes;
pub use modes::{Desktop, Mobile};

mod loading;
pub use loading::{Error as LoadError, Load};
mod saving;
pub use saving::{Error as SaveError, Save};

pub(crate) mod keys;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Targets {
    android: Option<models::TargetAndroid>,
    i_os: Option<models::TargetIOS>,
    mac_os: Option<models::TargetMacOS>,
    windows: Option<models::TargetWindows>,
    chrome: Option<models::TargetChrome>,
    x11: Option<models::TargetX11>,
}

/// A project bundle consists of a `project.yaml` file, a `targets/` directory
/// and a `layouts/` directory.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct ProjectBundle {
    pub path: Option<PathBuf>,
    pub project: models::Project,
    pub layouts: HashMap<String, models::Layout>,
    pub targets: Targets,
}
<|endoftext|>


<commit_before>use luminance::M44;
use nalgebra::Rotate;
use std::default::Default;
use std::f32::consts::FRAC_PI_4;

use entity::{Axis, Entity, Translation, X_AXIS, Y_AXIS, Z_AXIS};
use projection::perspective;

pub struct Freefly {
  // sensitivities
  pub yaw_sens: f32,
  pub pitch_sens: f32,
  pub roll_sens: f32,
  pub forward_sens: f32,
  pub strafe_sens: f32,
  pub upward_sens: f32,
  // projection
  pub ratio: f32,
  pub fovy: f32,
  // clipping
  pub znear: f32,
  pub zfar: f32,
}

impl Freefly {
  pub fn new() -> Self {
    Freefly {
      yaw_sens: 0.01,
      pitch_sens: 0.01,
      roll_sens: 0.01,
      forward_sens: 0.1,
      strafe_sens: 0.1,
      upward_sens: 0.1,
      ratio: 4. / 3.,
      fovy: FRAC_PI_4,
      znear: 0.1,
      zfar: 10.,
    }
  }

  pub fn projection_matrix(&self) -> M44 {
    perspective(self.ratio, self.fovy, self.znear, self.zfar)
  }
}

impl Default for Freefly {
  fn default() -> Self {
    Self::new()
  }
}

impl Entity<Freefly> {
  pub fn mv(&mut self, dir: Translation) {
    let cam = &self.object;
    let axis = dir * Axis::new(cam.strafe_sens, cam.upward_sens, cam.forward_sens);
    let v = self.transform.orientation.inverse_rotate(&axis);

    self.transform = self.transform.translate(v);
  }

  pub fn look_around(&mut self, dir: Translation) {
    let cam = &self.object;

    self.transform = self.transform.orient(Y_AXIS, cam.yaw_sens);
    self.transform = self.transform.orient(X_AXIS, cam.pitch_sens);
    self.transform = self.transform.orient(Z_AXIS, cam.roll_sens);
  }
}
<commit_msg>Fixed look_around (#5).<commit_after>use luminance::M44;
use nalgebra::Rotate;
use std::default::Default;
use std::f32::consts::FRAC_PI_4;

use entity::{Axis, Entity, Translation, X_AXIS, Y_AXIS, Z_AXIS};
use projection::perspective;

pub struct Freefly {
  // sensitivities
  pub yaw_sens: f32,
  pub pitch_sens: f32,
  pub roll_sens: f32,
  pub forward_sens: f32,
  pub strafe_sens: f32,
  pub upward_sens: f32,
  // projection
  pub ratio: f32,
  pub fovy: f32,
  // clipping
  pub znear: f32,
  pub zfar: f32,
}

impl Freefly {
  pub fn new() -> Self {
    Freefly {
      yaw_sens: 0.01,
      pitch_sens: 0.01,
      roll_sens: 0.01,
      forward_sens: 0.1,
      strafe_sens: 0.1,
      upward_sens: 0.1,
      ratio: 4. / 3.,
      fovy: FRAC_PI_4,
      znear: 0.1,
      zfar: 10.,
    }
  }

  pub fn projection_matrix(&self) -> M44 {
    perspective(self.ratio, self.fovy, self.znear, self.zfar)
  }
}

impl Default for Freefly {
  fn default() -> Self {
    Self::new()
  }
}

impl Entity<Freefly> {
  pub fn mv(&mut self, dir: Translation) {
    let cam = &self.object;
    let axis = dir * Axis::new(cam.strafe_sens, cam.upward_sens, cam.forward_sens);
    let v = self.transform.orientation.inverse_rotate(&axis);

    self.transform = self.transform.translate(v);
  }

  pub fn look_around(&mut self, dir: Translation) {
    let cam = &self.object;

    self.transform = self.transform.orient(Y_AXIS * dir.y, cam.yaw_sens);
    self.transform = self.transform.orient(X_AXIS * dir.x, cam.pitch_sens);
    self.transform = self.transform.orient(Z_AXIS * dir.z, cam.roll_sens);
  }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use libimagstore::store::Store;
use libimagstore::storeid::StoreIdIterator;

use diaryid::DiaryId;
use diaryid::FromStoreId;
use is_in_diary::IsInDiary;
use entry::Entry as DiaryEntry;
use error::DiaryError as DE;
use error::DiaryErrorKind as DEK;
use result::Result;

/// A iterator for iterating over diary entries
pub struct DiaryEntryIterator<'a> {
    store: &'a Store,
    name: &'a str,
    iter: StoreIdIterator,

    year: Option<i32>,
    month: Option<u32>,
    day: Option<u32>,
}

impl<'a> Debug for DiaryEntryIterator<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "DiaryEntryIterator<name = {}, year = {:?}, month = {:?}, day = {:?}>",
               self.name, self.year, self.month, self.day)
    }

}

impl<'a> DiaryEntryIterator<'a> {

    pub fn new(diaryname: &'a str, store: &'a Store, iter: StoreIdIterator) -> DiaryEntryIterator<'a> {
        DiaryEntryIterator {
            store: store,
            name: diaryname,
            iter: iter,

            year: None,
            month: None,
            day: None,
        }
    }

    // Filter by year, get all diary entries for this year
    pub fn year(mut self, year: i32) -> DiaryEntryIterator<'a> {
        self.year = Some(year);
        self
    }

    // Filter by month, get all diary entries for this month (every year)
    pub fn month(mut self, month: u32) -> DiaryEntryIterator<'a> {
        self.month = Some(month);
        self
    }

    // Filter by day, get all diary entries for this day (every year, every year)
    pub fn day(mut self, day: u32) -> DiaryEntryIterator<'a> {
        self.day = Some(day);
        self
    }

}

impl<'a> Iterator for DiaryEntryIterator<'a> {
    type Item = Result<DiaryEntry<'a>>;

    fn next(&mut self) -> Option<Result<DiaryEntry<'a>>> {
        loop {
            let next = match self.iter.next() {
                Some(s) => s,
                None => return None,
            };
            debug!("Next element: {:?}", next);

            if next.is_in_diary(self.name) {
                debug!("Seems to be in diary: {:?}", next);
                let id = match DiaryId::from_storeid(&next) {
                    Ok(i) => i,
                    Err(e) => {
                        debug!("Couldn't parse {:?} into DiaryId: {:?}", next, e);
                        continue;
                    }
                };
                debug!("Success parsing id = {:?}", id);

                let y = match self.year  { None => true, Some(y) => y == id.year() };
                let m = match self.month { None => true, Some(m) => m == id.month() };
                let d = match self.day   { None => true, Some(d) => d == id.day() };

                if y && m && d {
                    debug!("Return = {:?}", id);
                    return Some(self
                                .store
                                .retrieve(next)
                                .map(|fle| DiaryEntry::new(fle))
                                .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
                                );
                }
            } else {
                debug!("Not in the requested diary ({}): {:?}", self.name, next);
            }
        }
    }

}

<commit_msg>Use trace_error<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use libimagstore::store::Store;
use libimagstore::storeid::StoreIdIterator;

use diaryid::DiaryId;
use diaryid::FromStoreId;
use is_in_diary::IsInDiary;
use entry::Entry as DiaryEntry;
use error::DiaryError as DE;
use error::DiaryErrorKind as DEK;
use result::Result;
use libimagerror::trace::trace_error;

/// A iterator for iterating over diary entries
pub struct DiaryEntryIterator<'a> {
    store: &'a Store,
    name: &'a str,
    iter: StoreIdIterator,

    year: Option<i32>,
    month: Option<u32>,
    day: Option<u32>,
}

impl<'a> Debug for DiaryEntryIterator<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "DiaryEntryIterator<name = {}, year = {:?}, month = {:?}, day = {:?}>",
               self.name, self.year, self.month, self.day)
    }

}

impl<'a> DiaryEntryIterator<'a> {

    pub fn new(diaryname: &'a str, store: &'a Store, iter: StoreIdIterator) -> DiaryEntryIterator<'a> {
        DiaryEntryIterator {
            store: store,
            name: diaryname,
            iter: iter,

            year: None,
            month: None,
            day: None,
        }
    }

    // Filter by year, get all diary entries for this year
    pub fn year(mut self, year: i32) -> DiaryEntryIterator<'a> {
        self.year = Some(year);
        self
    }

    // Filter by month, get all diary entries for this month (every year)
    pub fn month(mut self, month: u32) -> DiaryEntryIterator<'a> {
        self.month = Some(month);
        self
    }

    // Filter by day, get all diary entries for this day (every year, every year)
    pub fn day(mut self, day: u32) -> DiaryEntryIterator<'a> {
        self.day = Some(day);
        self
    }

}

impl<'a> Iterator for DiaryEntryIterator<'a> {
    type Item = Result<DiaryEntry<'a>>;

    fn next(&mut self) -> Option<Result<DiaryEntry<'a>>> {
        loop {
            let next = match self.iter.next() {
                Some(s) => s,
                None => return None,
            };
            debug!("Next element: {:?}", next);

            if next.is_in_diary(self.name) {
                debug!("Seems to be in diary: {:?}", next);
                let id = match DiaryId::from_storeid(&next) {
                    Ok(i) => i,
                    Err(e) => {
                        trace_error(&e);
                        debug!("Couldn't parse {:?} into DiaryId: {:?}", next, e);
                        continue;
                    }
                };
                debug!("Success parsing id = {:?}", id);

                let y = match self.year  { None => true, Some(y) => y == id.year() };
                let m = match self.month { None => true, Some(m) => m == id.month() };
                let d = match self.day   { None => true, Some(d) => d == id.day() };

                if y && m && d {
                    debug!("Return = {:?}", id);
                    return Some(self
                                .store
                                .retrieve(next)
                                .map(|fle| DiaryEntry::new(fle))
                                .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
                                );
                }
            } else {
                debug!("Not in the requested diary ({}): {:?}", self.name, next);
            }
        }
    }

}

<|endoftext|>


<commit_before>use std::error::Error;
use std::io::Write;
use std::io::stderr;

pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "");
}

pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    write!(stderr(), "{}/{} Levels of errors will be printed", (if max > n { n } else { max }), n);
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "");
}

pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        print_trace_maxdepth(idx - 1, e.cause().unwrap(), max);
        write!(stderr(), " -- caused:");
    }
    write!(stderr(), "Error {:>4} : {}", idx, e.description());
    e.cause()
}

/// Count errors in Error::cause() recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + if e.cause().is_some() { count_error_causes(e.cause().unwrap()) } else { 0 }
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("Error {:>4} : {}", idx, e.description());
    if e.cause().is_some() {
        debug!(" -- caused by:");
        print_trace_dbg(idx + 1, e.cause().unwrap());
    }
}

<commit_msg>Add documentation of functions<commit_after>use std::error::Error;
use std::io::Write;
use std::io::stderr;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "");
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    write!(stderr(), "{}/{} Levels of errors will be printed", (if max > n { n } else { max }), n);
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "");
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        print_trace_maxdepth(idx - 1, e.cause().unwrap(), max);
        write!(stderr(), " -- caused:");
    }
    write!(stderr(), "Error {:>4} : {}", idx, e.description());
    e.cause()
}

/// Count errors in Error::cause() recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + if e.cause().is_some() { count_error_causes(e.cause().unwrap()) } else { 0 }
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("Error {:>4} : {}", idx, e.description());
    if e.cause().is_some() {
        debug!(" -- caused by:");
        print_trace_dbg(idx + 1, e.cause().unwrap());
    }
}

<|endoftext|>


<commit_before>use std::kinds::marker;
use std::mem;
use std::c_str::CString;
use libc;
use time;

use {raw, Repository, Error, Tree, Oid};

/// A structure to represent a git [index][1]
///
/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects
pub struct Index {
    raw: *mut raw::git_index,
    marker: marker::NoSync,
}

/// A structure to represent an entry or a file inside of an index.
///
/// All fields of an entry are public for modification and inspection. This is
/// also how a new index entry is created.
#[allow(missing_doc)]
pub struct IndexEntry {
    pub ctime: time::Timespec,
    pub mtime: time::Timespec,
    pub dev: uint,
    pub ino: uint,
    pub mode: uint,
    pub uid: uint,
    pub gid: uint,
    pub file_size: u64,
    pub id: Oid,
    pub flags: u16,
    pub flags_extended: u16,
    pub path: CString,
}

impl Index {
    /// Creates a new in-memory index.
    ///
    /// This index object cannot be read/written to the filesystem, but may be
    /// used to perform in-memory index operations.
    pub fn new() -> Result<Index, Error> {
        ::init();
        let mut raw = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_index_new(&mut raw));
            Ok(Index::from_raw(raw))
        }
    }

    /// Create a new bare Git index object as a memory representation of the Git
    /// index file in 'index_path', without a repository to back it.
    ///
    /// Since there is no ODB or working directory behind this index, any Index
    /// methods which rely on these (e.g. add_path) will fail.
    ///
    /// If you need an index attached to a repository, use the `index()` method
    /// on `Repository`.
    pub fn open(index_path: &Path) -> Result<Index, Error> {
        ::init();
        let mut raw = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_index_open(&mut raw, index_path.to_c_str()));
            Ok(Index::from_raw(raw))
        }
    }

    /// Creates a new index from a raw pointer.
    ///
    /// This function is unsafe as it cannot guarantee the validity of `raw`.
    pub unsafe fn from_raw(raw: *mut raw::git_index) -> Index {
        Index { raw: raw, marker: marker::NoSync }
    }

    /// Add or update an index entry from an in-memory struct
    ///
    /// If a previous index entry exists that has the same path and stage as the
    /// given 'source_entry', it will be replaced. Otherwise, the 'source_entry'
    /// will be added.
    pub fn add(&mut self, source_entry: &IndexEntry) -> Result<(), Error> {
        let mut entry: raw::git_index_entry = unsafe { mem::zeroed() };
        source_entry.configure(&mut entry);
        unsafe {
            try_call!(raw::git_index_add(self.raw, &entry));
            Ok(())
        }
    }

    /// Add or update an index entry from a file on disk
    ///
    /// The file path must be relative to the repository's working folder and
    /// must be readable.
    ///
    /// This method will fail in bare index instances.
    ///
    /// This forces the file to be added to the index, not looking at gitignore
    /// rules.
    ///
    /// If this file currently is the result of a merge conflict, this file will
    /// no longer be marked as conflicting. The data about the conflict will be
    /// moved to the "resolve undo" (REUC) section.
    pub fn add_path(&mut self, path: &Path) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_add_bypath(self.raw, path.to_c_str()));
            Ok(())
        }
    }

    /// Get access to the underlying raw index pointer.
    pub fn raw(&self) -> *mut raw::git_index { self.raw }

    /// Clear the contents (all the entries) of an index object.
    ///
    /// This clears the index object in memory; changes must be explicitly
    /// written to disk for them to take effect persistently via `write_*`.
    pub fn clear(&mut self) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_clear(self.raw)); }
        Ok(())
    }

    /// Get the count of entries currently in the index
    pub fn len(&self) -> uint {
        unsafe { raw::git_index_entrycount(&*self.raw) as uint }
    }

    /// Get one of the entries in the index by its position.
    pub fn get(&self, n: uint) -> Option<IndexEntry> {
        unsafe {
            let ptr = raw::git_index_get_byindex(self.raw, n as libc::size_t);
            if ptr.is_null() {None} else {Some(IndexEntry::from_raw(ptr))}
        }
    }

    /// Get one of the entries in the index by its path.
    pub fn get_path(&self, path: &Path, stage: int) -> Option<IndexEntry> {
        unsafe {
            let ptr = call!(raw::git_index_get_bypath(self.raw, path.to_c_str(),
                                                      stage as libc::c_int));
            if ptr.is_null() {None} else {Some(IndexEntry::from_raw(ptr))}
        }
    }

    /// Get the full path to the index file on disk.
    ///
    /// Returns `None` if this is an in-memory index.
    pub fn path(&self) -> Option<Path> {
        unsafe {
            ::opt_bytes(self, raw::git_index_path(&*self.raw)).map(Path::new)
        }
    }

    /// Update the contents of an existing index object in memory by reading
    /// from the hard disk.
    ///
    /// If force is true, this performs a "hard" read that discards in-memory
    /// changes and always reloads the on-disk index data. If there is no
    /// on-disk version, the index will be cleared.
    ///
    /// If force is false, this does a "soft" read that reloads the index data
    /// from disk only if it has changed since the last time it was loaded.
    /// Purely in-memory index data will be untouched. Be aware: if there are
    /// changes on disk, unwritten in-memory changes are discarded.
    pub fn read(&mut self, force: bool) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_read(self.raw, force)); }
        Ok(())
    }

    /// Read a tree into the index file with stats
    ///
    /// The current index contents will be replaced by the specified tree.
    pub fn read_tree(&mut self, tree: &Tree) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_read_tree(self.raw, &*tree.raw())); }
        Ok(())
    }

    /// Remove an entry from the index
    pub fn remove(&mut self, path: &Path, stage: int) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_remove(self.raw, path.to_c_str(),
                                            stage as libc::c_int));
        }
        Ok(())
    }

    /// Remove an index entry corresponding to a file on disk.
    ///
    /// The file path must be relative to the repository's working folder. It
    /// may exist.
    ///
    /// If this file currently is the result of a merge conflict, this file will
    /// no longer be marked as conflicting. The data about the conflict will be
    /// moved to the "resolve undo" (REUC) section.
    pub fn remove_path(&mut self, path: &Path) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_remove_bypath(self.raw, path.to_c_str()));
        }
        Ok(())
    }

    /// Remove all entries from the index under a given directory.
    pub fn remove_dir(&mut self, path: &Path, stage: int) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_remove_directory(self.raw, path.to_c_str(),
                                                      stage as libc::c_int));
        }
        Ok(())
    }

    /// Write an existing index object from memory back to disk using an atomic
    /// file lock.
    pub fn write(&mut self) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_write(self.raw)); }
        Ok(())
    }

    /// Write the index as a tree.
    ///
    /// This method will scan the index and write a representation of its
    /// current state back to disk; it recursively creates tree objects for each
    /// of the subtrees stored in the index, but only returns the OID of the
    /// root tree. This is the OID that can be used e.g. to create a commit.
    ///
    /// The index instance cannot be bare, and needs to be associated to an
    /// existing repository.
    ///
    /// The index must not contain any file in conflict.
    pub fn write_tree(&mut self) -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0, ..raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_index_write_tree(&mut raw, self.raw));
            Ok(Oid::from_raw(&raw))
        }
    }

    /// Write the index as a tree to the given repository
    ///
    /// This is the same as `write_tree` except that the destination repository
    /// can be chosen.
    pub fn write_tree_to(&mut self, repo: &Repository) -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0, ..raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_index_write_tree_to(&mut raw, self.raw,
                                                   repo.raw()));
            Ok(Oid::from_raw(&raw))
        }
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        unsafe { raw::git_index_free(self.raw) }
    }
}

impl IndexEntry {
    /// Creates a new entry from its raw pointer.
    pub unsafe fn from_raw(raw: *const raw::git_index_entry) -> IndexEntry {
        let raw::git_index_entry {
            ctime, mtime, dev, ino, mode, uid, gid, file_size, id, flags,
            flags_extended, path
        } = *raw;
        IndexEntry {
            dev: dev as uint,
            ino: ino as uint,
            mode: mode as uint,
            uid: uid as uint,
            gid: gid as uint,
            file_size: file_size as u64,
            id: Oid::from_raw(&id),
            flags: flags as u16,
            flags_extended: flags_extended as u16,
            path: CString::new(path, false).clone(),
            mtime: time::Timespec {
                sec: mtime.seconds as i64,
                nsec: mtime.nanoseconds as i32,
            },
            ctime: time::Timespec {
                sec: ctime.seconds as i64,
                nsec: ctime.nanoseconds as i32,
            },
        }
    }

    /// Configures a raw git entry from this entry
    pub fn configure(&self, raw: &mut raw::git_index_entry) {
        *raw = raw::git_index_entry {
            dev: self.dev as libc::c_uint,
            ino: self.ino as libc::c_uint,
            mode: self.mode as libc::c_uint,
            uid: self.uid as libc::c_uint,
            gid: self.gid as libc::c_uint,
            file_size: self.file_size as raw::git_off_t,
            id: unsafe { *self.id.raw() },
            flags: self.flags as libc::c_ushort,
            flags_extended: self.flags_extended as libc::c_ushort,
            path: self.path.as_ptr(),
            mtime: raw::git_index_time {
                seconds: self.mtime.sec as raw::git_time_t,
                nanoseconds: self.mtime.nsec as libc::c_uint,
            },
            ctime: raw::git_index_time {
                seconds: self.ctime.sec as raw::git_time_t,
                nanoseconds: self.ctime.nsec as libc::c_uint,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use std::io::{mod, fs, File, TempDir};
    use url::Url;

    use {Index, Object, Commit, Tree, Reference, Signature, Repository};

    #[test]
    fn smoke() {
        let mut index = Index::new().unwrap();
        assert!(index.add_path(&Path::new(".")).is_err());
        index.clear().unwrap();
        assert_eq!(index.len(), 0);
        assert!(index.get(0).is_none());
        assert!(index.path().is_none());
        assert!(index.read(true).is_err());
    }

    #[test]
    fn smoke_from_repo() {
        let (_td, repo) = ::test::repo_init();
        let mut index = repo.index().unwrap();
        assert!(index.path() == Some(repo.path().join("index")));
        Index::open(&repo.path().join("index")).unwrap();

        index.clear().unwrap();
        index.read(true).unwrap();
        index.write().unwrap();
        index.write_tree().unwrap();
        index.write_tree_to(&repo).unwrap();
    }

    #[test]
    fn smoke_add() {
        let (_td, repo) = ::test::repo_init();
        let mut index = repo.index().unwrap();

        let root = repo.path().dir_path();
        fs::mkdir(&root.join("foo"), io::UserDir).unwrap();
        File::create(&root.join("foo/bar")).unwrap();
        index.add_path(&Path::new("foo/bar")).unwrap();
        index.write().unwrap();

        // Make sure we can use this repo somewhere else now.
        let id = index.write_tree().unwrap();
        let tree = Tree::lookup(&repo, id).unwrap();
        let sig = Signature::default(&repo).unwrap();
        let id = Reference::name_to_id(&repo, "HEAD").unwrap();
        let parent = Commit::lookup(&repo, id).unwrap();
        let commit = Commit::new(&repo, Some("HEAD"), &sig, &sig, "commit",
                                 &tree, [&parent]).unwrap();
        let obj = Object::lookup(&repo, commit, None).unwrap();
        repo.reset(&obj, ::Hard, None, None).unwrap();

        let td2 = TempDir::new("git").unwrap();
        let url = Url::from_file_path(&root).unwrap();
        let url = url.to_string();
        let repo = Repository::clone(url.as_slice(), td2.path()).unwrap();
        let obj = Object::lookup(&repo, commit, None).unwrap();
        repo.reset(&obj, ::Hard, None, None).unwrap();
    }
}

<commit_msg>Fix a test on windows<commit_after>use std::kinds::marker;
use std::mem;
use std::c_str::CString;
use std::path::PosixPath;

use libc;
use time;

use {raw, Repository, Error, Tree, Oid};

/// A structure to represent a git [index][1]
///
/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects
pub struct Index {
    raw: *mut raw::git_index,
    marker: marker::NoSync,
}

/// A structure to represent an entry or a file inside of an index.
///
/// All fields of an entry are public for modification and inspection. This is
/// also how a new index entry is created.
#[allow(missing_doc)]
pub struct IndexEntry {
    pub ctime: time::Timespec,
    pub mtime: time::Timespec,
    pub dev: uint,
    pub ino: uint,
    pub mode: uint,
    pub uid: uint,
    pub gid: uint,
    pub file_size: u64,
    pub id: Oid,
    pub flags: u16,
    pub flags_extended: u16,
    pub path: CString,
}

impl Index {
    /// Creates a new in-memory index.
    ///
    /// This index object cannot be read/written to the filesystem, but may be
    /// used to perform in-memory index operations.
    pub fn new() -> Result<Index, Error> {
        ::init();
        let mut raw = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_index_new(&mut raw));
            Ok(Index::from_raw(raw))
        }
    }

    /// Create a new bare Git index object as a memory representation of the Git
    /// index file in 'index_path', without a repository to back it.
    ///
    /// Since there is no ODB or working directory behind this index, any Index
    /// methods which rely on these (e.g. add_path) will fail.
    ///
    /// If you need an index attached to a repository, use the `index()` method
    /// on `Repository`.
    pub fn open(index_path: &Path) -> Result<Index, Error> {
        ::init();
        let mut raw = 0 as *mut raw::git_index;
        unsafe {
            try_call!(raw::git_index_open(&mut raw, index_path.to_c_str()));
            Ok(Index::from_raw(raw))
        }
    }

    /// Creates a new index from a raw pointer.
    ///
    /// This function is unsafe as it cannot guarantee the validity of `raw`.
    pub unsafe fn from_raw(raw: *mut raw::git_index) -> Index {
        Index { raw: raw, marker: marker::NoSync }
    }

    /// Add or update an index entry from an in-memory struct
    ///
    /// If a previous index entry exists that has the same path and stage as the
    /// given 'source_entry', it will be replaced. Otherwise, the 'source_entry'
    /// will be added.
    pub fn add(&mut self, source_entry: &IndexEntry) -> Result<(), Error> {
        let mut entry: raw::git_index_entry = unsafe { mem::zeroed() };
        source_entry.configure(&mut entry);
        unsafe {
            try_call!(raw::git_index_add(self.raw, &entry));
            Ok(())
        }
    }

    /// Add or update an index entry from a file on disk
    ///
    /// The file path must be relative to the repository's working folder and
    /// must be readable.
    ///
    /// This method will fail in bare index instances.
    ///
    /// This forces the file to be added to the index, not looking at gitignore
    /// rules.
    ///
    /// If this file currently is the result of a merge conflict, this file will
    /// no longer be marked as conflicting. The data about the conflict will be
    /// moved to the "resolve undo" (REUC) section.
    pub fn add_path(&mut self, path: &Path) -> Result<(), Error> {
        // Git apparently expects '/' to be separators for paths
        let mut posix_path = PosixPath::new(".");
        for comp in path.components() {
            posix_path.push(comp);
        }
        unsafe {
            try_call!(raw::git_index_add_bypath(self.raw, posix_path.to_c_str()));
            Ok(())
        }
    }

    /// Get access to the underlying raw index pointer.
    pub fn raw(&self) -> *mut raw::git_index { self.raw }

    /// Clear the contents (all the entries) of an index object.
    ///
    /// This clears the index object in memory; changes must be explicitly
    /// written to disk for them to take effect persistently via `write_*`.
    pub fn clear(&mut self) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_clear(self.raw)); }
        Ok(())
    }

    /// Get the count of entries currently in the index
    pub fn len(&self) -> uint {
        unsafe { raw::git_index_entrycount(&*self.raw) as uint }
    }

    /// Get one of the entries in the index by its position.
    pub fn get(&self, n: uint) -> Option<IndexEntry> {
        unsafe {
            let ptr = raw::git_index_get_byindex(self.raw, n as libc::size_t);
            if ptr.is_null() {None} else {Some(IndexEntry::from_raw(ptr))}
        }
    }

    /// Get one of the entries in the index by its path.
    pub fn get_path(&self, path: &Path, stage: int) -> Option<IndexEntry> {
        unsafe {
            let ptr = call!(raw::git_index_get_bypath(self.raw, path.to_c_str(),
                                                      stage as libc::c_int));
            if ptr.is_null() {None} else {Some(IndexEntry::from_raw(ptr))}
        }
    }

    /// Get the full path to the index file on disk.
    ///
    /// Returns `None` if this is an in-memory index.
    pub fn path(&self) -> Option<Path> {
        unsafe {
            ::opt_bytes(self, raw::git_index_path(&*self.raw)).map(Path::new)
        }
    }

    /// Update the contents of an existing index object in memory by reading
    /// from the hard disk.
    ///
    /// If force is true, this performs a "hard" read that discards in-memory
    /// changes and always reloads the on-disk index data. If there is no
    /// on-disk version, the index will be cleared.
    ///
    /// If force is false, this does a "soft" read that reloads the index data
    /// from disk only if it has changed since the last time it was loaded.
    /// Purely in-memory index data will be untouched. Be aware: if there are
    /// changes on disk, unwritten in-memory changes are discarded.
    pub fn read(&mut self, force: bool) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_read(self.raw, force)); }
        Ok(())
    }

    /// Read a tree into the index file with stats
    ///
    /// The current index contents will be replaced by the specified tree.
    pub fn read_tree(&mut self, tree: &Tree) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_read_tree(self.raw, &*tree.raw())); }
        Ok(())
    }

    /// Remove an entry from the index
    pub fn remove(&mut self, path: &Path, stage: int) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_remove(self.raw, path.to_c_str(),
                                            stage as libc::c_int));
        }
        Ok(())
    }

    /// Remove an index entry corresponding to a file on disk.
    ///
    /// The file path must be relative to the repository's working folder. It
    /// may exist.
    ///
    /// If this file currently is the result of a merge conflict, this file will
    /// no longer be marked as conflicting. The data about the conflict will be
    /// moved to the "resolve undo" (REUC) section.
    pub fn remove_path(&mut self, path: &Path) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_remove_bypath(self.raw, path.to_c_str()));
        }
        Ok(())
    }

    /// Remove all entries from the index under a given directory.
    pub fn remove_dir(&mut self, path: &Path, stage: int) -> Result<(), Error> {
        unsafe {
            try_call!(raw::git_index_remove_directory(self.raw, path.to_c_str(),
                                                      stage as libc::c_int));
        }
        Ok(())
    }

    /// Write an existing index object from memory back to disk using an atomic
    /// file lock.
    pub fn write(&mut self) -> Result<(), Error> {
        unsafe { try_call!(raw::git_index_write(self.raw)); }
        Ok(())
    }

    /// Write the index as a tree.
    ///
    /// This method will scan the index and write a representation of its
    /// current state back to disk; it recursively creates tree objects for each
    /// of the subtrees stored in the index, but only returns the OID of the
    /// root tree. This is the OID that can be used e.g. to create a commit.
    ///
    /// The index instance cannot be bare, and needs to be associated to an
    /// existing repository.
    ///
    /// The index must not contain any file in conflict.
    pub fn write_tree(&mut self) -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0, ..raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_index_write_tree(&mut raw, self.raw));
            Ok(Oid::from_raw(&raw))
        }
    }

    /// Write the index as a tree to the given repository
    ///
    /// This is the same as `write_tree` except that the destination repository
    /// can be chosen.
    pub fn write_tree_to(&mut self, repo: &Repository) -> Result<Oid, Error> {
        let mut raw = raw::git_oid { id: [0, ..raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_index_write_tree_to(&mut raw, self.raw,
                                                   repo.raw()));
            Ok(Oid::from_raw(&raw))
        }
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        unsafe { raw::git_index_free(self.raw) }
    }
}

impl IndexEntry {
    /// Creates a new entry from its raw pointer.
    pub unsafe fn from_raw(raw: *const raw::git_index_entry) -> IndexEntry {
        let raw::git_index_entry {
            ctime, mtime, dev, ino, mode, uid, gid, file_size, id, flags,
            flags_extended, path
        } = *raw;
        IndexEntry {
            dev: dev as uint,
            ino: ino as uint,
            mode: mode as uint,
            uid: uid as uint,
            gid: gid as uint,
            file_size: file_size as u64,
            id: Oid::from_raw(&id),
            flags: flags as u16,
            flags_extended: flags_extended as u16,
            path: CString::new(path, false).clone(),
            mtime: time::Timespec {
                sec: mtime.seconds as i64,
                nsec: mtime.nanoseconds as i32,
            },
            ctime: time::Timespec {
                sec: ctime.seconds as i64,
                nsec: ctime.nanoseconds as i32,
            },
        }
    }

    /// Configures a raw git entry from this entry
    pub fn configure(&self, raw: &mut raw::git_index_entry) {
        *raw = raw::git_index_entry {
            dev: self.dev as libc::c_uint,
            ino: self.ino as libc::c_uint,
            mode: self.mode as libc::c_uint,
            uid: self.uid as libc::c_uint,
            gid: self.gid as libc::c_uint,
            file_size: self.file_size as raw::git_off_t,
            id: unsafe { *self.id.raw() },
            flags: self.flags as libc::c_ushort,
            flags_extended: self.flags_extended as libc::c_ushort,
            path: self.path.as_ptr(),
            mtime: raw::git_index_time {
                seconds: self.mtime.sec as raw::git_time_t,
                nanoseconds: self.mtime.nsec as libc::c_uint,
            },
            ctime: raw::git_index_time {
                seconds: self.ctime.sec as raw::git_time_t,
                nanoseconds: self.ctime.nsec as libc::c_uint,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use std::io::{mod, fs, File, TempDir};
    use url::Url;

    use {Index, Object, Commit, Tree, Reference, Signature, Repository};

    #[test]
    fn smoke() {
        let mut index = Index::new().unwrap();
        assert!(index.add_path(&Path::new(".")).is_err());
        index.clear().unwrap();
        assert_eq!(index.len(), 0);
        assert!(index.get(0).is_none());
        assert!(index.path().is_none());
        assert!(index.read(true).is_err());
    }

    #[test]
    fn smoke_from_repo() {
        let (_td, repo) = ::test::repo_init();
        let mut index = repo.index().unwrap();
        assert!(index.path() == Some(repo.path().join("index")));
        Index::open(&repo.path().join("index")).unwrap();

        index.clear().unwrap();
        index.read(true).unwrap();
        index.write().unwrap();
        index.write_tree().unwrap();
        index.write_tree_to(&repo).unwrap();
    }

    #[test]
    fn smoke_add() {
        let (_td, repo) = ::test::repo_init();
        let mut index = repo.index().unwrap();

        let root = repo.path().dir_path();
        fs::mkdir(&root.join("foo"), io::UserDir).unwrap();
        File::create(&root.join("foo/bar")).unwrap();
        index.add_path(&Path::new("foo/bar")).unwrap();
        index.write().unwrap();

        // Make sure we can use this repo somewhere else now.
        let id = index.write_tree().unwrap();
        let tree = Tree::lookup(&repo, id).unwrap();
        let sig = Signature::default(&repo).unwrap();
        let id = Reference::name_to_id(&repo, "HEAD").unwrap();
        let parent = Commit::lookup(&repo, id).unwrap();
        let commit = Commit::new(&repo, Some("HEAD"), &sig, &sig, "commit",
                                 &tree, [&parent]).unwrap();
        let obj = Object::lookup(&repo, commit, None).unwrap();
        repo.reset(&obj, ::Hard, None, None).unwrap();

        let td2 = TempDir::new("git").unwrap();
        let url = Url::from_file_path(&root).unwrap();
        let url = url.to_string();
        let repo = Repository::clone(url.as_slice(), td2.path()).unwrap();
        let obj = Object::lookup(&repo, commit, None).unwrap();
        repo.reset(&obj, ::Hard, None, None).unwrap();
    }
}

<|endoftext|>


<commit_before>extern crate lazy_static;

use std::env;
use std::io;
use std::path::{Path, PathBuf};
use std::fs::{self, DirEntry};
use std::string::String;

pub struct Config {
    pub steps_file: String,
    pub step_implementations_path: PathBuf,
    pub skel_path: PathBuf,
    pub internal_port: String,
}

lazy_static! {
    pub static ref PROJECT_ROOT: PathBuf = PathBuf::from(env_var("GAUGE_PROJECT_ROOT"));
    pub static ref PLUGIN_SOURCE: PathBuf = match env::current_dir() {
        Ok(d) => d,
        Err(_) => PathBuf::from("")
    };

    pub static ref CONFIG: Config = Config {
        steps_file: String::from("steps.rs"),
        step_implementations_path: path_to("tests", &PROJECT_ROOT),
        skel_path: path_to("skel", &PLUGIN_SOURCE),
        internal_port: env_var("GAUGE_INTERNAL_PORT"),
    };
}

pub fn env_var(ev: &'static str) -> String {
    match env::var(ev) {
        Ok(val) => val,
        Err(_) => String::new(),
    }
}

pub fn path_to<'a>(pathslice: &'a str, root: &PathBuf) -> PathBuf { root.join(pathslice) }

pub fn create_dir(dirpath: &PathBuf) -> io::Result<&PathBuf> {
    try!(fs::create_dir_all(dirpath));
    Ok(dirpath)
}

pub fn copy_file<'a>(from: &'a PathBuf, to: &'a PathBuf) -> io::Result<(&'a PathBuf, &'a PathBuf)> {
    try!(fs::copy(from, to));
    Ok((from, to))
}

// Source: https://doc.rust-lang.org/std/fs/fn.read_dir.html
pub fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(visit_dirs(&entry.path(), cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}
<commit_msg>Use PathBuf in common::visit_dirs()<commit_after>extern crate lazy_static;

use std::env;
use std::io;
use std::path::PathBuf;
use std::fs::{self, DirEntry};
use std::string::String;

pub struct Config {
    pub steps_file: String,
    pub step_implementations_path: PathBuf,
    pub skel_path: PathBuf,
    pub internal_port: String,
}

lazy_static! {
    pub static ref PROJECT_ROOT: PathBuf = PathBuf::from(env_var("GAUGE_PROJECT_ROOT"));
    pub static ref PLUGIN_SOURCE: PathBuf = match env::current_dir() {
        Ok(d) => d,
        Err(_) => PathBuf::from("")
    };

    pub static ref CONFIG: Config = Config {
        steps_file: String::from("steps.rs"),
        step_implementations_path: path_to("tests", &PROJECT_ROOT),
        skel_path: path_to("skel", &PLUGIN_SOURCE),
        internal_port: env_var("GAUGE_INTERNAL_PORT"),
    };
}

pub fn env_var(ev: &'static str) -> String {
    match env::var(ev) {
        Ok(val) => val,
        Err(_) => String::new(),
    }
}

pub fn path_to<'a>(pathslice: &'a str, root: &PathBuf) -> PathBuf { root.join(pathslice) }

pub fn create_dir(dirpath: &PathBuf) -> io::Result<&PathBuf> {
    try!(fs::create_dir_all(dirpath));
    Ok(dirpath)
}

pub fn copy_file<'a>(from: &'a PathBuf, to: &'a PathBuf) -> io::Result<(&'a PathBuf, &'a PathBuf)> {
    try!(fs::copy(from, to));
    Ok((from, to))
}

// Source: https://doc.rust-lang.org/std/fs/fn.read_dir.html
pub fn visit_dirs(dir: &PathBuf, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(visit_dirs(&entry.path(), cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}
<|endoftext|>