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

use std::result::Result;
use handle_table::{Handle};
use ::io::{AsyncRead, AsyncWrite, try_read_internal, write_internal,
           FdObserver, HasHandle, register_new_handle,
           Error};
use {EventLoop, Promise, WaitScope};
use private::{with_current_event_loop};

pub struct Stream {
    stream: ::mio::unix::UnixStream,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Stream
}

pub struct Listener {
    listener: ::mio::unix::UnixListener,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Listener
}

impl Drop for Listener {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Listener {
    pub fn bind<P: AsRef<::std::path::Path>>(addr: P) -> Result<Listener, ::std::io::Error> {
        let listener = try!(::mio::unix::UnixListener::bind(&addr));
        let handle = FdObserver::new();

        with_current_event_loop(move |event_loop| {
            try!(event_loop.event_port.borrow_mut().reactor.register(&listener, ::mio::Token(handle.val),
                                                                         ::mio::EventSet::readable(),
                                                                         ::mio::PollOpt::edge()));
            Ok(Listener { listener: listener, handle: handle, no_send: ::std::marker::PhantomData })
        })
    }

    fn accept_internal(self) -> Promise<(Listener, Stream), Error<Listener>> {
        let accept_result = match self.listener.accept() {
            Err(e) => return Promise::err((Error::new(self, e))),
            Ok(v) => v,
        };
        match accept_result {
            Some(stream) => {
                let handle = match register_new_handle(&stream) {
                    Err(e) => return Promise::err(Error::new(self, e)),
                    Ok(v) => v,
                };
                Promise::ok((self, Stream::new(stream, handle)))
            }
            None => {
                with_current_event_loop(move |event_loop| {
                    let promise =
                        event_loop.event_port.borrow_mut().handler.observers[self.handle].when_becomes_readable();
                    promise.then_else(move |r| match r {
                        Ok(()) => self.accept_internal(),
                        Err(e) => Promise::err(Error::new(self, e))
                    })
                })
            }
        }
    }

    pub fn accept(self) -> Promise<(Listener, Stream), Error<Listener>> {
        Promise::ok(()).then(move |()| self.accept_internal())
    }
}

impl ::std::io::Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        use std::io::Read;
        self.stream.read(buf)
    }
}

impl ::std::io::Write for Stream {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        use std::io::Write;
        self.stream.write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl HasHandle for Stream {
    fn get_handle(&self) -> Handle { self.handle }
}

impl Drop for Stream {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Stream {
    fn new(stream: ::mio::unix::UnixStream, handle: Handle) -> Stream {
        Stream { stream: stream, handle: handle, no_send: ::std::marker::PhantomData }
    }

    pub fn connect<P: AsRef<::std::path::Path>>(addr: P) -> Promise<Stream, ::std::io::Error> {
        let connect_result = ::mio::unix::UnixStream::connect(&addr);
        Promise::ok(()).then(move |()| {
            let stream = pry!(connect_result);

            // TODO: if we're not already connected, maybe only register writable interest,
            // and then reregister with read/write interested once we successfully connect.

            let handle = pry!(register_new_handle(&stream));

            with_current_event_loop(move |event_loop| {
                let promise =
                    event_loop.event_port.borrow_mut().handler.observers[handle].when_becomes_writable();
                promise.map(move |()| {
                    //try!(stream.take_socket_error());
                    Ok(Stream::new(stream, handle))
                })
            })
        })
    }

    pub fn try_clone(&self) -> Result<Stream, ::std::io::Error> {
        let stream = try!(self.stream.try_clone());
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }

    pub unsafe fn from_raw_fd(fd: ::std::os::unix::io::RawFd) -> Result<Stream, ::std::io::Error> {
        let stream = ::std::os::unix::io::FromRawFd::from_raw_fd(fd);
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }
}

impl AsyncRead for Stream {
    fn try_read<T>(self, buf: T,
                   min_bytes: usize) -> Promise<(Self, T, usize), Error<(Self, T)>>
        where T: AsMut<[u8]>
    {
        Promise::ok(()).then(move |()| {
            try_read_internal(self, buf, 0, min_bytes)
        })
    }
}

impl AsyncWrite for Stream {
    fn write<T>(self, buf: T) -> Promise<(Self, T), Error<(Self, T)>> where T: AsRef<[u8]> {
        Promise::ok(()).then(move |()| {
            write_internal(self, buf, 0)
        })
    }
}

/// Creates a new thread and sets up a socket pair that can be used to communicate with it.
/// Passes one of the sockets to the thread's start function and returns the other socket.
/// The new thread will already have an active event loop when `start_func` is called.
pub fn spawn<F>(start_func: F) -> Result<(::std::thread::JoinHandle<()>, Stream), Box<::std::error::Error>>
    where F: FnOnce(Stream, &WaitScope) -> Result<(), Box<::std::error::Error>>,
          F: Send + 'static
{
    use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
    use std::os::unix::io::FromRawFd;

    let (fd0, fd1) =
        // eh... the trait `std::error::Error` is not implemented for the type `nix::Error`
        match socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC) {
            Ok(v) => v,
            Err(_) => {
                return Err(Box::new(::std::io::Error::new(::std::io::ErrorKind::Other,
                                                          "failed to create socketpair")))
            }
        };

    let io = unsafe { ::mio::unix::UnixStream::from_raw_fd(fd0) };
    let handle = try!(register_new_handle(&io));
    let socket_stream = Stream::new(io, handle);

    let join_handle = ::std::thread::spawn(move || {
        let _result = EventLoop::top_level(move |wait_scope| {
            let io = unsafe { ::mio::unix::UnixStream::from_raw_fd(fd1) };
            let handle = try!(register_new_handle(&io));
            let socket_stream = Stream::new(io, handle);
            start_func(socket_stream, &wait_scope)
        });
    });

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

use std::result::Result;
use handle_table::{Handle};
use ::io::{AsyncRead, AsyncWrite, try_read_internal, write_internal,
           FdObserver, HasHandle, register_new_handle,
           Error};
use {EventLoop, Promise, WaitScope};
use private::{with_current_event_loop};

pub struct Stream {
    stream: ::mio::unix::UnixStream,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Stream
}

pub struct Listener {
    listener: ::mio::unix::UnixListener,
    handle: Handle,
    no_send: ::std::marker::PhantomData<*mut ()>, // impl !Send for Listener
}

impl Drop for Listener {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Listener {
    pub fn bind<P: AsRef<::std::path::Path>>(addr: P) -> Result<Listener, ::std::io::Error> {
        let listener = try!(::mio::unix::UnixListener::bind(&addr));
        let handle = FdObserver::new();

        with_current_event_loop(move |event_loop| {
            try!(event_loop.event_port.borrow_mut().reactor.register(&listener, ::mio::Token(handle.val),
                                                                         ::mio::EventSet::readable(),
                                                                         ::mio::PollOpt::edge()));
            Ok(Listener { listener: listener, handle: handle, no_send: ::std::marker::PhantomData })
        })
    }

    fn accept_internal(self) -> Promise<(Listener, Stream), Error<Listener>> {
        let accept_result = match self.listener.accept() {
            Err(e) => return Promise::err((Error::new(self, e))),
            Ok(v) => v,
        };
        match accept_result {
            Some(stream) => {
                let handle = match register_new_handle(&stream) {
                    Err(e) => return Promise::err(Error::new(self, e)),
                    Ok(v) => v,
                };
                Promise::ok((self, Stream::new(stream, handle)))
            }
            None => {
                with_current_event_loop(move |event_loop| {
                    let promise =
                        event_loop.event_port.borrow_mut().handler.observers[self.handle].when_becomes_readable();
                    promise.then_else(move |r| match r {
                        Ok(()) => self.accept_internal(),
                        Err(e) => Promise::err(Error::new(self, e))
                    })
                })
            }
        }
    }

    pub fn accept(self) -> Promise<(Listener, Stream), Error<Listener>> {
        Promise::ok(()).then(move |()| self.accept_internal())
    }
}

impl ::std::io::Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        use std::io::Read;
        self.stream.read(buf)
    }
}

impl ::std::io::Write for Stream {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        use std::io::Write;
        self.stream.write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl HasHandle for Stream {
    fn get_handle(&self) -> Handle { self.handle }
}

impl Drop for Stream {
    fn drop(&mut self) {
        with_current_event_loop(move |event_loop| {
            event_loop.event_port.borrow_mut().handler.observers.remove(self.handle);
        })
    }
}

impl Stream {
    fn new(stream: ::mio::unix::UnixStream, handle: Handle) -> Stream {
        Stream { stream: stream, handle: handle, no_send: ::std::marker::PhantomData }
    }

    pub fn connect<P: AsRef<::std::path::Path>>(addr: P) -> Promise<Stream, ::std::io::Error> {
        let connect_result = ::mio::unix::UnixStream::connect(&addr);
        Promise::ok(()).then(move |()| {
            let stream = pry!(connect_result);

            // TODO: if we're not already connected, maybe only register writable interest,
            // and then reregister with read/write interested once we successfully connect.

            let handle = pry!(register_new_handle(&stream));

            with_current_event_loop(move |event_loop| {
                let promise =
                    event_loop.event_port.borrow_mut().handler.observers[handle].when_becomes_writable();
                promise.map(move |()| {
                    //try!(stream.take_socket_error());
                    Ok(Stream::new(stream, handle))
                })
            })
        })
    }

    pub fn new_pair() -> Result<(Stream, Stream), ::std::io::Error> {
        use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
        use std::os::unix::io::FromRawFd;

        let (fd1, fd2) =
            try!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC)
                 .map_err(|_| ::std::io::Error::new(::std::io::ErrorKind::Other,
                                                    "failed to create socketpair")));

        unsafe { Ok((try!(Stream::from_raw_fd(fd1)), try!(Stream::from_raw_fd(fd2)))) }
    }

    pub fn try_clone(&self) -> Result<Stream, ::std::io::Error> {
        let stream = try!(self.stream.try_clone());
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }

    pub unsafe fn from_raw_fd(fd: ::std::os::unix::io::RawFd) -> Result<Stream, ::std::io::Error> {
        let stream = ::std::os::unix::io::FromRawFd::from_raw_fd(fd);
        let handle = try!(register_new_handle(&stream));
        Ok(Stream::new(stream, handle))
    }
}

impl AsyncRead for Stream {
    fn try_read<T>(self, buf: T,
                   min_bytes: usize) -> Promise<(Self, T, usize), Error<(Self, T)>>
        where T: AsMut<[u8]>
    {
        Promise::ok(()).then(move |()| {
            try_read_internal(self, buf, 0, min_bytes)
        })
    }
}

impl AsyncWrite for Stream {
    fn write<T>(self, buf: T) -> Promise<(Self, T), Error<(Self, T)>> where T: AsRef<[u8]> {
        Promise::ok(()).then(move |()| {
            write_internal(self, buf, 0)
        })
    }
}

/// Creates a new thread and sets up a socket pair that can be used to communicate with it.
/// Passes one of the sockets to the thread's start function and returns the other socket.
/// The new thread will already have an active event loop when `start_func` is called.
pub fn spawn<F>(start_func: F) -> Result<(::std::thread::JoinHandle<()>, Stream), Box<::std::error::Error>>
    where F: FnOnce(Stream, &WaitScope) -> Result<(), Box<::std::error::Error>>,
          F: Send + 'static
{
    use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};
    use std::os::unix::io::FromRawFd;

    let (fd0, fd1) =
        // eh... the trait `std::error::Error` is not implemented for the type `nix::Error`
        match socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC) {
            Ok(v) => v,
            Err(_) => {
                return Err(Box::new(::std::io::Error::new(::std::io::ErrorKind::Other,
                                                          "failed to create socketpair")))
            }
        };

    let socket_stream = try!(unsafe { Stream::from_raw_fd(fd0) });

    let join_handle = ::std::thread::spawn(move || {
        let _result = EventLoop::top_level(move |wait_scope| {
            let socket_stream = try!(unsafe { Stream::from_raw_fd(fd1) });
            start_func(socket_stream, &wait_scope)
        });
    });

    return Ok((join_handle, socket_stream));
}
<|endoftext|>


<commit_before>use base_db::fixture::WithFixture;

use crate::test_db::TestDB;

fn check_diagnostics(ra_fixture: &str) {
    let db: TestDB = TestDB::with_files(ra_fixture);
    db.check_diagnostics();
}

#[test]
fn unresolved_import() {
    check_diagnostics(
        r"
        use does_exist;
        use does_not_exist;
          //^^^^^^^^^^^^^^ unresolved import

        mod does_exist {}
        ",
    );
}

#[test]
fn unresolved_import_in_use_tree() {
    // Only the relevant part of a nested `use` item should be highlighted.
    check_diagnostics(
        r"
        use does_exist::{Exists, DoesntExist};
                               //^^^^^^^^^^^ unresolved import

        use {does_not_exist::*, does_exist};
           //^^^^^^^^^^^^^^^^^ unresolved import

        use does_not_exist::{
            a,
          //^ unresolved import
            b,
          //^ unresolved import
            c,
          //^ unresolved import
        };

        mod does_exist {
            pub struct Exists;
        }
        ",
    );
}

#[test]
fn unresolved_extern_crate() {
    check_diagnostics(
        r"
        //- /main.rs crate:main deps:core
        extern crate core;
          extern crate doesnotexist;
        //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
        //- /lib.rs crate:core
        ",
    );
}

#[test]
fn dedup_unresolved_import_from_unresolved_crate() {
    check_diagnostics(
        r"
        //- /main.rs crate:main
        mod a {
            extern crate doesnotexist;
          //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate

            // Should not error, since we already errored for the missing crate.
            use doesnotexist::{self, bla, *};

            use crate::doesnotexist;
              //^^^^^^^^^^^^^^^^^^^ unresolved import
        }

        mod m {
            use super::doesnotexist;
              //^^^^^^^^^^^^^^^^^^^ unresolved import
        }
        ",
    );
}

#[test]
fn unresolved_module() {
    check_diagnostics(
        r"
        //- /lib.rs
        mod foo;
          mod bar;
        //^^^^^^^^ unresolved module
        mod baz {}
        //- /foo.rs
        ",
    );
}

#[test]
fn inactive_item() {
    // Additional tests in `cfg` crate. This only tests disabled cfgs.

    check_diagnostics(
        r#"
        //- /lib.rs
          #[cfg(no)] pub fn f() {}
        //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled

          #[cfg(no)] #[cfg(no2)] mod m;
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled

          #[cfg(all(not(a), b))] enum E {}
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled

          #[cfg(feature = "std")] use std;
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled
        "#,
    );
}
<commit_msg>Add test<commit_after>use base_db::fixture::WithFixture;

use crate::test_db::TestDB;

fn check_diagnostics(ra_fixture: &str) {
    let db: TestDB = TestDB::with_files(ra_fixture);
    db.check_diagnostics();
}

#[test]
fn unresolved_import() {
    check_diagnostics(
        r"
        use does_exist;
        use does_not_exist;
          //^^^^^^^^^^^^^^ unresolved import

        mod does_exist {}
        ",
    );
}

#[test]
fn unresolved_import_in_use_tree() {
    // Only the relevant part of a nested `use` item should be highlighted.
    check_diagnostics(
        r"
        use does_exist::{Exists, DoesntExist};
                               //^^^^^^^^^^^ unresolved import

        use {does_not_exist::*, does_exist};
           //^^^^^^^^^^^^^^^^^ unresolved import

        use does_not_exist::{
            a,
          //^ unresolved import
            b,
          //^ unresolved import
            c,
          //^ unresolved import
        };

        mod does_exist {
            pub struct Exists;
        }
        ",
    );
}

#[test]
fn unresolved_extern_crate() {
    check_diagnostics(
        r"
        //- /main.rs crate:main deps:core
        extern crate core;
          extern crate doesnotexist;
        //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
        //- /lib.rs crate:core
        ",
    );
}

#[test]
fn dedup_unresolved_import_from_unresolved_crate() {
    check_diagnostics(
        r"
        //- /main.rs crate:main
        mod a {
            extern crate doesnotexist;
          //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate

            // Should not error, since we already errored for the missing crate.
            use doesnotexist::{self, bla, *};

            use crate::doesnotexist;
              //^^^^^^^^^^^^^^^^^^^ unresolved import
        }

        mod m {
            use super::doesnotexist;
              //^^^^^^^^^^^^^^^^^^^ unresolved import
        }
        ",
    );
}

#[test]
fn unresolved_module() {
    check_diagnostics(
        r"
        //- /lib.rs
        mod foo;
          mod bar;
        //^^^^^^^^ unresolved module
        mod baz {}
        //- /foo.rs
        ",
    );
}

#[test]
fn inactive_item() {
    // Additional tests in `cfg` crate. This only tests disabled cfgs.

    check_diagnostics(
        r#"
        //- /lib.rs
          #[cfg(no)] pub fn f() {}
        //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled

          #[cfg(no)] #[cfg(no2)] mod m;
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled

          #[cfg(all(not(a), b))] enum E {}
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled

          #[cfg(feature = "std")] use std;
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled
        "#,
    );
}

/// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
#[test]
fn inactive_via_cfg_attr() {
    check_diagnostics(
        r#"
        //- /lib.rs
          #[cfg_attr(not(never), cfg(no))] fn f() {}
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled

          #[cfg_attr(not(never), cfg(not(no)))] fn f() {}

          #[cfg_attr(never, cfg(no))] fn g() {}
        "#,
    );
}
<|endoftext|>


<commit_before>extern crate htmlescape;

use irc::client::prelude::*;

use regex::Regex;

use plugin::*;
use utils::Url;

use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;
use failure::ResultExt;

lazy_static! {
    static ref URL_RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
    static ref WORD_RE: Regex = Regex::new(r"(\w+)").unwrap();
}

#[derive(PluginName, Debug)]
pub struct UrlTitles {
    max_kib: usize,
}

#[derive(Clone, Debug)]
struct Title(String);

impl From<String> for Title {
    fn from(title: String) -> Self {
        Title(title)
    }
}

impl From<Title> for String {
    fn from(title: Title) -> Self {
        title.0
    }
}

impl Title {
    fn find_by_delimiters(body: &str, delimiters: [&str; 3]) -> Result<Self, UrlError> {
        let title = body.find(delimiters[0])
            .map(|tag| {
                body[tag..]
                    .find(delimiters[1])
                    .map(|offset| tag + offset + delimiters[1].len())
                    .map(|start| {
                        body[start..]
                            .find(delimiters[2])
                            .map(|offset| start + offset)
                            .map(|end| &body[start..end])
                    })
            })
            .and_then(|s| s.and_then(|s| s))
            .ok_or(ErrorKind::MissingTitle)?;

        debug!("delimiters: {:?}", delimiters);
        debug!("title: {:?}", title);

        htmlescape::decode_html(title)
            .map(|t| t.into())
            .map_err(|_| ErrorKind::HtmlDecoding.into())
    }

    fn find_ogtitle<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["property=\"og:title\"", "content=\"", "\""])
    }

    fn find_title<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["<title", ">", "</title>"])
    }

    // TODO Improve logic
    fn is_useful(&self, url: &str) -> bool {
        for word in WORD_RE.find_iter(&self.0) {
            let w = word.as_str().to_lowercase();
            if w.len() > 2 && !url.to_lowercase().contains(&w) {
                return true;
            }
        }

        return false;
    }

    fn into_useful_title<'a>(self, url: &str) -> Result<Self, UrlError> {
        if self.is_useful(url) {
            Ok(self)
        } else {
            Err(ErrorKind::UselessTitle)?
        }
    }

    fn clean_up(self) -> Self {
        self.0.trim().replace('\n', "|").replace('\r', "|").into()
    }

    pub fn find_useful_ogtitle<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        Self::find_ogtitle(body)
            .and_then(|t| t.into_useful_title(url))
            .map(|t| t.clean_up())
    }

    pub fn find_useful_title<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        Self::find_title(body)
            .and_then(|t| t.into_useful_title(url))
            .map(|t| t.clean_up())
    }
}

impl UrlTitles {
    /// If a file is larger than `max_kib` KiB the download is stopped
    pub fn new(max_kib: usize) -> Self {
        UrlTitles { max_kib: max_kib }
    }

    fn grep_url<'a>(&self, msg: &'a str) -> Option<Url<'a>> {
        let captures = URL_RE.captures(msg)?;
        debug!("Url captures: {:?}", captures);

        Some(captures.get(2)?.as_str().into())
    }

    fn url(&self, text: &str) -> Result<String, UrlError> {
        let url = self.grep_url(text)
            .ok_or(ErrorKind::MissingUrl)?
            .max_kib(self.max_kib);
        let body = url.request().context(ErrorKind::Download)?;

        let title = match Title::find_useful_ogtitle(&body, url.as_str()) {
            Ok(t) => t,
            Err(e) => match e.kind() {
                ErrorKind::MissingTitle | ErrorKind::UselessTitle => {
                    Title::find_useful_title(&body, url.as_str())?
                }
                _ => Err(e)?,
            },
        };

        Ok(title.into())
    }
}

impl Plugin for UrlTitles {
    fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::PRIVMSG(_, ref msg) => if URL_RE.is_match(msg) {
                ExecutionStatus::RequiresThread
            } else {
                ExecutionStatus::Done
            },
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
        Ok(match message.command {
            Command::PRIVMSG(_, ref content) => match self.url(content) {
                Ok(title) => client
                    .send_privmsg(message.response_target().unwrap(), &title)
                    .context(FrippyErrorKind::Connection)?,
                Err(e) => Err(e).context(FrippyErrorKind::Url)?,
            },
            _ => (),
        })
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        Ok(client
            .send_notice(
                &command.source,
                "This Plugin does not implement any commands.",
            )
            .context(FrippyErrorKind::Connection)?)
    }

    fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
        self.url(&command.tokens[0])
            .map_err(|e| e.cause().unwrap().to_string())
    }
}

pub mod error {
    /// A URL plugin error
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "UrlError"]
    pub enum ErrorKind {
        /// A download error
        #[fail(display = "A download error occured")]
        Download,

        /// Missing URL error
        #[fail(display = "No URL was found")]
        MissingUrl,

        /// Missing title error
        #[fail(display = "No title was found")]
        MissingTitle,

        /// Useless title error
        #[fail(display = "Title was not helpful")]
        UselessTitle,

        /// Html decoding error
        #[fail(display = "Failed to decode Html characters")]
        HtmlDecoding,
    }
}
<commit_msg>Take better title instead of first found<commit_after>extern crate htmlescape;

use irc::client::prelude::*;

use regex::Regex;

use plugin::*;
use utils::Url;

use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;
use failure::ResultExt;

lazy_static! {
    static ref URL_RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
    static ref WORD_RE: Regex = Regex::new(r"(\w+)").unwrap();
}

#[derive(PluginName, Debug)]
pub struct UrlTitles {
    max_kib: usize,
}

#[derive(Clone, Debug)]
struct Title(String);

impl From<String> for Title {
    fn from(title: String) -> Self {
        Title(title)
    }
}

impl From<Title> for String {
    fn from(title: Title) -> Self {
        title.0
    }
}

impl Title {
    fn find_by_delimiters(body: &str, delimiters: [&str; 3]) -> Result<Self, UrlError> {
        let title = body.find(delimiters[0])
            .map(|tag| {
                body[tag..]
                    .find(delimiters[1])
                    .map(|offset| tag + offset + delimiters[1].len())
                    .map(|start| {
                        body[start..]
                            .find(delimiters[2])
                            .map(|offset| start + offset)
                            .map(|end| &body[start..end])
                    })
            })
            .and_then(|s| s.and_then(|s| s))
            .ok_or(ErrorKind::MissingTitle)?;

        debug!("delimiters: {:?}", delimiters);
        debug!("title: {:?}", title);

        htmlescape::decode_html(title)
            .map(|t| t.into())
            .map_err(|_| ErrorKind::HtmlDecoding.into())
    }

    fn find_ogtitle<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["property=\"og:title\"", "content=\"", "\""])
    }

    fn find_title<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["<title", ">", "</title>"])
    }

    // TODO Improve logic
    pub fn usefulness(&self, url: &str) -> usize {
        let mut usefulness = 0;
        for word in WORD_RE.find_iter(&self.0) {
            let w = word.as_str().to_lowercase();
            if w.len() > 2 && !url.to_lowercase().contains(&w) {
                usefulness += 1;
            }
        }

        usefulness
    }

    fn clean_up(self) -> Self {
        self.0.trim().replace('\n', "|").replace('\r', "|").into()
    }

    pub fn find_clean_ogtitle<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        Self::find_ogtitle(body)
            .map(|t| t.clean_up())
    }

    pub fn find_clean_title<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        Self::find_title(body)
            .map(|t| t.clean_up())
    }
}

impl UrlTitles {
    /// If a file is larger than `max_kib` KiB the download is stopped
    pub fn new(max_kib: usize) -> Self {
        UrlTitles { max_kib: max_kib }
    }

    fn grep_url<'a>(&self, msg: &'a str) -> Option<Url<'a>> {
        let captures = URL_RE.captures(msg)?;
        debug!("Url captures: {:?}", captures);

        Some(captures.get(2)?.as_str().into())
    }

    fn url(&self, text: &str) -> Result<String, UrlError> {
        let url = self.grep_url(text)
            .ok_or(ErrorKind::MissingUrl)?
            .max_kib(self.max_kib);
        let body = url.request().context(ErrorKind::Download)?;

        let title = Title::find_clean_title(&body, url.as_str());
        let og_title = Title::find_clean_ogtitle(&body, url.as_str());

        let title = match (title, og_title) {
            (Ok(title), Ok(og_title)) => {
                if title.usefulness(url.as_str()) > og_title.usefulness(url.as_str()) {
                    title
                } else {
                    og_title
                }
            },
            (Ok(title), _) => title,
            (_, Ok(title)) => title,
            (Err(e), _) => Err(e)?,
        };

        Ok(title.into())
    }
}

impl Plugin for UrlTitles {
    fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::PRIVMSG(_, ref msg) => if URL_RE.is_match(msg) {
                ExecutionStatus::RequiresThread
            } else {
                ExecutionStatus::Done
            },
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
        Ok(match message.command {
            Command::PRIVMSG(_, ref content) => match self.url(content) {
                Ok(title) => client
                    .send_privmsg(message.response_target().unwrap(), &title)
                    .context(FrippyErrorKind::Connection)?,
                Err(e) => Err(e).context(FrippyErrorKind::Url)?,
            },
            _ => (),
        })
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        Ok(client
            .send_notice(
                &command.source,
                "This Plugin does not implement any commands.",
            )
            .context(FrippyErrorKind::Connection)?)
    }

    fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
        self.url(&command.tokens[0])
            .map_err(|e| e.cause().unwrap().to_string())
    }
}

pub mod error {
    /// A URL plugin error
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "UrlError"]
    pub enum ErrorKind {
        /// A download error
        #[fail(display = "A download error occured")]
        Download,

        /// Missing URL error
        #[fail(display = "No URL was found")]
        MissingUrl,

        /// Missing title error
        #[fail(display = "No title was found")]
        MissingTitle,

        /// Html decoding error
        #[fail(display = "Failed to decode Html characters")]
        HtmlDecoding,
    }
}
<|endoftext|>


<commit_before>use naulang::interpreter::frame::Frame;
use std::rc::Rc;

#[derive(PartialEq)]
pub enum TaskState {
    Continue,
    Halt,
    Yield,
    Suspend,
}

pub struct Task<'task> {
    state:       TaskState,
    top_frame:   Option<&'task mut Frame>,
    parent_task: Option<Rc<Task<'task>>>,
}

impl<'task> Task<'task> {
    pub fn new() -> Task<'task> {
        Task {
            state: TaskState::Continue,
            top_frame: Option::None,
            parent_task: Option::None,
        }
    }

    pub fn set_parent_task(&mut self, task: Task<'task>) -> () {
        let rc_task = Rc::new(task);
        self.parent_task = Some(rc_task);
    }
}

#[cfg(test)]
mod tests {
    use super::{Task, TaskState};
    use naulang::interpreter::frame::{Frame, FrameInfo};
    use std::ops::Deref;

    #[test]
    fn test_new_task_state() {
        assert!(Task::new().state == TaskState::Continue);
    }

    #[test]
    fn test_set_parent_task() {
        let mut root_task = Task::new();

        // Create new Task in short lived scope
        {
            // TODO: Proper initialisation, here we're mutating, and then later
            // moving immutable
            let mut next_task = Task::new();
            (*&mut next_task.state) = TaskState::Halt;

            let next_task = next_task;
            root_task.set_parent_task(next_task);
        }

        let task_is_set = match root_task.parent_task {
            Some(rc_task) => rc_task.deref().state == TaskState::Halt,
            None => false
        };

        assert!(task_is_set);
    }
}
<commit_msg>Just allocate on the heap without ref count<commit_after>use naulang::interpreter::frame::Frame;

#[derive(PartialEq)]
pub enum TaskState {
    Continue,
    Halt,
    Yield,
    Suspend,
}

pub struct Task<'task> {
    state:       TaskState,
    top_frame:   Option<&'task mut Frame>,
    parent_task: Option<Box<Task<'task>>>,
}

impl<'task> Task<'task> {
    pub fn new() -> Task<'task> {
        Task {
            state: TaskState::Continue,
            top_frame: Option::None,
            parent_task: Option::None,
        }
    }

    pub fn set_parent_task(&mut self, task: Task<'task>) -> () {
        self.parent_task =  Some(Box::new(task));
    }
}

#[cfg(test)]
mod tests {
    use super::{Task, TaskState};
    use naulang::interpreter::frame::{Frame, FrameInfo};
    use std::ops::Deref;

    #[test]
    fn test_new_task_state() {
        assert!(Task::new().state == TaskState::Continue);
    }

    #[test]
    fn test_set_parent_task() {
        let mut root_task = Task::new();

        // Create new Task in short lived scope
        {
            // TODO: Proper initialisation, here we're mutating, and then later
            // moving immutable
            let mut next_task = Task::new();
            (*&mut next_task.state) = TaskState::Halt;

            let next_task = next_task;
            root_task.set_parent_task(next_task);
        }

        let task_is_set = match root_task.parent_task {
            Some(rc_task) => rc_task.deref().state == TaskState::Halt,
            None => false
        };

        assert!(task_is_set);
    }
}
<|endoftext|>


<commit_before>
use std::io;
use std::clone::Clone;
use std::slice::Iter;

use linked_hash_map::LinkedHashMap;

use parser::ast::*;
use parser::util::*;
use processing::structs::*;
use output::client_ops_stream_writer::*;
use output::client_misc::*;
use output::scope::*;

#[derive(Debug)]
pub struct BlockDefinition {
    pub block_id: String,
    pub ops: Vec<ElementOp>
}
pub type BlockMap = LinkedHashMap<String, BlockDefinition>;

pub struct ElementOpsWriter<'input: 'scope, 'scope> {
    pub doc: &'input DocumentState<'input>,
    pub stream_writer: &'scope mut ElementOpsStreamWriter,
    pub scopes: LinkedHashMap<String, ElementOpScope>,
    pub blocks: BlockMap,
    pub cur_block_id: Option<String>
}

impl<'input: 'scope, 'scope> ElementOpsWriter<'input, 'scope> {

    pub fn with_doc(doc: &'input DocumentState<'input>, stream_writer: &'scope mut ElementOpsStreamWriter) -> Self {
        ElementOpsWriter {
            doc: doc,
            stream_writer: stream_writer,
            scopes: Default::default(),
            blocks: Default::default(),
            cur_block_id: None
        }
    }

    #[inline]
    fn write_loop_item(&mut self, w: &mut io::Write, doc: &'input DocumentState, item_expr: &ExprValue, scope: &ElementOpScope, ele: Option<&str>, element_ty: Option<&VarType>, block_id: &str, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(ele_key) = ele {
            scope.add_loop_var_with_value(ele_key, item_expr);

            // loop_scope.1.symbol_map.insert(ele_key.to_owned(), (Some(SymbolReferenceType::LoopVarReference(ele_key.to_owned())), None));
            // loop_scope = loop_scope
            //     .with_var(ele_key,
            //         SymbolReferenceType::LoopVarReference(ele_key.to_owned()),
            //         element_ty.as_ref().map(Clone::clone),
            //         Some(SymbolValueType::ConstantValue(item_expr.clone()))
            //     );
        };

        let block_ops = self.blocks.get(block_id)
            .map(|block| block.ops.clone());

        if let Some(ref block_ops) = block_ops {
            // Push scope
            let scope_id = format!("{}_{}", scope.0.key_prefix(block_id), 1);
            self.scopes.insert(scope_id, scope.clone());

            // Output ops
            self.write_ops_content(w, block_ops.iter(), doc, &scope, output_component_contents)?;

            // Pop scope
            self.scopes.pop_back();
        };
        Ok(())
    }

    #[inline]
    fn invoke_component_with_props(&mut self, w: &mut io::Write, doc: &'input DocumentState, scope: &ElementOpScope, comp: &Component, props: Option<Iter<Prop>>, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(props) = props {
            for &(ref key, ref expr) in props {
                if let Some(ref expr) = expr.as_ref().and_then(|expr| reduce_expr(&expr, doc, &scope)) {
                    scope.add_prop_with_value(key, &expr);
                };
            }
        };

        // for (key, param) in comp.props.iter() {
            // if let Some(_) = scope.1.props.get(key) {
            //     let sym = Symbol::prop(key);
            //     let sym_ref = ExprValue::SymbolReference(sym);
            //     scope.add_prop_with_value(key, &sym_ref);
            //     continue;
            // };

            // if let Some(ref expr) = doc.resolve_symbol_value(param) {
            //     prop_scope.add_prop_with_value(key, &expr);
            // };

            // if let &Symbol(SymbolReferenceType::PropReference(ref var_name), _, _) = param {
            //     if let Some(&Symbol(SymbolReferenceType::ReducerKeyReference(ref reducer_key), _, Some(box ref expr))) = scope.1.props.get(var_name) {
            //         if let Some(ref expr) = reduce_expr(&expr, doc, scope) {
            //             //let value = ExprValue::SymbolReference(sym.clone());
            //             prop_scope.add_prop_with_value(key, &expr);
            //         };
            //     };
            // };
        // }

        let scope_key = allocate_element_key();
        let scope_id = scope.0.key_prefix(&scope_key);
        self.scopes.insert(scope_id, scope.clone());

        if let Some(ref ops) = comp.ops {
            self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
        };
        Ok(())
    }

    #[inline]
    #[allow(unused_variables)]
    pub fn write_ops_content<'op>(&mut self, w: &mut io::Write, ops: Iter<'op, ElementOp>, doc: &'input DocumentState, scope: &ElementOpScope, output_component_contents: bool) -> Result {
        for op in ops {
            if output_component_contents {
                if let &ElementOp::EndBlock(..) = op {
                    self.cur_block_id = None;
                    continue;
                };

                if let Some(ref cur_block_id) = self.cur_block_id {
                    let block = self.blocks.entry(cur_block_id.to_owned())
                        .or_insert_with(|| BlockDefinition { block_id: cur_block_id.clone(), ops: Default::default() });

                    block.ops.push(op.clone());
                    continue;
                };
            };

            let is_void = if let &ElementOp::ElementVoid(..) = op { true } else { false };

            match op {
                &ElementOp::ElementOpen(ref element_tag, ref element_key, ref attrs, ref events) |
                &ElementOp::ElementVoid(ref element_tag, ref element_key, ref attrs, ref events) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let element_key = element_key.as_ref().map_or("null", |s| s);

                    let attrs = attrs.as_ref().map(|attrs| attrs.iter());
                    let events = events.as_ref().map(|events| events.iter());

                    let element_key = format!("{}", scope.0.key_prefix(element_key));
                    self.stream_writer.write_op_element(w, op, doc, &scope, &element_key, element_tag, is_void, attrs, events)?;
                }
                &ElementOp::ElementClose(ref element_tag) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    self.stream_writer.write_op_element_close(w, op, doc, &scope, element_tag)?;
                }
                &ElementOp::WriteValue(ref expr, ref value_key) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let value_key = value_key.as_ref().map_or("null", |s| s);
                    self.stream_writer.write_op_element_value(w, op, doc, &scope, expr, value_key)?;
                }
                &ElementOp::InstanceComponent(ref component_ty,
                                            ref component_key,
                                            ref props,
                                            ref lens) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let comp = doc.comp_map.get(component_ty.as_str());
                    if let Some(ref comp) = comp {
                        let props = props.as_ref().map(|s| s.clone());
                        let lens = lens.as_ref().map(|s| s.clone());

                        let component_key = component_key.as_ref().map_or("null", |s| s);
                        let component_id = format!("{}_1", component_key);

                        let props_iter = props.as_ref().map(|s| s.iter());

                        // OpenS
                        self.stream_writer.write_op_element_instance_component_open(w, op, doc, &scope, &comp, component_key, component_id.as_str(), props_iter.as_ref().map(Clone::clone), lens.as_ref())?;

                        if output_component_contents {
                            self.invoke_component_with_props(w, doc, &scope, comp, props_iter.as_ref().map(Clone::clone), true)?;
                            // if let Some(ref ops) = comp.ops {
                            //     self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
                            // };
                        };

                        // Close
                        self.stream_writer.write_op_element_instance_component_close(w, op, doc, &scope, &comp, component_key, component_id.as_str())?;
                    }
                }

                &ElementOp::StartBlock(ref block_id) => {
                    if output_component_contents {
                        // Collect blocks to render
                        self.cur_block_id = Some(block_id.to_owned());
                    } else {
                        // Write function header
                        let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        let loopidx_ref = Symbol::loop_idx("foridx", block_id);
                        scope.0 = with_key_expr_prefix(&scope.0, ExprValue::SymbolReference(loopidx_ref));
                        self.stream_writer.write_op_element_start_block(w, op, doc, &scope, block_id)?;

                        let scope_id = scope.0.key_prefix(block_id);
                        self.scopes.insert(scope_id, scope.clone());
                    };
                }

                &ElementOp::EndBlock(ref block_id) => {
                    if output_component_contents {
                        // Finish current block
                        self.cur_block_id = None;
                    } else {
                        self.scopes.pop_back();
                        let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        self.stream_writer.write_op_element_end_block(w, op, doc, &scope, block_id)?;
                    };
                }

                &ElementOp::MapCollection(ref block_id, ref ele, ref coll_expr) => {
                    if output_component_contents {
                        let scope = self.scopes.back().unwrap().1.clone();
                        // let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        let has_block = self.blocks.contains_key(block_id);
                        if has_block {
                            let ele = ele.as_ref().map(|e| e.as_str());

                            let coll_expr = reduce_expr(coll_expr, doc, &scope);

                            if let Some(ExprValue::LiteralArray(Some(ref items))) = coll_expr {
                                for item_expr in items {
                                    self.write_loop_item(w, doc, item_expr, &scope, ele, None, block_id, output_component_contents)?;
                                };
                            };
                        };
                    } else {
                        let forvar_default = &format!("__forvar_{}", block_id);
                        let scope_id = format!("{}_map", block_id);

                        // Map to block
                        self.stream_writer.write_op_element_map_collection_to_block(w, op, doc, &scope, coll_expr, block_id)?;
                    };
                }
            }
        }

        Ok(())
    }
}<commit_msg>Cleanup dead code<commit_after>
use std::io;
use std::clone::Clone;
use std::slice::Iter;

use linked_hash_map::LinkedHashMap;

use parser::ast::*;
use parser::util::*;
use processing::structs::*;
use output::client_ops_stream_writer::*;
use output::client_misc::*;
use output::scope::*;

#[derive(Debug)]
pub struct BlockDefinition {
    pub block_id: String,
    pub ops: Vec<ElementOp>
}
pub type BlockMap = LinkedHashMap<String, BlockDefinition>;

pub struct ElementOpsWriter<'input: 'scope, 'scope> {
    pub doc: &'input DocumentState<'input>,
    pub stream_writer: &'scope mut ElementOpsStreamWriter,
    pub scopes: LinkedHashMap<String, ElementOpScope>,
    pub blocks: BlockMap,
    pub cur_block_id: Option<String>
}

impl<'input: 'scope, 'scope> ElementOpsWriter<'input, 'scope> {

    pub fn with_doc(doc: &'input DocumentState<'input>, stream_writer: &'scope mut ElementOpsStreamWriter) -> Self {
        ElementOpsWriter {
            doc: doc,
            stream_writer: stream_writer,
            scopes: Default::default(),
            blocks: Default::default(),
            cur_block_id: None
        }
    }

    #[inline]
    fn write_loop_item(&mut self, w: &mut io::Write, doc: &'input DocumentState, item_expr: &ExprValue, scope: &ElementOpScope, ele: Option<&str>, element_ty: Option<&VarType>, block_id: &str, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(ele_key) = ele {
            scope.add_loop_var_with_value(ele_key, item_expr);

            // loop_scope.1.symbol_map.insert(ele_key.to_owned(), (Some(SymbolReferenceType::LoopVarReference(ele_key.to_owned())), None));
            // loop_scope = loop_scope
            //     .with_var(ele_key,
            //         SymbolReferenceType::LoopVarReference(ele_key.to_owned()),
            //         element_ty.as_ref().map(Clone::clone),
            //         Some(SymbolValueType::ConstantValue(item_expr.clone()))
            //     );
        };

        let block_ops = self.blocks.get(block_id)
            .map(|block| block.ops.clone());

        if let Some(ref block_ops) = block_ops {
            // Push scope
            let scope_id = format!("{}_{}", scope.0.key_prefix(block_id), 1);
            self.scopes.insert(scope_id, scope.clone());

            // Output ops
            self.write_ops_content(w, block_ops.iter(), doc, &scope, output_component_contents)?;

            // Pop scope
            self.scopes.pop_back();
        };
        Ok(())
    }

    #[inline]
    fn invoke_component_with_props(&mut self, w: &mut io::Write, doc: &'input DocumentState, scope: &ElementOpScope, comp: &Component, props: Option<Iter<Prop>>, output_component_contents: bool) -> Result {
        let mut scope = scope.clone();

        if let Some(props) = props {
            for &(ref key, ref expr) in props {
                if let Some(ref expr) = expr.as_ref().and_then(|expr| reduce_expr(&expr, doc, &scope)) {
                    scope.add_prop_with_value(key, &expr);
                };
            }
        };

        // TODO: Restore props from Component object

        let scope_key = allocate_element_key();
        let scope_id = scope.0.key_prefix(&scope_key);
        self.scopes.insert(scope_id, scope.clone());

        if let Some(ref ops) = comp.ops {
            self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
        };
        Ok(())
    }

    #[inline]
    #[allow(unused_variables)]
    pub fn write_ops_content<'op>(&mut self, w: &mut io::Write, ops: Iter<'op, ElementOp>, doc: &'input DocumentState, scope: &ElementOpScope, output_component_contents: bool) -> Result {
        for op in ops {
            if output_component_contents {
                if let &ElementOp::EndBlock(..) = op {
                    self.cur_block_id = None;
                    continue;
                };

                if let Some(ref cur_block_id) = self.cur_block_id {
                    let block = self.blocks.entry(cur_block_id.to_owned())
                        .or_insert_with(|| BlockDefinition { block_id: cur_block_id.clone(), ops: Default::default() });

                    block.ops.push(op.clone());
                    continue;
                };
            };

            let is_void = if let &ElementOp::ElementVoid(..) = op { true } else { false };

            match op {
                &ElementOp::ElementOpen(ref element_tag, ref element_key, ref attrs, ref events) |
                &ElementOp::ElementVoid(ref element_tag, ref element_key, ref attrs, ref events) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let element_key = element_key.as_ref().map_or("null", |s| s);

                    let attrs = attrs.as_ref().map(|attrs| attrs.iter());
                    let events = events.as_ref().map(|events| events.iter());

                    let element_key = format!("{}", scope.0.key_prefix(element_key));
                    self.stream_writer.write_op_element(w, op, doc, &scope, &element_key, element_tag, is_void, attrs, events)?;
                }
                &ElementOp::ElementClose(ref element_tag) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    self.stream_writer.write_op_element_close(w, op, doc, &scope, element_tag)?;
                }
                &ElementOp::WriteValue(ref expr, ref value_key) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let value_key = value_key.as_ref().map_or("null", |s| s);
                    self.stream_writer.write_op_element_value(w, op, doc, &scope, expr, value_key)?;
                }
                &ElementOp::InstanceComponent(ref component_ty,
                                            ref component_key,
                                            ref props,
                                            ref lens) => {
                    let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                    let comp = doc.comp_map.get(component_ty.as_str());
                    if let Some(ref comp) = comp {
                        let props = props.as_ref().map(|s| s.clone());
                        let lens = lens.as_ref().map(|s| s.clone());

                        let component_key = component_key.as_ref().map_or("null", |s| s);
                        let component_id = format!("{}_1", component_key);

                        let props_iter = props.as_ref().map(|s| s.iter());

                        // OpenS
                        self.stream_writer.write_op_element_instance_component_open(w, op, doc, &scope, &comp, component_key, component_id.as_str(), props_iter.as_ref().map(Clone::clone), lens.as_ref())?;

                        if output_component_contents {
                            self.invoke_component_with_props(w, doc, &scope, comp, props_iter.as_ref().map(Clone::clone), true)?;
                            // if let Some(ref ops) = comp.ops {
                            //     self.write_ops_content(w, ops.iter(), doc, &scope, output_component_contents)?;
                            // };
                        };

                        // Close
                        self.stream_writer.write_op_element_instance_component_close(w, op, doc, &scope, &comp, component_key, component_id.as_str())?;
                    }
                }

                &ElementOp::StartBlock(ref block_id) => {
                    if output_component_contents {
                        // Collect blocks to render
                        self.cur_block_id = Some(block_id.to_owned());
                    } else {
                        // Write function header
                        let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        let loopidx_ref = Symbol::loop_idx("foridx", block_id);
                        scope.0 = with_key_expr_prefix(&scope.0, ExprValue::SymbolReference(loopidx_ref));
                        self.stream_writer.write_op_element_start_block(w, op, doc, &scope, block_id)?;

                        let scope_id = scope.0.key_prefix(block_id);
                        self.scopes.insert(scope_id, scope.clone());
                    };
                }

                &ElementOp::EndBlock(ref block_id) => {
                    if output_component_contents {
                        // Finish current block
                        self.cur_block_id = None;
                    } else {
                        self.scopes.pop_back();
                        let scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        self.stream_writer.write_op_element_end_block(w, op, doc, &scope, block_id)?;
                    };
                }

                &ElementOp::MapCollection(ref block_id, ref ele, ref coll_expr) => {
                    if output_component_contents {
                        let scope = self.scopes.back().unwrap().1.clone();
                        // let mut scope = self.scopes.back().map_or(scope.clone(), |s| s.1.clone());

                        let has_block = self.blocks.contains_key(block_id);
                        if has_block {
                            let ele = ele.as_ref().map(|e| e.as_str());

                            let coll_expr = reduce_expr(coll_expr, doc, &scope);

                            if let Some(ExprValue::LiteralArray(Some(ref items))) = coll_expr {
                                for item_expr in items {
                                    self.write_loop_item(w, doc, item_expr, &scope, ele, None, block_id, output_component_contents)?;
                                };
                            };
                        };
                    } else {
                        let forvar_default = &format!("__forvar_{}", block_id);
                        let scope_id = format!("{}_map", block_id);

                        // Map to block
                        self.stream_writer.write_op_element_map_collection_to_block(w, op, doc, &scope, coll_expr, block_id)?;
                    };
                }
            }
        }

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


<commit_before>use ast::Script;
use compile::ExecutableDevEnv;
use run::{ Execution, ExecutionEvent, Error as RunError, StartStopError };

use std::collections::HashMap;
use std::path::{ Path as FilePath, PathBuf as FilePathBuf };

use foxbox_taxonomy::api::ResultMap;
use foxbox_taxonomy::parse::*;
use foxbox_taxonomy::util::{ Id };

use rusqlite;
use transformable_channels::mpsc::{ channel, ExtSender, TransformableSender };

/// A ScriptManager error.
#[derive(Serialize, Debug)]
pub enum Error {
    /// The script you requested (by ID) does not exist.
    NoSuchScriptError,

    /// There was an error executing some SQL.
    SQLError(String),

    /// There was an error attempting to run a script. (See `run.rs`.)
    RunError(RunError),

    /// There was an error parsing the script's JSON.
    ParseError(String),
}

/// A type for ensuring type-safety (Id<ScriptId>).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ScriptId;

/// ScriptManager stores a persistent database of scripts and executes them.
/// Each script can be individually enabled or disabled.
/// When a script is enabled, it is always running (unless an error occured during launch).
/// Script sources are stored as JSON strings in a SQLite database.
pub struct ScriptManager<Env, T> where Env: ExecutableDevEnv + Clone + 'static {
    env: Env,

    /// The path to the SQLite file to store, e.g. "./database.sqlite"
    path: FilePathBuf,

    /// A map to track currently-executing scripts.
    runners: HashMap<Id<ScriptId>, Execution<Env>>,

    /// The tx end of the channel passed to ScriptManager::new()
    tx: Box<T>,
}

impl<Env, T> ScriptManager<Env, T>
    where Env: ExecutableDevEnv + Clone + 'static,
          T: ExtSender<(Id<ScriptId>, ExecutionEvent)> + TransformableSender<(Id<ScriptId>, ExecutionEvent)> {

    /// Create a ScriptManager using a SQLite database file with the given path, i.e. filename.
    /// If the database file does not exist, it will be created.
    ///
    /// NOTE: You MUST consume the contents of `tx` to prevent memory leaks.
    ///
    /// The database stores the raw script source, but only after the source has been parsed
    /// to ensure validity.
    pub fn new(env: Env, path: &FilePath, tx: Box<T>) -> Result<Self, Error> {

        let connection = try!(rusqlite::Connection::open(&path));
        try!(connection.execute("CREATE TABLE IF NOT EXISTS scripts (
            id          TEXT NOT NULL PRIMARY KEY,
            source      TEXT NOT NULL,
            is_enabled  BOOL NOT NULL DEFAULT 1
        )", &[]));

        Ok(ScriptManager {
            path: path.to_owned(),
            env: env,
            runners: HashMap::new(),
            tx: tx
        })
    }

    /// Load and launch all existing scripts from the database.
    pub fn load(&mut self) -> Result<ResultMap<Id<ScriptId>, (), Error>, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut result_map = HashMap::new();
        let mut stmt = try!(connection.prepare("SELECT id, source, is_enabled FROM scripts"));
        let rows = try!(stmt.query(&[]));

        for result_row in rows {
            let row = try!(result_row);
            let id_string: String = try!(row.get_checked(0));
            let id: Id<ScriptId> = Id::new(&id_string);
            let source: String = try!(row.get_checked(1));
            let is_enabled: bool = try!(row.get_checked(2));

            if is_enabled {
                result_map.insert(
                    id.clone(),
                    self.start_script(&id, &source).map(|_| ()));
            }
        }
        Ok(result_map)
    }

    /// Attempt to add a new script. The script will be executed and persisted to disk.
    /// The ID is chosen by the consumer and must be unique.
    pub fn put(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        try!(self.start_script(&id, &source));

        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("INSERT OR REPLACE INTO scripts (id, source, is_enabled)
                VALUES ($1, $2, $3)", &[&id.to_string(), source, &1])
            .map(|_| ()).map_err(From::from)
    }

    /// Enable or disable a script, starting or stopping the script if necessary.
    pub fn set_enabled(&mut self, id: &Id<ScriptId>, enabled: bool) -> Result<(), Error> {
        let source = try!(self.get_source(id));
        let is_running = self.runners.contains_key(&id);
        match (enabled, is_running) {
            (false, true) => {
                if let Some(mut runner) = self.runners.remove(&id) {
                    let (tx, rx) = channel();
                    runner.stop(move |result| {
                        let _ = tx.send(result);
                    });
                    if let Err(_) = rx.recv() {
                        return Err(Error::RunError(RunError::StartStopError(StartStopError::ThreadError)));
                    }
                }

                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 0 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            (true, false) => {
                try!(self.start_script(id, &source));
                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 1 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            _ => {
                // Nothing to do.
            }
        }

        Ok(())
    }

    /// Remove a script entirely, stopping it if necessary.
    /// If the script cannot be stopped (due to an error), it will not be removed.
    pub fn remove(&mut self, id: &Id<ScriptId>) -> Result<(), Error> {
        try!(self.set_enabled(id, false));
        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("DELETE FROM scripts WHERE id = $1", &[&id.to_string()])
            .map(|_| ())
            .map_err(From::from)
    }

    /// Remove all scripts, stopping any running scripts.
    /// (If any scripts fail to stop, we store and return those errors in a Vec<Error> so that
    /// we ensure that the database always gets wiped.)
    pub fn remove_all(&mut self) -> Result<Vec<Error>, Error> {
        // Get a copy of the keys (so that we don't borow `self` twice).
        let keys: Vec<Id<ScriptId>> = self.runners.keys().cloned().collect();
        let mut errors = Vec::new();
        // Remove any running scripts, storing errors for later return so that we
        // for sure end up nuking the database at the end.
        for id in keys {
            if let Err(err) = self.remove(&id) {
                errors.push(err);
            }
        }
        // Nuke the scripts database.
        let connection = try!(rusqlite::Connection::open(&self.path));
        try!(connection.execute("DELETE FROM scripts", &[])
                .map(|_| ()));
        Ok(errors)
    }

    /// Get the number of currently-running scripts.
    pub fn get_running_count(&self) -> usize {
        self.runners.len()
    }

    /// Get the source for a script with the given id.
    fn get_source(&self, id: &Id<ScriptId>) -> Result<String, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut stmt = try!(connection.prepare("SELECT source FROM scripts WHERE id = $1"));
        let mut rows = try!(stmt.query(&[&id.to_string()]));
        let first_row = try!(try!(rows.nth(0).ok_or(Error::NoSuchScriptError)));
        Ok(try!(first_row.get_checked(0)))
    }

    /// Execute a script. Returns an error if the script is already running,
    /// or it won't parse, or it won't compile.
    fn start_script(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        if self.runners.contains_key(id) {
            return Err(Error::RunError(RunError::StartStopError(StartStopError::AlreadyRunning)));
        }
        let mut runner = Execution::<Env>::new();
        let tx_id = id.clone();
        let tx = self.tx.map(move |event| {
            (tx_id.clone(), event)
        });
        let parsed_source = try!(Script::from_str(source));
        try!(runner.start(self.env.clone(), parsed_source, tx));
        self.runners.insert(id.clone(), runner);
        Ok(())
    }
}

impl From<rusqlite::Error> for Error {
    fn from(err: rusqlite::Error) -> Error {
        Error::SQLError(format!("{:?}", err))
    }
}

impl From<RunError> for Error {
    fn from(err: RunError) -> Error {
        Error::RunError(err)
    }
}

impl From<ParseError> for Error {
    fn from(err: ParseError) -> Error {
        Error::ParseError(format!("{:?}", err))
    }
}
<commit_msg>Add is_enabled() method for ScriptManager.<commit_after>use ast::Script;
use compile::ExecutableDevEnv;
use run::{ Execution, ExecutionEvent, Error as RunError, StartStopError };

use std::collections::HashMap;
use std::path::{ Path as FilePath, PathBuf as FilePathBuf };

use foxbox_taxonomy::api::ResultMap;
use foxbox_taxonomy::parse::*;
use foxbox_taxonomy::util::{ Id };

use rusqlite;
use transformable_channels::mpsc::{ channel, ExtSender, TransformableSender };

/// A ScriptManager error.
#[derive(Serialize, Debug)]
pub enum Error {
    /// The script you requested (by ID) does not exist.
    NoSuchScriptError,

    /// There was an error executing some SQL.
    SQLError(String),

    /// There was an error attempting to run a script. (See `run.rs`.)
    RunError(RunError),

    /// There was an error parsing the script's JSON.
    ParseError(String),
}

/// A type for ensuring type-safety (Id<ScriptId>).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ScriptId;

/// ScriptManager stores a persistent database of scripts and executes them.
/// Each script can be individually enabled or disabled.
/// When a script is enabled, it is always running (unless an error occured during launch).
/// Script sources are stored as JSON strings in a SQLite database.
pub struct ScriptManager<Env, T> where Env: ExecutableDevEnv + Clone + 'static {
    env: Env,

    /// The path to the SQLite file to store, e.g. "./database.sqlite"
    path: FilePathBuf,

    /// A map to track currently-executing scripts.
    runners: HashMap<Id<ScriptId>, Execution<Env>>,

    /// The tx end of the channel passed to ScriptManager::new()
    tx: Box<T>,
}

impl<Env, T> ScriptManager<Env, T>
    where Env: ExecutableDevEnv + Clone + 'static,
          T: ExtSender<(Id<ScriptId>, ExecutionEvent)> + TransformableSender<(Id<ScriptId>, ExecutionEvent)> {

    /// Create a ScriptManager using a SQLite database file with the given path, i.e. filename.
    /// If the database file does not exist, it will be created.
    ///
    /// NOTE: You MUST consume the contents of `tx` to prevent memory leaks.
    ///
    /// The database stores the raw script source, but only after the source has been parsed
    /// to ensure validity.
    pub fn new(env: Env, path: &FilePath, tx: Box<T>) -> Result<Self, Error> {

        let connection = try!(rusqlite::Connection::open(&path));
        try!(connection.execute("CREATE TABLE IF NOT EXISTS scripts (
            id          TEXT NOT NULL PRIMARY KEY,
            source      TEXT NOT NULL,
            is_enabled  BOOL NOT NULL DEFAULT 1
        )", &[]));

        Ok(ScriptManager {
            path: path.to_owned(),
            env: env,
            runners: HashMap::new(),
            tx: tx
        })
    }

    /// Load and launch all existing scripts from the database.
    pub fn load(&mut self) -> Result<ResultMap<Id<ScriptId>, (), Error>, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut result_map = HashMap::new();
        let mut stmt = try!(connection.prepare("SELECT id, source, is_enabled FROM scripts"));
        let rows = try!(stmt.query(&[]));

        for result_row in rows {
            let row = try!(result_row);
            let id_string: String = try!(row.get_checked(0));
            let id: Id<ScriptId> = Id::new(&id_string);
            let source: String = try!(row.get_checked(1));
            let is_enabled: bool = try!(row.get_checked(2));

            if is_enabled {
                result_map.insert(
                    id.clone(),
                    self.start_script(&id, &source).map(|_| ()));
            }
        }
        Ok(result_map)
    }

    /// Attempt to add a new script. The script will be executed and persisted to disk.
    /// The ID is chosen by the consumer and must be unique.
    pub fn put(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        try!(self.start_script(&id, &source));

        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("INSERT OR REPLACE INTO scripts (id, source, is_enabled)
                VALUES ($1, $2, $3)", &[&id.to_string(), source, &1])
            .map(|_| ()).map_err(From::from)
    }

    /// Enable or disable a script, starting or stopping the script if necessary.
    pub fn set_enabled(&mut self, id: &Id<ScriptId>, enabled: bool) -> Result<(), Error> {
        let source = try!(self.get_source(id));
        let is_running = self.runners.contains_key(&id);
        match (enabled, is_running) {
            (false, true) => {
                if let Some(mut runner) = self.runners.remove(&id) {
                    let (tx, rx) = channel();
                    runner.stop(move |result| {
                        let _ = tx.send(result);
                    });
                    if let Err(_) = rx.recv() {
                        return Err(Error::RunError(RunError::StartStopError(StartStopError::ThreadError)));
                    }
                }

                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 0 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            (true, false) => {
                try!(self.start_script(id, &source));
                let connection = try!(rusqlite::Connection::open(&self.path));
                try!(connection.execute("UPDATE scripts SET is_enabled = 1 WHERE id = $1",
                                        &[&id.to_string()]));
            },
            _ => {
                // Nothing to do.
            }
        }

        Ok(())
    }

    /// Remove a script entirely, stopping it if necessary.
    /// If the script cannot be stopped (due to an error), it will not be removed.
    pub fn remove(&mut self, id: &Id<ScriptId>) -> Result<(), Error> {
        try!(self.set_enabled(id, false));
        let connection = try!(rusqlite::Connection::open(&self.path));
        connection.execute("DELETE FROM scripts WHERE id = $1", &[&id.to_string()])
            .map(|_| ())
            .map_err(From::from)
    }

    /// Remove all scripts, stopping any running scripts.
    /// (If any scripts fail to stop, we store and return those errors in a Vec<Error> so that
    /// we ensure that the database always gets wiped.)
    pub fn remove_all(&mut self) -> Result<Vec<Error>, Error> {
        // Get a copy of the keys (so that we don't borow `self` twice).
        let keys: Vec<Id<ScriptId>> = self.runners.keys().cloned().collect();
        let mut errors = Vec::new();
        // Remove any running scripts, storing errors for later return so that we
        // for sure end up nuking the database at the end.
        for id in keys {
            if let Err(err) = self.remove(&id) {
                errors.push(err);
            }
        }
        // Nuke the scripts database.
        let connection = try!(rusqlite::Connection::open(&self.path));
        try!(connection.execute("DELETE FROM scripts", &[])
                .map(|_| ()));
        Ok(errors)
    }

    /// Get the number of currently-running scripts.
    pub fn get_running_count(&self) -> usize {
        self.runners.len()
    }

    /// Get the source for a script with the given id.
    fn get_source(&self, id: &Id<ScriptId>) -> Result<String, Error> {
        let connection = try!(rusqlite::Connection::open(&self.path));
        let mut stmt = try!(connection.prepare("SELECT source FROM scripts WHERE id = $1"));
        let mut rows = try!(stmt.query(&[&id.to_string()]));
        let first_row = try!(try!(rows.nth(0).ok_or(Error::NoSuchScriptError)));
        Ok(try!(first_row.get_checked(0)))
    }

    /// Return true if the script is enabled.
    pub fn is_enabled(&self, id: &Id<ScriptId>) -> bool {
        self.runners.contains_key(id)
    }

    /// Execute a script. Returns an error if the script is already running,
    /// or it won't parse, or it won't compile.
    fn start_script(&mut self, id: &Id<ScriptId>, source: &String) -> Result<(), Error> {
        if self.runners.contains_key(id) {
            return Err(Error::RunError(RunError::StartStopError(StartStopError::AlreadyRunning)));
        }
        let mut runner = Execution::<Env>::new();
        let tx_id = id.clone();
        let tx = self.tx.map(move |event| {
            (tx_id.clone(), event)
        });
        let parsed_source = try!(Script::from_str(source));
        try!(runner.start(self.env.clone(), parsed_source, tx));
        self.runners.insert(id.clone(), runner);
        Ok(())
    }
}

impl From<rusqlite::Error> for Error {
    fn from(err: rusqlite::Error) -> Error {
        Error::SQLError(format!("{:?}", err))
    }
}

impl From<RunError> for Error {
    fn from(err: RunError) -> Error {
        Error::RunError(err)
    }
}

impl From<ParseError> for Error {
    fn from(err: ParseError) -> Error {
        Error::ParseError(format!("{:?}", err))
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Common definitions for SMTP
//!
//! Needs to be organized later

use std::strbuf::StrBuf;

pub static SP: &'static str = " ";
pub static CRLF: &'static str = "\r\n";

/// Adds quotes to emails if needed
pub fn quote_email_address(addr: &str) -> ~str {
    match (addr.slice_to(1), addr.slice_from(addr.len()-1)) {
        ("<", ">") => addr.to_owned(),
        _          => format!("<{:s}>", addr)
    }
}

/// Removes quotes from emails if needed
pub fn unquote_email_address(addr: &str) -> ~str {
    match (addr.slice_to(1), addr.slice_from(addr.len() - 1)) {
        ("<", ">") => addr.slice(1, addr.len() - 1).to_owned(),
        _          => addr.to_owned()
    }
}

/// Returns the first word of a string, or the string if it contains no space
pub fn get_first_word<T: Str>(string: T) -> StrBuf {
    StrBuf::from_str(string.into_owned().split_str(CRLF).next().unwrap().splitn(' ', 1).next().unwrap())
}

#[cfg(test)]
mod test {
    #[test]
    fn test_quote_email_address() {
        assert!(super::quote_email_address("plop") == "<plop>".to_owned());
        assert!(super::quote_email_address("<plop>") == "<plop>".to_owned());
    }

    #[test]
    fn test_unquote_email_address() {
        assert!(super::unquote_email_address("<plop>") == "plop".to_owned());
        assert!(super::unquote_email_address("plop") == "plop".to_owned());
        assert!(super::unquote_email_address("<plop") == "<plop".to_owned());
    }

    #[test]
    fn test_get_first_word() {
        assert!(super::get_first_word("first word") == StrBuf::from_str("first"));
        assert!(super::get_first_word("first word\r\ntest") == StrBuf::from_str("first"));
        assert!(super::get_first_word("first") == StrBuf::from_str("first"));
    }
}
<commit_msg>~string -> string.to_owned()<commit_after>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Common definitions for SMTP
//!
//! Needs to be organized later

use std::strbuf::StrBuf;

pub static SP: &'static str = " ";
pub static CRLF: &'static str = "\r\n";

/// Adds quotes to emails if needed
pub fn quote_email_address<T: Str>(address: T) -> StrBuf {
    match (address.as_slice().slice_to(1), address.as_slice().slice_from(address.as_slice().len()-1)) {
        ("<", ">") => address.into_strbuf(),
        _          => StrBuf::from_str(format!("<{:s}>", address))
    }
}

/// Removes quotes from emails if needed
pub fn unquote_email_address<T: Str>(address: T) -> StrBuf {
    match (address.as_slice().slice_to(1), address.as_slice().slice_from(address.as_slice().len() - 1)) {
        ("<", ">") => address.as_slice().slice(1, address.len() - 1).into_strbuf(),
        _          => address.into_strbuf()
    }
}

/// Returns the first word of a string, or the string if it contains no space
pub fn get_first_word<T: Str>(string: T) -> StrBuf {
    StrBuf::from_str(string.into_owned().split_str(CRLF).next().unwrap().splitn(' ', 1).next().unwrap())
}

#[cfg(test)]
mod test {
    #[test]
    fn test_quote_email_address() {
        assert!(super::quote_email_address("plop") == "<plop>");
        assert!(super::quote_email_address("<plop>") == "<plop>");
    }

    #[test]
    fn test_unquote_email_address() {
        assert!(super::unquote_email_address("<plop>") == "plop");
        assert!(super::unquote_email_address("plop") == "plop");
        assert!(super::unquote_email_address("<plop") == "<plop");
    }

    #[test]
    fn test_get_first_word() {
        assert!(super::get_first_word("first word") == StrBuf::from_str("first"));
        assert!(super::get_first_word("first word\r\ntest") == StrBuf::from_str("first"));
        assert!(super::get_first_word("first") == StrBuf::from_str("first"));
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

use std::slice::SliceConcatExt;
use std::convert::AsRef;
use std::fmt::Debug;
use std::num::{Zero, One};
use std::ops::{Add, Sub};

use ::crypto::Hash;
use ::messages::{TxMessage, Precommit, Propose};

mod leveldb;
mod memorydb;
mod map_table;
mod list_table;
mod fields;
mod db;

pub use self::db::{Database, Fork, Patch, Change};
pub use self::memorydb::MemoryDB;
pub use self::leveldb::LevelDB;
pub use self::map_table::MapTable;
pub use self::list_table::ListTable;
pub use self::fields::{StorageValue};

pub struct Storage<T: Database> {
    db: T,
}

pub type Error = Box<Debug>;

impl<T> Storage<T>
    where T: Database
{
    pub fn new(backend: T) -> Self {
        Storage { db: backend }
    }

    pub fn transactions<'a>(&'a mut self) -> MapTable<'a, T, Hash, TxMessage> {
        self.db.map(vec![00])
    }

    pub fn proposes<'a>(&'a mut self) -> MapTable<'a, T, Hash, Propose> {
        self.db.map(vec![01])
    }

    pub fn heights<'a>(&'a mut self) -> ListTable<MapTable<'a, T, [u8], Vec<u8>>, u64, Hash> {
        self.db.list(vec![02])
    }

    pub fn last_hash(&mut self) -> Result<Option<Hash>, Error> {
        self.heights().last()
    }

    pub fn last_propose(&mut self) -> Result<Option<Propose>, Error> {
        Ok(match self.last_hash()? {
            Some(hash) => Some(self.proposes().get(&hash)?.unwrap()),
            None => None,
        })

    }

    pub fn precommits<'a>(&'a mut self,
                          hash: &'a Hash)
                          -> ListTable<MapTable<'a, T, [u8], Vec<u8>>, u32, Precommit> {
        self.db.list([&[03], hash.as_ref()].concat())
    }

    pub fn fork<'a>(&'a self) -> Storage<Fork<'a, T>> {
        Storage { db: self.db.fork() }
    }

    pub fn merge(&mut self, patch: Patch) -> Result<(), Error> {
        self.db.merge(patch)
    }
}

impl<'a, T> Storage<Fork<'a, T>>
    where T: Database
{
    pub fn patch(self) -> Patch {
        self.db.patch()
    }
}

pub trait Map<K: ?Sized, V> {
    fn get(&self, key: &K) -> Result<Option<V>, Error>;
    fn put(&mut self, key: &K, value: V) -> Result<(), Error>;
    fn delete(&mut self, key: &K) -> Result<(), Error>;
}

pub trait MapExt: Map<[u8], Vec<u8>> + Sized {
    fn list<'a, K, V>(&'a mut self,
                      prefix: Vec<u8>)
                      -> ListTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Zero + One + Add<Output = K> + Sub<Output = K> + PartialEq + Copy + StorageValue,
              ::std::ops::Range<K>: ::std::iter::Iterator<Item = K>,
              V: StorageValue;

    fn map<'a, K: ?Sized, V>(&'a mut self, prefix: Vec<u8>) -> MapTable<'a, Self, K, V>;
}

impl<T> MapExt for T
    where T: Map<[u8], Vec<u8>> + Sized
{
    fn list<'a, K, V>(&'a mut self,
                      prefix: Vec<u8>)
                      -> ListTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Zero + One + Add<Output = K> + Sub<Output = K> + PartialEq + Copy + StorageValue,
              ::std::ops::Range<K>: ::std::iter::Iterator<Item = K>,
              V: StorageValue
    {
        ListTable::new(self.map(prefix))
    }

    fn map<'a, K: ?Sized, V>(&'a mut self, prefix: Vec<u8>) -> MapTable<'a, Self, K, V> {
        MapTable::new(prefix, self)
    }
}
<commit_msg>Add TODO<commit_after>#[cfg(test)]
mod tests;

use std::slice::SliceConcatExt;
use std::convert::AsRef;
use std::fmt::Debug;
use std::num::{Zero, One};
use std::ops::{Add, Sub};

use ::crypto::Hash;
use ::messages::{TxMessage, Precommit, Propose};

mod leveldb;
mod memorydb;
mod map_table;
mod list_table;
mod fields;
mod db;

pub use self::db::{Database, Fork, Patch, Change};
pub use self::memorydb::MemoryDB;
pub use self::leveldb::LevelDB;
pub use self::map_table::MapTable;
pub use self::list_table::ListTable;
pub use self::fields::{StorageValue};

pub struct Storage<T: Database> {
    db: T,
}

pub type Error = Box<Debug>;

impl<T> Storage<T>
    where T: Database
{
    pub fn new(backend: T) -> Self {
        Storage { db: backend }
    }

    pub fn transactions<'a>(&'a mut self) -> MapTable<'a, T, Hash, TxMessage> {
        self.db.map(vec![00])
    }

    pub fn proposes<'a>(&'a mut self) -> MapTable<'a, T, Hash, Propose> {
        self.db.map(vec![01])
    }

    pub fn heights<'a>(&'a mut self) -> ListTable<MapTable<'a, T, [u8], Vec<u8>>, u64, Hash> {
        self.db.list(vec![02])
    }

    pub fn last_hash(&mut self) -> Result<Option<Hash>, Error> {
        self.heights().last()
    }

    pub fn last_propose(&mut self) -> Result<Option<Propose>, Error> {
        Ok(match self.last_hash()? {
            Some(hash) => Some(self.proposes().get(&hash)?.unwrap()),
            None => None,
        })

    }

    pub fn precommits<'a>(&'a mut self,
                          hash: &'a Hash)
                          -> ListTable<MapTable<'a, T, [u8], Vec<u8>>, u32, Precommit> {
        self.db.list([&[03], hash.as_ref()].concat())
    }

    pub fn fork<'a>(&'a self) -> Storage<Fork<'a, T>> {
        Storage { db: self.db.fork() }
    }

    pub fn merge(&mut self, patch: Patch) -> Result<(), Error> {
        self.db.merge(patch)
    }
}

impl<'a, T> Storage<Fork<'a, T>>
    where T: Database
{
    pub fn patch(self) -> Patch {
        self.db.patch()
    }
}

pub trait Map<K: ?Sized, V> {
    fn get(&self, key: &K) -> Result<Option<V>, Error>;
    fn put(&mut self, key: &K, value: V) -> Result<(), Error>;
    fn delete(&mut self, key: &K) -> Result<(), Error>;
}

pub trait MapExt: Map<[u8], Vec<u8>> + Sized {
    fn list<'a, K, V>(&'a mut self,
                      prefix: Vec<u8>)
                      -> ListTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Zero + One + Add<Output = K> + Sub<Output = K> + PartialEq + Copy + StorageValue,
              ::std::ops::Range<K>: ::std::iter::Iterator<Item = K>,
              V: StorageValue;

    fn map<'a, K: ?Sized, V>(&'a mut self, prefix: Vec<u8>) -> MapTable<'a, Self, K, V>;
}

//TODO MapExt looks too complex. Find more simple way.
impl<T> MapExt for T
    where T: Map<[u8], Vec<u8>> + Sized
{
    fn list<'a, K, V>(&'a mut self,
                      prefix: Vec<u8>)
                      -> ListTable<MapTable<'a, Self, [u8], Vec<u8>>, K, V>
        where K: Zero + One + Add<Output = K> + Sub<Output = K> + PartialEq + Copy + StorageValue,
              ::std::ops::Range<K>: ::std::iter::Iterator<Item = K>,
              V: StorageValue
    {
        ListTable::new(self.map(prefix))
    }

    fn map<'a, K: ?Sized, V>(&'a mut self, prefix: Vec<u8>) -> MapTable<'a, Self, K, V> {
        MapTable::new(prefix, self)
    }
}
<|endoftext|>


<commit_before>//! The module containing a structure for BAPS3 protocol messages.
#![experimental]

use util::{slicify, unslicify};
use baps3_protocol;

/// A structure for BAPS3 protocol messages.
#[deriving(Clone)]
pub struct Message {
    /// The command word of the message.
    _word: String,

    /// The arguments of the message.
    _args: Vec<String>
}

impl Message {
    /// Creates a new Message.
    pub fn new<Sized? W: Str, Sized? A: Str+Sized>(word: &W, args: &[A])
      -> Message {
        Message { _word: word.as_slice().to_string(), _args: unslicify(args) }
    }

    /// Creates a new Message with no arguments.
    pub fn from_word<Sized? W: Str>(word: &W) -> Message {
        Message { _word: word.as_slice().to_string(), _args: vec![] }
    }

    /// Packs a Message into a BAPS3 protocol line.
    ///
    /// A `pack`ed message is ready for sending down the wire to a BAPS3
    /// client or server via `write_line`.
    ///
    /// # Example
    ///
    /// If none of the arguments have special characters, this is trivial:
    ///
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.pack().as_slice(), "foo bar baz");
    /// ```
    ///
    /// With special characters, we get escaping:
    ///
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["with space", "'single'", "\"double\""]);
    /// assert_eq!(m.pack().as_slice(),
    ///            "foo 'with space' ''\\''single'\\''' '\"double\"'");
    /// ```
    pub fn pack(&self) -> String {
        let vargs = self.args();
        baps3_protocol::pack(self.word(), vargs.as_slice())
    }

    /// Retrieves the command word of this Message.
    ///
    /// # Example
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.word(), "foo");
    /// ```
    pub fn word<'a>(&'a self) -> &'a str {
        self._word.as_slice()
    }

    /// Retrieves the command arguments of this Message.
    ///
    /// # Example
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.args(), vec!["bar", "baz"]);
    /// ```
    pub fn args<'a>(&'a self) -> Vec<&'a str> {
        slicify(&self._args)
    }

    /// Constructs a vector of string slices referencing the whole Message.
    ///
    /// This is probably best used for pattern-matching on the entire Message.
    ///
    /// # Example
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.as_str_vec(), vec!["foo", "bar", "baz"]);
    /// ```
    pub fn as_str_vec<'a>(&'a self) -> Vec<&'a str> {
        let mut v = self.args();
        v.insert(0, self.word());
        v
    }
}
<commit_msg>Add doctests to Message::from_word.<commit_after>//! The module containing a structure for BAPS3 protocol messages.
#![experimental]

use util::{slicify, unslicify};
use baps3_protocol;

/// A structure for BAPS3 protocol messages.
#[deriving(Clone)]
pub struct Message {
    /// The command word of the message.
    _word: String,

    /// The arguments of the message.
    _args: Vec<String>
}

impl Message {
    /// Creates a new Message.
    pub fn new<Sized? W: Str, Sized? A: Str+Sized>(word: &W, args: &[A])
      -> Message {
        Message { _word: word.as_slice().to_string(), _args: unslicify(args) }
    }

    /// Creates a new Message with no arguments.
    ///
    /// # Example
    ///
    /// A `from_word` message has a word:
    ///
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::from_word("bird");
    /// assert_eq!(m.word(), "bird");
    /// ```
    ///
    /// ...but no arguments:
    ///
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::from_word("bird");
    /// assert!(m.args().is_empty());
    /// ```
    pub fn from_word<Sized? W: Str>(word: &W) -> Message {
        Message { _word: word.as_slice().to_string(), _args: vec![] }
    }

    /// Packs a Message into a BAPS3 protocol line.
    ///
    /// A `pack`ed message is ready for sending down the wire to a BAPS3
    /// client or server via `write_line`.
    ///
    /// # Example
    ///
    /// If none of the arguments have special characters, this is trivial:
    ///
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.pack().as_slice(), "foo bar baz");
    /// ```
    ///
    /// With special characters, we get escaping:
    ///
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["with space", "'single'", "\"double\""]);
    /// assert_eq!(m.pack().as_slice(),
    ///            "foo 'with space' ''\\''single'\\''' '\"double\"'");
    /// ```
    pub fn pack(&self) -> String {
        let vargs = self.args();
        baps3_protocol::pack(self.word(), vargs.as_slice())
    }

    /// Retrieves the command word of this Message.
    ///
    /// # Example
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.word(), "foo");
    /// ```
    pub fn word<'a>(&'a self) -> &'a str {
        self._word.as_slice()
    }

    /// Retrieves the command arguments of this Message.
    ///
    /// # Example
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.args(), vec!["bar", "baz"]);
    /// ```
    pub fn args<'a>(&'a self) -> Vec<&'a str> {
        slicify(&self._args)
    }

    /// Constructs a vector of string slices referencing the whole Message.
    ///
    /// This is probably best used for pattern-matching on the entire Message.
    ///
    /// # Example
    /// ```rust
    /// use baps3_cli::message::Message;
    /// let m = Message::new("foo", &["bar", "baz"]);
    /// assert_eq!(m.as_str_vec(), vec!["foo", "bar", "baz"]);
    /// ```
    pub fn as_str_vec<'a>(&'a self) -> Vec<&'a str> {
        let mut v = self.args();
        v.insert(0, self.word());
        v
    }
}
<|endoftext|>