<commit_before>use crc32::Crc32Reader;
use types::ZipFile;
use compression::CompressionMethod;
use spec;
use reader_spec;
use result::{ZipResult, ZipError};
use std::io;
use std::io::prelude::*;
use std::cell::{RefCell, BorrowState};
use std::collections::HashMap;
use flate2::FlateReadExt;
use bzip2::reader::BzDecompressor;

/// Wrapper for reading the contents of a ZIP file.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::prelude::*;
///
///     // For demonstration purposes we read from an empty buffer.
///     // Normally a File object would be used.
///     let buf: &[u8] = &[0u8; 128];
///     let mut reader = std::io::Cursor::new(buf);
///
///     let zip = try!(zip::ZipReader::new(reader));
///
///     for file in zip.files()
///     {
///         println!("Filename: {}", file.file_name);
///         let mut file_reader = try!(zip.read_file(file));
///         let first_byte = try!(file_reader.bytes().next().unwrap());
///         println!("{}", first_byte);
///     }
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
pub struct ZipReader<T>
{
    inner: RefCell<T>,
    files: Vec<ZipFile>,
    names_map: HashMap<String, usize>,
}

pub struct ZipFileIterator<'a>
{
    inner: ::std::slice::Iter<'a, ZipFile>,
}

impl<'a> Iterator for ZipFileIterator<'a> {
    type Item = &'a ZipFile;
    fn next(&mut self) -> Option<&'a ZipFile> {
        self.inner.next()
    }
}

fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
    Err(ZipError::UnsupportedZipFile(detail))
}

impl<T: Read+io::Seek> ZipReader<T>
{
    /// Opens a ZIP file and parses the content headers.
    pub fn new(mut reader: T) -> ZipResult<ZipReader<T>>
    {
        let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));

        if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") }

        let directory_start = footer.central_directory_offset as u64;
        let number_of_files = footer.number_of_files_on_this_disk as usize;

        let mut files = Vec::with_capacity(number_of_files);
        let mut names_map = HashMap::new();

        try!(reader.seek(io::SeekFrom::Start(directory_start)));
        for _ in (0 .. number_of_files)
        {
            let file = try!(reader_spec::central_header_to_zip_file(&mut reader));
            names_map.insert(file.file_name.clone(), files.len());
            files.push(file);
        }

        Ok(ZipReader { inner: RefCell::new(reader), files: files, names_map: names_map })
    }

    /// An iterator over the information of all contained files.
    pub fn files(&self) -> ZipFileIterator
    {
        ZipFileIterator { inner: (&*self.files).iter(), }
    }

    /// Search for a file entry by name
    pub fn get(&self, name: &str) -> Option<&ZipFile>
    {
        self.names_map.get(name).map(|index| &self.files[*index])
    }

    /// Gets a reader for a contained zipfile.
    ///
    /// May return `ReaderUnavailable` if there is another reader borrowed.
    pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult<Box<Read+'a>>
    {
        let mut inner_reader = match self.inner.borrow_state()
        {
            BorrowState::Unused => self.inner.borrow_mut(),
            _ => return Err(ZipError::ReaderUnavailable),
        };
        let pos = file.data_start as u64;

        if file.encrypted
        {
            return unsupported_zip_error("Encrypted files are not supported")
        }

        try!(inner_reader.seek(io::SeekFrom::Start(pos)));
        let refmut_reader = ::util::RefMutReader::new(inner_reader);
        let limit_reader = refmut_reader.take(file.compressed_size as u64);

        let reader = match file.compression_method
        {
            CompressionMethod::Stored =>
            {
                Box::new(
                    Crc32Reader::new(
                        limit_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Deflated =>
            {
                let deflate_reader = limit_reader.deflate_decode();
                Box::new(
                    Crc32Reader::new(
                        deflate_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Bzip2 =>
            {
                let bzip2_reader = BzDecompressor::new(limit_reader);
                Box::new(
                    Crc32Reader::new(
                        bzip2_reader,
                        file.crc32))
                    as Box<Read>
            },
            _ => return unsupported_zip_error("Compression method not supported"),
        };
        Ok(reader)
    }

    /// Unwrap and return the inner reader object
    ///
    /// The position of the reader is undefined.
    pub fn into_inner(self) -> T
    {
        self.inner.into_inner()
    }

    /// Deprecated method equal to `into_inner()`
    #[deprecated="renamed to into_inner()"]
    pub fn unwrap(self) -> T
    {
        self.into_inner()
    }
}
<commit_msg>Remove deprecated function alltogether<commit_after>use crc32::Crc32Reader;
use types::ZipFile;
use compression::CompressionMethod;
use spec;
use reader_spec;
use result::{ZipResult, ZipError};
use std::io;
use std::io::prelude::*;
use std::cell::{RefCell, BorrowState};
use std::collections::HashMap;
use flate2::FlateReadExt;
use bzip2::reader::BzDecompressor;

/// Wrapper for reading the contents of a ZIP file.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::prelude::*;
///
///     // For demonstration purposes we read from an empty buffer.
///     // Normally a File object would be used.
///     let buf: &[u8] = &[0u8; 128];
///     let mut reader = std::io::Cursor::new(buf);
///
///     let zip = try!(zip::ZipReader::new(reader));
///
///     for file in zip.files()
///     {
///         println!("Filename: {}", file.file_name);
///         let mut file_reader = try!(zip.read_file(file));
///         let first_byte = try!(file_reader.bytes().next().unwrap());
///         println!("{}", first_byte);
///     }
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
pub struct ZipReader<T>
{
    inner: RefCell<T>,
    files: Vec<ZipFile>,
    names_map: HashMap<String, usize>,
}

pub struct ZipFileIterator<'a>
{
    inner: ::std::slice::Iter<'a, ZipFile>,
}

impl<'a> Iterator for ZipFileIterator<'a> {
    type Item = &'a ZipFile;
    fn next(&mut self) -> Option<&'a ZipFile> {
        self.inner.next()
    }
}

fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
    Err(ZipError::UnsupportedZipFile(detail))
}

impl<T: Read+io::Seek> ZipReader<T>
{
    /// Opens a ZIP file and parses the content headers.
    pub fn new(mut reader: T) -> ZipResult<ZipReader<T>>
    {
        let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));

        if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") }

        let directory_start = footer.central_directory_offset as u64;
        let number_of_files = footer.number_of_files_on_this_disk as usize;

        let mut files = Vec::with_capacity(number_of_files);
        let mut names_map = HashMap::new();

        try!(reader.seek(io::SeekFrom::Start(directory_start)));
        for _ in (0 .. number_of_files)
        {
            let file = try!(reader_spec::central_header_to_zip_file(&mut reader));
            names_map.insert(file.file_name.clone(), files.len());
            files.push(file);
        }

        Ok(ZipReader { inner: RefCell::new(reader), files: files, names_map: names_map })
    }

    /// An iterator over the information of all contained files.
    pub fn files(&self) -> ZipFileIterator
    {
        ZipFileIterator { inner: (&*self.files).iter(), }
    }

    /// Search for a file entry by name
    pub fn get(&self, name: &str) -> Option<&ZipFile>
    {
        self.names_map.get(name).map(|index| &self.files[*index])
    }

    /// Gets a reader for a contained zipfile.
    ///
    /// May return `ReaderUnavailable` if there is another reader borrowed.
    pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult<Box<Read+'a>>
    {
        let mut inner_reader = match self.inner.borrow_state()
        {
            BorrowState::Unused => self.inner.borrow_mut(),
            _ => return Err(ZipError::ReaderUnavailable),
        };
        let pos = file.data_start as u64;

        if file.encrypted
        {
            return unsupported_zip_error("Encrypted files are not supported")
        }

        try!(inner_reader.seek(io::SeekFrom::Start(pos)));
        let refmut_reader = ::util::RefMutReader::new(inner_reader);
        let limit_reader = refmut_reader.take(file.compressed_size as u64);

        let reader = match file.compression_method
        {
            CompressionMethod::Stored =>
            {
                Box::new(
                    Crc32Reader::new(
                        limit_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Deflated =>
            {
                let deflate_reader = limit_reader.deflate_decode();
                Box::new(
                    Crc32Reader::new(
                        deflate_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Bzip2 =>
            {
                let bzip2_reader = BzDecompressor::new(limit_reader);
                Box::new(
                    Crc32Reader::new(
                        bzip2_reader,
                        file.crc32))
                    as Box<Read>
            },
            _ => return unsupported_zip_error("Compression method not supported"),
        };
        Ok(reader)
    }

    /// Unwrap and return the inner reader object
    ///
    /// The position of the reader is undefined.
    pub fn into_inner(self) -> T
    {
        self.inner.into_inner()
    }
}
<|endoftext|>


<commit_before>use std::result;
use std::convert::From;
use std::error::Error as StdError;
use std::fmt::{self, Display, Write};
use std::ffi::NulError;

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCString(NulError),
    DatabaseError(String),
}

#[derive(Debug)]
pub enum ConnectionError {
    InvalidCString(NulError),
    BadConnection(String),
}

#[derive(Debug, PartialEq)]
pub enum TransactionError<E> {
    CouldntCreateTransaction(Error),
    UserReturnedError(E),
}

pub type Result<T> = result::Result<T, Error>;
pub type ConnectionResult<T> = result::Result<T, ConnectionError>;
pub type TransactionResult<T, E> = result::Result<T, TransactionError<E>>;

impl From<NulError> for ConnectionError {
    fn from(e: NulError) -> Self {
        ConnectionError::InvalidCString(e)
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Error::InvalidCString(e)
    }
}

impl<E> From<Error> for TransactionError<E> {
    fn from(e: Error) -> Self {
        TransactionError::CouldntCreateTransaction(e)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &Error::DatabaseError(ref s) => write!(f, "{}", &s),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.description(),
            &Error::DatabaseError(ref s) => &s,
        }
    }
}

impl Display for ConnectionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &ConnectionError::BadConnection(ref s) => write!(f, "{}", &s),
        }
    }
}

impl StdError for ConnectionError {
    fn description(&self) -> &str {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.description(),
            &ConnectionError::BadConnection(ref s) => &s,
        }
    }
}

impl<E: Display> Display for TransactionError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.fmt(f),
            &TransactionError::UserReturnedError(ref e) => e.fmt(f),
        }
    }
}

impl<E: StdError> StdError for TransactionError<E> {
    fn description(&self) -> &str {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.description(),
            &TransactionError::UserReturnedError(ref e) => e.description(),
        }
    }
}
<commit_msg>Add a helpful `From` impl for common transaction usage<commit_after>use std::result;
use std::convert::From;
use std::error::Error as StdError;
use std::fmt::{self, Display, Write};
use std::ffi::NulError;

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCString(NulError),
    DatabaseError(String),
}

#[derive(Debug)]
pub enum ConnectionError {
    InvalidCString(NulError),
    BadConnection(String),
}

#[derive(Debug, PartialEq)]
pub enum TransactionError<E> {
    CouldntCreateTransaction(Error),
    UserReturnedError(E),
}

pub type Result<T> = result::Result<T, Error>;
pub type ConnectionResult<T> = result::Result<T, ConnectionError>;
pub type TransactionResult<T, E> = result::Result<T, TransactionError<E>>;

impl From<NulError> for ConnectionError {
    fn from(e: NulError) -> Self {
        ConnectionError::InvalidCString(e)
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Error::InvalidCString(e)
    }
}

impl<E> From<Error> for TransactionError<E> {
    fn from(e: Error) -> Self {
        TransactionError::CouldntCreateTransaction(e)
    }
}

impl From<TransactionError<Error>> for Error {
    fn from(e: TransactionError<Error>) -> Self {
        match e {
            TransactionError::CouldntCreateTransaction(e) => e,
            TransactionError::UserReturnedError(e) => e,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &Error::DatabaseError(ref s) => write!(f, "{}", &s),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.description(),
            &Error::DatabaseError(ref s) => &s,
        }
    }
}

impl Display for ConnectionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &ConnectionError::BadConnection(ref s) => write!(f, "{}", &s),
        }
    }
}

impl StdError for ConnectionError {
    fn description(&self) -> &str {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.description(),
            &ConnectionError::BadConnection(ref s) => &s,
        }
    }
}

impl<E: Display> Display for TransactionError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.fmt(f),
            &TransactionError::UserReturnedError(ref e) => e.fmt(f),
        }
    }
}

impl<E: StdError> StdError for TransactionError<E> {
    fn description(&self) -> &str {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.description(),
            &TransactionError::UserReturnedError(ref e) => e.description(),
        }
    }
}
<|endoftext|>


<commit_before>use common::{ApiError, Body, Credentials, Query, discovery_api};
use hyper::method::Method::{Delete, Get, Post};
use serde_json::{Value, to_string};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct NewEnvironment {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub size: u64,
}

pub fn list(creds: &Credentials) -> Result<Value, ApiError> {
    Ok(discovery_api(creds, Get, "/v1/environments", Query::None, &Body::None)?)
}

pub fn detail(creds: &Credentials, env_id: &str) -> Result<Value, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    Ok(discovery_api(creds, Get, &path, Query::None, &Body::None)?)
}

pub fn preview(creds: &Credentials,
               env_id: &str,
               configuration_id: Option<&str>,
               filename: &str)
               -> Result<Value, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    let q = match configuration_id {
        Some(id) => Query::Config(id.to_string()),
        None => Query::None,
    };
    Ok(discovery_api(creds, Post, &path, q, &Body::Filename(filename))?)
}

pub fn create(creds: &Credentials,
              options: &NewEnvironment)
              -> Result<Value, ApiError> {
    let request_body = to_string(options)
        .expect("Internal error: failed to convert NewEnvironment into JSON");
    Ok(discovery_api(creds,
                     Post,
                     "/v1/environments",
                     Query::None,
                     &Body::Json(&request_body))?)
}

pub fn delete(creds: &Credentials, env_id: &str) -> Result<Value, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    Ok(discovery_api(creds, Delete, &path, Query::None, &Body::None)?)
}
<commit_msg>Fix environment::preview to, um, actually invoke `preview`<commit_after>use common::{ApiError, Body, Credentials, Query, discovery_api};
use hyper::method::Method::{Delete, Get, Post};
use serde_json::{Value, to_string};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct NewEnvironment {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub size: u64,
}

pub fn list(creds: &Credentials) -> Result<Value, ApiError> {
    Ok(discovery_api(creds, Get, "/v1/environments", Query::None, &Body::None)?)
}

pub fn detail(creds: &Credentials, env_id: &str) -> Result<Value, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    Ok(discovery_api(creds, Get, &path, Query::None, &Body::None)?)
}

pub fn preview(creds: &Credentials,
               env_id: &str,
               configuration_id: Option<&str>,
               filename: &str)
               -> Result<Value, ApiError> {
    let path = "/v1/environments/".to_string() + env_id + "/preview";
    let q = match configuration_id {
        Some(id) => Query::Config(id.to_string()),
        None => Query::None,
    };
    Ok(discovery_api(creds, Post, &path, q, &Body::Filename(filename))?)
}

pub fn create(creds: &Credentials,
              options: &NewEnvironment)
              -> Result<Value, ApiError> {
    let request_body = to_string(options)
        .expect("Internal error: failed to convert NewEnvironment into JSON");
    Ok(discovery_api(creds,
                     Post,
                     "/v1/environments",
                     Query::None,
                     &Body::Json(&request_body))?)
}

pub fn delete(creds: &Credentials, env_id: &str) -> Result<Value, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    Ok(discovery_api(creds, Delete, &path, Query::None, &Body::None)?)
}
<|endoftext|>


<commit_before>extern crate futures_cpupool;
use futures_cpupool::CpuPool;
use futures_cpupool::CpuFuture;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::RwLock;
use global::Global;
use document::Document;

#[derive(Clone)]
pub struct Search {
	pub indices: Arc<
		RwLock<
			HashMap<
				String,
				Arc<RwLock<Global>>
			>
		>
	>, //<name, Global> for Global indices
	threadpool: CpuPool
}

impl Search {
	pub fn new() -> Search {
		Search {
			indices: Arc::new(
				RwLock::new(
					HashMap::new()
				)
			),
			threadpool: CpuPool::new_num_cpus()
		}
	}

	pub fn create_index(&mut self, name: &str) -> Result< Arc<RwLock<Global>>, &str > {
		let indices = self.indices.clone();
		let mut indices = indices.write().unwrap();

		if indices.contains_key(name) {
			Err("Global Index already exists")
		} else {
			let index: Arc<RwLock<Global>> =
				Arc::new(
					RwLock::new(
						Global::new(name)
					)
				);

			indices.insert(name.to_string(), index.clone());
			Ok(index.clone())
		}
	}

	pub fn remove_index(&mut self, name: &str) -> Result< Arc<RwLock<Global>>, &str > {
		let indices = self.indices.clone();
		let mut indices = indices.write().unwrap();

		match indices.remove(name) {
			Some(val) => Ok(val),
			None => Err("Global Index not found")
		}
	}

	pub fn insert(&mut self, name: String, corpus: String) -> CpuFuture<Arc<Document>, String> {
		let indices = self.indices.clone();

		let future: CpuFuture<Arc<Document>, String> = self.threadpool.spawn_fn(move || {
			let indices = indices.read().unwrap();

			match indices.get(&name) {
				Some(val) => {
					let val = val.clone();

					let mut global = val.write().unwrap();
					let index = global.insert(&corpus);
					let res: Result<Arc<Document>, String> = Ok(index.doc.clone());

					res
				},
				None => {
					let res: Result<Arc<Document>, String> = Err("Global Index not found.".to_string());

					res
				}
			}
		});

		future
	}

	pub fn search(&self, name: String, text: String) -> CpuFuture<Vec<(Arc<Document>, f32)>, String> {
		let indices = self.indices.clone();

		let future: CpuFuture<Vec<(Arc<Document>, f32)>, String> = self.threadpool.spawn_fn(move || {
			let indices = indices.read().unwrap();

			match indices.get(&name) {
				Some(val) => {
					let val = val.clone();

					let global = val.read().unwrap();
					let res: Result<Vec<(Arc<Document>, f32)>, String> = Ok(global.search(&text));

					res
				},
				None => {
					let res: Result<Vec<(Arc<Document>, f32)>, String> = Err("Global Index not found.".to_string());

					res
				}
			}
		});

		future
	}
}<commit_msg>No need<commit_after>extern crate futures_cpupool;
use futures_cpupool::CpuPool;
use futures_cpupool::CpuFuture;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::RwLock;
use global::Global;
use document::Document;

pub struct Search {
	pub indices: Arc<
		RwLock<
			HashMap<
				String,
				Arc<RwLock<Global>>
			>
		>
	>, //<name, Global> for Global indices
	threadpool: CpuPool
}

impl Search {
	pub fn new() -> Search {
		Search {
			indices: Arc::new(
				RwLock::new(
					HashMap::new()
				)
			),
			threadpool: CpuPool::new_num_cpus()
		}
	}

	pub fn create_index(&mut self, name: &str) -> Result< Arc<RwLock<Global>>, &str > {
		let indices = self.indices.clone();
		let mut indices = indices.write().unwrap();

		if indices.contains_key(name) {
			Err("Global Index already exists")
		} else {
			let index: Arc<RwLock<Global>> =
				Arc::new(
					RwLock::new(
						Global::new(name)
					)
				);

			indices.insert(name.to_string(), index.clone());
			Ok(index.clone())
		}
	}

	pub fn remove_index(&mut self, name: &str) -> Result< Arc<RwLock<Global>>, &str > {
		let indices = self.indices.clone();
		let mut indices = indices.write().unwrap();

		match indices.remove(name) {
			Some(val) => Ok(val),
			None => Err("Global Index not found")
		}
	}

	pub fn insert(&mut self, name: String, corpus: String) -> CpuFuture<Arc<Document>, String> {
		let indices = self.indices.clone();

		let future: CpuFuture<Arc<Document>, String> = self.threadpool.spawn_fn(move || {
			let indices = indices.read().unwrap();

			match indices.get(&name) {
				Some(val) => {
					let val = val.clone();

					let mut global = val.write().unwrap();
					let index = global.insert(&corpus);
					let res: Result<Arc<Document>, String> = Ok(index.doc.clone());

					res
				},
				None => {
					let res: Result<Arc<Document>, String> = Err("Global Index not found.".to_string());

					res
				}
			}
		});

		future
	}

	pub fn search(&self, name: String, text: String) -> CpuFuture<Vec<(Arc<Document>, f32)>, String> {
		let indices = self.indices.clone();

		let future: CpuFuture<Vec<(Arc<Document>, f32)>, String> = self.threadpool.spawn_fn(move || {
			let indices = indices.read().unwrap();

			match indices.get(&name) {
				Some(val) => {
					let val = val.clone();

					let global = val.read().unwrap();
					let res: Result<Vec<(Arc<Document>, f32)>, String> = Ok(global.search(&text));

					res
				},
				None => {
					let res: Result<Vec<(Arc<Document>, f32)>, String> = Err("Global Index not found.".to_string());

					res
				}
			}
		});

		future
	}
}<|endoftext|>


<commit_before>use nom::{multispace, space};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, unsigned_number, statement_terminator, table_list};
use parser::ConditionExpression;

use condition::*;

#[derive(Clone, Debug, PartialEq)]
pub struct GroupByClause {
    columns: Vec<String>,
    having: String, // XXX(malte): should this be an arbitrary expr?
}

#[derive(Clone, Debug, PartialEq)]
pub struct LimitClause {
    limit: u64,
    offset: u64,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OrderType {
    OrderAscending,
    OrderDescending,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderClause {
    cols: Vec<String>, // TODO(malte): can this be an arbitrary expr?
    order: OrderType,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct SelectStatement {
    pub table: String,
    pub distinct: bool,
    pub fields: Vec<String>,
    pub where_clause: Option<ConditionExpression>,
    pub group_by: Option<GroupByClause>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse LIMIT clause
named!(limit_clause<&[u8], LimitClause>,
    chain!(
        space ~
        caseless_tag!("limit") ~
        space ~
        limit_val: unsigned_number ~
        space? ~
        offset_val: opt!(chain!(
                caseless_tag!("offset") ~
                space ~
                val: unsigned_number,
                || { val }
            )
        ),
    || {
        LimitClause {
            limit: limit_val,
            offset: match offset_val {
                None => 0,
                Some(v) => v,
            },
        }
    })
);

named!(order_clause<&[u8], OrderClause>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("order by") ~
        multispace ~
        order_expr: field_list ~
        ordering: opt!(
            alt_complete!(
                  map!(caseless_tag!("desc"), |_| OrderType::OrderDescending)
                | map!(caseless_tag!("asc"), |_| OrderType::OrderAscending)
            )
        ),
    || {
        OrderClause {
            cols: order_expr.iter().map(|e| String::from(*e)).collect(),
            order: match ordering {
                None => OrderType::OrderAscending,
                Some(ref o) => o.clone(),
            },
        }
    })
));

/// Parse WHERE clause of a selection
named!(where_clause<&[u8], ConditionExpression>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("where") ~
        multispace ~
        cond: condition_expr,
        || { cond }
    )
));

/// Parse rule for a SQL selection query.
/// TODO(malte): support nested queries as selection targets
named!(pub selection<&[u8], SelectStatement>,
    chain!(
        caseless_tag!("select") ~
        space ~
        distinct: opt!(caseless_tag!("distinct")) ~
        space? ~
        fields: field_list ~
        delimited!(opt!(multispace), caseless_tag!("from"), opt!(multispace)) ~
        tables: table_list ~
        cond: opt!(where_clause) ~
        order: opt!(order_clause) ~
        limit: opt!(limit_clause) ~
        statement_terminator,
        || {
            SelectStatement {
                tables: tables.iter().map(|t| String::from(*t)).collect(),
                distinct: distinct.is_some(),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
                where_clause: cond,
                group_by: None,
                order: order,
                limit: limit,
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use common::Operator;
    use parser::{ConditionBase, ConditionExpression, ConditionTree};

    #[test]
    fn simple_select() {
        let qstring = "SELECT id, name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn select_all() {
        let qstring = "SELECT * FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn spaces_optional() {
        let qstring = "SELECT id,name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn case_sensitivity() {
        let qstring_lc = "select id, name from users;";
        let qstring_uc = "SELECT id, name FROM users;";

        assert_eq!(selection(qstring_lc.as_bytes()).unwrap(),
                   selection(qstring_uc.as_bytes()).unwrap());
    }

    #[test]
    fn termination() {
        let qstring_sem = "select id, name from users;";
        let qstring_linebreak = "select id, name from users\n";

        assert_eq!(selection(qstring_sem.as_bytes()).unwrap(),
                   selection(qstring_linebreak.as_bytes()).unwrap());
    }

    #[test]
    fn where_clause() {
        let qstring = "select * from ContactInfo where email=?;";

        let res = selection(qstring.as_bytes());

        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("email"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("ContactInfo"),
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn limit_clause() {
        let qstring1 = "select * from users limit 10\n";
        let qstring2 = "select * from users limit 10 offset 10\n";

        let expected_lim1 = LimitClause {
            limit: 10,
            offset: 0,
        };
        let expected_lim2 = LimitClause {
            limit: 10,
            offset: 10,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        assert_eq!(res1.unwrap().1.limit, Some(expected_lim1));
        assert_eq!(res2.unwrap().1.limit, Some(expected_lim2));
    }

    #[test]
    fn order_clause() {
        let qstring1 = "select * from users order by name desc\n";
        let qstring2 = "select * from users order by name, age desc\n";
        let qstring3 = "select * from users order by name\n";

        let expected_ord1 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord2 = OrderClause {
            cols: vec!["name".into(), "age".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord3 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderAscending,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        let res3 = selection(qstring3.as_bytes());
        assert_eq!(res1.unwrap().1.order, Some(expected_ord1));
        assert_eq!(res2.unwrap().1.order, Some(expected_ord2));
        assert_eq!(res3.unwrap().1.order, Some(expected_ord3));
    }

    #[test]
    fn table_alias() {
        let qstring1 = "select * from PaperTag as t;";
        // let qstring2 = "select * from PaperTag t;";

        let res1 = selection(qstring1.as_bytes());
        assert_eq!(res1.clone().unwrap().1,
                   SelectStatement {
                       table: String::from("PaperTag"),
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
        // let res2 = selection(qstring2.as_bytes());
        // assert_eq!(res1.unwrap().1, res2.unwrap().1);
    }

    #[test]
    fn distinct() {
        let qstring = "select distinct tag from PaperTag where paperId=?;";

        let res = selection(qstring.as_bytes());
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("PaperTag"),
                       distinct: true,
                       fields: vec!["tag".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn simple_condition_expr() {
        let qstring = "select infoJson from PaperStorage where paperId=? and paperStorageId=?;";

        let res = selection(qstring.as_bytes());

        let left_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let right_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperStorageId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let expected_where_cond = Some(ConditionExpression::LogicalOp(ConditionTree {
            left: left_comp,
            right: right_comp,
            operator: String::from("and"),
        }));
        println!("res: {:#?}", res);
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("PaperStorage"),
                       fields: vec!["infoJson".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }
}
<commit_msg>Support multiple tables in FROM part of selection<commit_after>use nom::{multispace, space};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, unsigned_number, statement_terminator, table_list};
use parser::ConditionExpression;

use condition::*;

#[derive(Clone, Debug, PartialEq)]
pub struct GroupByClause {
    columns: Vec<String>,
    having: String, // XXX(malte): should this be an arbitrary expr?
}

#[derive(Clone, Debug, PartialEq)]
pub struct LimitClause {
    limit: u64,
    offset: u64,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OrderType {
    OrderAscending,
    OrderDescending,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderClause {
    cols: Vec<String>, // TODO(malte): can this be an arbitrary expr?
    order: OrderType,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct SelectStatement {
    pub tables: Vec<String>,
    pub distinct: bool,
    pub fields: Vec<String>,
    pub where_clause: Option<ConditionExpression>,
    pub group_by: Option<GroupByClause>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse LIMIT clause
named!(limit_clause<&[u8], LimitClause>,
    chain!(
        space ~
        caseless_tag!("limit") ~
        space ~
        limit_val: unsigned_number ~
        space? ~
        offset_val: opt!(chain!(
                caseless_tag!("offset") ~
                space ~
                val: unsigned_number,
                || { val }
            )
        ),
    || {
        LimitClause {
            limit: limit_val,
            offset: match offset_val {
                None => 0,
                Some(v) => v,
            },
        }
    })
);

named!(order_clause<&[u8], OrderClause>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("order by") ~
        multispace ~
        order_expr: field_list ~
        ordering: opt!(
            alt_complete!(
                  map!(caseless_tag!("desc"), |_| OrderType::OrderDescending)
                | map!(caseless_tag!("asc"), |_| OrderType::OrderAscending)
            )
        ),
    || {
        OrderClause {
            cols: order_expr.iter().map(|e| String::from(*e)).collect(),
            order: match ordering {
                None => OrderType::OrderAscending,
                Some(ref o) => o.clone(),
            },
        }
    })
));

/// Parse WHERE clause of a selection
named!(where_clause<&[u8], ConditionExpression>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("where") ~
        multispace ~
        cond: condition_expr,
        || { cond }
    )
));

/// Parse rule for a SQL selection query.
/// TODO(malte): support nested queries as selection targets
named!(pub selection<&[u8], SelectStatement>,
    chain!(
        caseless_tag!("select") ~
        space ~
        distinct: opt!(caseless_tag!("distinct")) ~
        space? ~
        fields: field_list ~
        delimited!(opt!(multispace), caseless_tag!("from"), opt!(multispace)) ~
        tables: table_list ~
        cond: opt!(where_clause) ~
        order: opt!(order_clause) ~
        limit: opt!(limit_clause) ~
        statement_terminator,
        || {
            SelectStatement {
                tables: tables.iter().map(|t| String::from(*t)).collect(),
                distinct: distinct.is_some(),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
                where_clause: cond,
                group_by: None,
                order: order,
                limit: limit,
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use common::Operator;
    use parser::{ConditionBase, ConditionExpression, ConditionTree};

    #[test]
    fn simple_select() {
        let qstring = "SELECT id, name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn select_all() {
        let qstring = "SELECT * FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn spaces_optional() {
        let qstring = "SELECT id,name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn case_sensitivity() {
        let qstring_lc = "select id, name from users;";
        let qstring_uc = "SELECT id, name FROM users;";

        assert_eq!(selection(qstring_lc.as_bytes()).unwrap(),
                   selection(qstring_uc.as_bytes()).unwrap());
    }

    #[test]
    fn termination() {
        let qstring_sem = "select id, name from users;";
        let qstring_linebreak = "select id, name from users\n";

        assert_eq!(selection(qstring_sem.as_bytes()).unwrap(),
                   selection(qstring_linebreak.as_bytes()).unwrap());
    }

    #[test]
    fn where_clause() {
        let qstring = "select * from ContactInfo where email=?;";

        let res = selection(qstring.as_bytes());

        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("email"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("ContactInfo")],
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn limit_clause() {
        let qstring1 = "select * from users limit 10\n";
        let qstring2 = "select * from users limit 10 offset 10\n";

        let expected_lim1 = LimitClause {
            limit: 10,
            offset: 0,
        };
        let expected_lim2 = LimitClause {
            limit: 10,
            offset: 10,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        assert_eq!(res1.unwrap().1.limit, Some(expected_lim1));
        assert_eq!(res2.unwrap().1.limit, Some(expected_lim2));
    }

    #[test]
    fn order_clause() {
        let qstring1 = "select * from users order by name desc\n";
        let qstring2 = "select * from users order by name, age desc\n";
        let qstring3 = "select * from users order by name\n";

        let expected_ord1 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord2 = OrderClause {
            cols: vec!["name".into(), "age".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord3 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderAscending,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        let res3 = selection(qstring3.as_bytes());
        assert_eq!(res1.unwrap().1.order, Some(expected_ord1));
        assert_eq!(res2.unwrap().1.order, Some(expected_ord2));
        assert_eq!(res3.unwrap().1.order, Some(expected_ord3));
    }

    #[test]
    fn table_alias() {
        let qstring1 = "select * from PaperTag as t;";
        // let qstring2 = "select * from PaperTag t;";

        let res1 = selection(qstring1.as_bytes());
        assert_eq!(res1.clone().unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperTag")],
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
        // let res2 = selection(qstring2.as_bytes());
        // assert_eq!(res1.unwrap().1, res2.unwrap().1);
    }

    #[test]
    fn distinct() {
        let qstring = "select distinct tag from PaperTag where paperId=?;";

        let res = selection(qstring.as_bytes());
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperTag")],
                       distinct: true,
                       fields: vec!["tag".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn simple_condition_expr() {
        let qstring = "select infoJson from PaperStorage where paperId=? and paperStorageId=?;";

        let res = selection(qstring.as_bytes());

        let left_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let right_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperStorageId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let expected_where_cond = Some(ConditionExpression::LogicalOp(ConditionTree {
            left: left_comp,
            right: right_comp,
            operator: String::from("and"),
        }));
        println!("res: {:#?}", res);
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperStorage")],
                       fields: vec!["infoJson".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }
}
<|endoftext|>


<commit_before>use super::command::Command;
use super::command::Command::Select;
use std::iter::IntoIterator;
use std::collections::HashMap;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct SelectCommand {
    command: Command,
    table: String,
    arguments: HashMap<String, String>,
}

impl Default for SelectCommand {
    fn default() -> SelectCommand {
        SelectCommand {
            command: Select,
            table: "".to_string(),
            arguments: HashMap::new(),
        }
    }
}

impl SelectCommand {
    pub fn new(table: String) -> SelectCommand {
        let default: SelectCommand = Default::default();
        SelectCommand {
            command: default.command,
            table: table,
            arguments: default.arguments,
        }
    }

    pub fn filter(mut self, filter: String) -> SelectCommand {
        let encoded = format!("'{}'", filter);
        self.arguments.insert("filter".to_string(), encoded.clone());
        self
    }

    pub fn query(mut self, query: String) -> SelectCommand {
        let encoded = format!("'{}'", query);
        self.arguments.insert("query".to_string(), encoded.clone());
        self
    }

    #[inline]
    fn split_columns_vec(&mut self, columns: Vec<String>) -> String {
        let string = columns.into_iter().collect::<Vec<String>>()
            .join(",").to_owned();
        string.clone()
    }

    pub fn match_columns(mut self, columns: Vec<String>) -> SelectCommand {
        let string = self.split_columns_vec(columns);
        self.arguments.insert("match_columns".to_string(), string.clone());
        self
    }

    pub fn output_columns(mut self, columns: Vec<String>) -> SelectCommand {
        let string = self.split_columns_vec(columns);
        self.arguments.insert("output_columns".to_string(), string.clone());
        self
    }

    pub fn offset(mut self, offset: u64) -> SelectCommand {
        let offset = format!("{}", offset);
        self.arguments.insert("offset".to_string(), offset.clone());
        self
    }

    pub fn limit(mut self, limit: u64) -> SelectCommand {
        let limit = format!("{}", limit);
        self.arguments.insert("limit".to_string(), limit.clone());
        self
    }

    pub fn cache(mut self, cache: bool) -> SelectCommand {
        let flag = match cache {
            true => "yes",
            false => "no"
        };
        self.arguments.insert("cache".to_string(), flag.to_string());
        self
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use command::Command::Select;
    use std::collections::HashMap;

    #[test]
    fn test_new() {
        let vanilla_select = SelectCommand::new("test".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: HashMap::new(),
        };
        assert_eq!(expected, vanilla_select);
    }

    #[test]
    fn test_filter() {
        let select = SelectCommand::new("test".to_string())
            .filter("output_column @ \"type_safe\"".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("filter".to_string(),
                   "'output_column @ \"type_safe\"'".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_query() {
        let select = SelectCommand::new("test".to_string())
            .query("_key:\"http://example.org/\"".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("query".to_string(),
                   "\'_key:\"http://example.org/\"\'".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_match_columns() {
        let select = SelectCommand::new("test".to_string())
            .match_columns(vec!["test".to_string(), "piyo".to_string()]);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("match_columns".to_string(), "test,piyo".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_output_columns() {
        let select = SelectCommand::new("test".to_string())
            .output_columns(vec!["test".to_string(), "piyo".to_string()]);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("output_columns".to_string(), "test,piyo".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_offset() {
        let select = SelectCommand::new("test".to_string())
            .offset(100);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("offset".to_string(), "100".to_string());
        let expected = SelectCommand {
            command: Select,
            arguments: arg,
            table: "test".to_string(),
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_limit() {
        let select = SelectCommand::new("test".to_string())
            .limit(50);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("limit".to_string(), "50".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_cache() {
        let select_yes = SelectCommand::new("test".to_string())
            .cache(true);
        let mut arg_yes: HashMap<String, String> = HashMap::new();
        arg_yes.insert("cache".to_string(), "yes".to_string());
        let expected_yes = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg_yes,
        };
        assert_eq!(expected_yes, select_yes);
        let select_no = SelectCommand::new("test".to_string())
            .cache(false);
        let mut arg_no: HashMap<String, String> = HashMap::new();
        arg_no.insert("cache".to_string(), "no".to_string());
        let expected_no = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg_no,
        };
        assert_eq!(expected_no, select_no);
    }
}
<commit_msg>select: Build arguments into Query type method<commit_after>use super::command::{Command, Query};
use super::command::Command::Select;
use std::iter::IntoIterator;
use std::collections::HashMap;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct SelectCommand {
    command: Command,
    table: String,
    arguments: HashMap<String, String>,
}

impl Default for SelectCommand {
    fn default() -> SelectCommand {
        SelectCommand {
            command: Select,
            table: "".to_string(),
            arguments: HashMap::new(),
        }
    }
}

impl SelectCommand {
    pub fn new(table: String) -> SelectCommand {
        let default: SelectCommand = Default::default();
        SelectCommand {
            command: default.command,
            table: table,
            arguments: default.arguments,
        }
    }

    pub fn filter(mut self, filter: String) -> SelectCommand {
        let encoded = format!("'{}'", filter);
        self.arguments.insert("filter".to_string(), encoded.clone());
        self
    }

    pub fn query(mut self, query: String) -> SelectCommand {
        let encoded = format!("'{}'", query);
        self.arguments.insert("query".to_string(), encoded.clone());
        self
    }

    #[inline]
    fn split_columns_vec(&mut self, columns: Vec<String>) -> String {
        let string = columns.into_iter().collect::<Vec<String>>()
            .join(",").to_owned();
        string.clone()
    }

    pub fn match_columns(mut self, columns: Vec<String>) -> SelectCommand {
        let string = self.split_columns_vec(columns);
        self.arguments.insert("match_columns".to_string(), string.clone());
        self
    }

    pub fn output_columns(mut self, columns: Vec<String>) -> SelectCommand {
        let string = self.split_columns_vec(columns);
        self.arguments.insert("output_columns".to_string(), string.clone());
        self
    }

    pub fn offset(mut self, offset: u64) -> SelectCommand {
        let offset = format!("{}", offset);
        self.arguments.insert("offset".to_string(), offset.clone());
        self
    }

    pub fn limit(mut self, limit: u64) -> SelectCommand {
        let limit = format!("{}", limit);
        self.arguments.insert("limit".to_string(), limit.clone());
        self
    }

    pub fn cache(mut self, cache: bool) -> SelectCommand {
        let flag = match cache {
            true => "yes",
            false => "no"
        };
        self.arguments.insert("cache".to_string(), flag.to_string());
        self
    }

    pub fn build(self) -> Query {
        let mut query: Query = vec![("table".to_string(), self.table)];
        for (key, value) in self.arguments.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        query
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use command::Query;
    use command::Command::Select;
    use std::collections::HashMap;

    #[test]
    fn test_new() {
        let vanilla_select = SelectCommand::new("test".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: HashMap::new(),
        };
        assert_eq!(expected, vanilla_select);
    }

    #[test]
    fn test_filter() {
        let select = SelectCommand::new("test".to_string())
            .filter("output_column @ \"type_safe\"".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("filter".to_string(),
                   "'output_column @ \"type_safe\"'".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_query() {
        let select = SelectCommand::new("test".to_string())
            .query("_key:\"http://example.org/\"".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("query".to_string(),
                   "\'_key:\"http://example.org/\"\'".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_match_columns() {
        let select = SelectCommand::new("test".to_string())
            .match_columns(vec!["test".to_string(), "piyo".to_string()]);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("match_columns".to_string(), "test,piyo".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_output_columns() {
        let select = SelectCommand::new("test".to_string())
            .output_columns(vec!["test".to_string(), "piyo".to_string()]);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("output_columns".to_string(), "test,piyo".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_offset() {
        let select = SelectCommand::new("test".to_string())
            .offset(100);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("offset".to_string(), "100".to_string());
        let expected = SelectCommand {
            command: Select,
            arguments: arg,
            table: "test".to_string(),
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_limit() {
        let select = SelectCommand::new("test".to_string())
            .limit(50);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("limit".to_string(), "50".to_string());
        let expected = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg,
        };
        assert_eq!(expected, select);
    }

    #[test]
    fn test_cache() {
        let select_yes = SelectCommand::new("test".to_string())
            .cache(true);
        let mut arg_yes: HashMap<String, String> = HashMap::new();
        arg_yes.insert("cache".to_string(), "yes".to_string());
        let expected_yes = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg_yes,
        };
        assert_eq!(expected_yes, select_yes);
        let select_no = SelectCommand::new("test".to_string())
            .cache(false);
        let mut arg_no: HashMap<String, String> = HashMap::new();
        arg_no.insert("cache".to_string(), "no".to_string());
        let expected_no = SelectCommand {
            command: Select,
            table: "test".to_string(),
            arguments: arg_no,
        };
        assert_eq!(expected_no, select_no);
    }

    #[test]
    fn test_build() {
        let query = SelectCommand::new("test".to_string())
            .filter("output_column @ \"type_safe\"".to_string()).build();
        let expected: Query =
            vec![("table".to_string(), "test".to_string()),
                 ("filter".to_string(),
                  "'output_column @ \"type_safe\"'".to_string())];
        assert_eq!(expected, query);
    }
}
<|endoftext|>


<commit_before>
pub struct Serial {
	enabled: bool,
	priv data: u8,
	priv control: u8,
}

impl Serial {
	pub fn new() -> Serial {
		Serial { enabled: true, data: 0, control: 0 }
	}

	pub fn wb(&mut self, a: u16, v: u8) {
		match a {
			0xFF01 => {
				if self.enabled {
					println!("{}", v as char);
					::std::io::stdio::flush();
				}
				self.data = v;
			},
			0xFF02 => { self.control = v; },
			_ => { fail!("Serial does not handle address {:4X} (write)", a); },
		};
	}

	pub fn rb(&self, a: u16) -> u8 {
		match a {
			0xFF01 => self.data,
			0xFF02 => self.control,
			_ => fail!("Serial does not handle address {:4X} (read)", a),
		}
	}
}
<commit_msg>No line endings in Serial<commit_after>
pub struct Serial {
	enabled: bool,
	priv data: u8,
	priv control: u8,
}

impl Serial {
	pub fn new() -> Serial {
		Serial { enabled: true, data: 0, control: 0 }
	}

	pub fn wb(&mut self, a: u16, v: u8) {
		match a {
			0xFF01 => {
				if self.enabled {
					print!("{}", v as char);
					::std::io::stdio::flush();
				}
				self.data = v;
			},
			0xFF02 => { self.control = v; },
			_ => { fail!("Serial does not handle address {:4X} (write)", a); },
		};
	}

	pub fn rb(&self, a: u16) -> u8 {
		match a {
			0xFF01 => self.data,
			0xFF02 => self.control,
			_ => fail!("Serial does not handle address {:4X} (read)", a),
		}
	}
}
<|endoftext|>


<commit_before>use std::thread;
use std::thread::JoinHandle;
use std::path::Path;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use git2::Repository;
use git2::ObjectType;

use payload;
use State;

extern crate fsevent;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start() {
    let server = Server::bind("127.0.0.1:2794").unwrap();
    thread::spawn(move || {
        for connection in server {
            thread::spawn(move || connect(connection.unwrap()));
        }
    });
}

fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();
    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("rust-websocket".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        tx.send(NotifierMessage::WebMessage(message));
    }
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    loop {
        let value = rx.recv().unwrap();
        println!("{:?}", value);
        match value {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        let message = WebMessage::close();
                        sender.send_message(&message).unwrap();
                        println!("Client disconnected");
                        return;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        println!("{:?}", payload);
                        let mut state: State = xml::from_str(&payload).unwrap();
                        println!("{:?}", state);

                        let repo = Repository::discover(".").unwrap();
                        let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap();
                        let mut index = repo.index().unwrap();

                        let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                            let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                            match state.include.iter().find(|i| i.as_ref() == entry_path) {
                                None => acc.push(entry_path.into_owned()),
                                _ => {}
                            };
                            acc
                        });

                        repo.reset_default(Some(&head), to_remove.iter()).unwrap();
                        for change in state.clone().include {
                            let path = Path::new(&change);
                            index.add_path(path).unwrap();
                        }
                        index.write().unwrap();

                        if let Some(event) = state.save_update.clone() {
                            let author = repo.signature().unwrap();
                            index.read(false);
                            let tree_oid = index.write_tree().unwrap();
                            let tree = repo.find_tree(tree_oid).unwrap();
                            repo.commit(Some("HEAD"), &author, &author, &state.message, &tree, &[&head.as_commit().unwrap()]);
                            let message = WebMessage::text(payload::generate(None));
                            sender.send_message(&message).unwrap();
                        } else {
                            let message = WebMessage::text(payload::generate(Some(state)));
                            sender.send_message(&message).unwrap();
                        }
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {}
        }
    }
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        tx.send(NotifierMessage::FsEvent(event));
    }
}

<commit_msg>attempting to be more diligent closing threads behind me.<commit_after>use std::thread;
use std::thread::JoinHandle;
use std::path::Path;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use git2::Repository;
use git2::ObjectType;

use payload;
use State;

extern crate fsevent;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start() {
    let server = Server::bind("127.0.0.1:2794").unwrap();
    thread::spawn(move || {
        for connection in server {
            thread::spawn(move || connect(connection.unwrap()));
        }
    });
}

fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();
    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("rust-websocket".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    loop {
        let value = rx.recv().unwrap();
        println!("{:?}", value);
        match value {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        println!("{:?}", payload);
                        let mut state: State = xml::from_str(&payload).unwrap();
                        println!("{:?}", state);

                        let repo = Repository::discover(".").unwrap();
                        let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap();
                        let mut index = repo.index().unwrap();

                        let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                            let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                            match state.include.iter().find(|i| i.as_ref() == entry_path) {
                                None => acc.push(entry_path.into_owned()),
                                _ => {}
                            };
                            acc
                        });

                        repo.reset_default(Some(&head), to_remove.iter()).unwrap();
                        for change in state.clone().include {
                            let path = Path::new(&change);
                            index.add_path(path).unwrap();
                        }
                        index.write().unwrap();

                        if let Some(event) = state.save_update.clone() {
                            let author = repo.signature().unwrap();
                            index.read(false);
                            let tree_oid = index.write_tree().unwrap();
                            let tree = repo.find_tree(tree_oid).unwrap();
                            repo.commit(Some("HEAD"), &author, &author, &state.message, &tree, &[&head.as_commit().unwrap()]);
                            let message = WebMessage::text(payload::generate(None));
                            sender.send_message(&message).unwrap();
                        } else {
                            let message = WebMessage::text(payload::generate(Some(state)));
                            sender.send_message(&message).unwrap();
                        }
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {}
        }
    }
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        tx.send(NotifierMessage::FsEvent(event));
    }
    observer.join();
}

<|endoftext|>


<commit_before>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use notify::{self, RecommendedWatcher, Watcher};
use std::collections::BTreeMap;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::thread;

pub use luminance::{ProgramError, UniformUpdate};
use luminance::shader::stage;
pub use luminance_gl::gl33::{Program, Uniform};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: GetUni) -> Result<Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else {
        if let Some(gs) = gs {
          Program::new(None, &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(None, &vs, None, &fs, get_uni)
        }
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn read_stage<T, P>(path: P) -> Result<Stage<T>, StageError> where T: ShaderTypeable, P: AsRef<Path> {
  let path = path.as_ref().to_str().unwrap();

  info!("\tloading {:?} stage: \x1b[35m{}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

/// A `Program` wrapped by **ion**.
///
/// That wrapper is used to enable hot-reloading of shader programs.
pub struct WrappedProgram<'a, T> {
  rx: mpsc::Receiver<PathBuf>,
  program: Program<T>,
  get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError> + 'a>,
  vs_path: PathBuf,
  fs_path: PathBuf,
  tess_path: Option<(PathBuf, PathBuf)>,
  gs_path: Option<PathBuf>
}

/// Add surveillance of a given `Program` by providing the path to all its shaders. When a change
/// occurs, the `Program` gets notified of the change via its `Receiver` channel part.
pub fn monitor_shader<P>(tess: &Option<(P, P)>, vs: &P, gs: &Option<P>, fs: &P, sx: mpsc::Sender<PathBuf>) where P: AsRef<Path> + Send + 'static {
  let (wsx, wrx) = mpsc::channel();
  let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

  // vertex shader
  watcher.watch(vs.as_ref());

  // fragment shader
  watcher.watch(fs.as_ref());

  // tessellation, if needed
  if let &Some((ref tcs, ref tes)) = tess {
    // tessellation control shader
    watcher.watch(tcs.as_ref());
    // tessellation evaluation shader
    watcher.watch(tes.as_ref());
  }

  // geometry shader, if needed
  if let &Some(ref gs) = gs {
    watcher.watch(gs.as_ref());
  }

  // start a new monitoring thread
  let _ = thread::spawn(move || {
    loop {
      if let Ok(notify::Event { path: Some(path), op: Ok(notify::op::WRITE) }) = wrx.recv() {
        deb!("{:?}’s content has changed!", path);
        sx.send(path);
      }
    }
  });
}

impl<'a, T> WrappedProgram<'a, T> {
  pub fn new<GetUni, P>(tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Self, ProgramError>
      where GetUni: 'a + Fn(ProgramProxy) -> Result<T, ProgramError> + Clone,
            P: AsRef<Path> + Send + 'static {

    // load vertex and fragment shaders first
    let vs = try!(read_stage(vs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
    let fs = try!(read_stage(fs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

    let program = try!(match (&tess_path, &gs_path) {
      (&None, &None) => { // no tessellation nor geometry
        Program::new(None, &vs, None, &fs, get_uni.clone())
      },
      (&Some((ref tcs_path, ref tes_path)), &None) => { // tessellation without geometry
        let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni.clone())
      },
      (&None, &Some(ref gs_path)) => { // geometry without tessellation
        let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(None, &vs, Some(&gs), &fs, get_uni.clone())
      },
      (&Some((ref tcs_path, ref tes_path)), &Some(ref gs_path)) => { // tessellation and geometry
        let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni.clone())
      }
    });

    let (sx, rx) = mpsc::channel();

    monitor_shader(&tess_path, &vs_path, &gs_path, &fs_path, sx);

    let wrapped = WrappedProgram {
      rx: rx,
      program: program,
      get_uni: Box::new(get_uni),
      vs_path: vs_path.as_ref().to_path_buf(),
      fs_path: fs_path.as_ref().to_path_buf(),
      tess_path: tess_path.map(|(tcs, tes)| (tcs.as_ref().to_path_buf(), tes.as_ref().to_path_buf())),
      gs_path: gs_path.map(|gs| gs.as_ref().to_path_buf())
    };

    Ok(wrapped)
  }

  /// Sync the embedded `Program`.
  pub fn sync(&mut self) {
    if let Ok(path) = self.rx.try_recv() {
      if path == self.vs_path {
        let vs = read_stage(path);
      } else if path == self.fs_path {
      } else if let Some((ref tcs, ref tes)) = self.tess_path {
        if path == *tcs {
        } else if path == *tes {
        }
      } else if Some(path) == self.gs_path {
      }
    }
  }
}
<commit_msg>Fixed errors.<commit_after>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use notify::{self, RecommendedWatcher, Watcher};
use std::collections::BTreeMap;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::thread;

pub use luminance::{ProgramError, UniformUpdate};
use luminance::shader::stage;
pub use luminance_gl::gl33::{Program, Uniform};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: GetUni) -> Result<Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else {
        if let Some(gs) = gs {
          Program::new(None, &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(None, &vs, None, &fs, get_uni)
        }
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn new_program_from_disk<GetUni, T>(tess_path: Option<(&Path, &Path)>, vs_path: &Path, gs_path: Option<&Path>, fs_path: &Path, get_uni: GetUni) -> Result<Program<T>, ProgramError>
      where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> + Clone {
  // load vertex and fragment shaders first
  let vs = try!(read_stage(vs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
  let fs = try!(read_stage(fs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

  match (&tess_path, &gs_path) {
    (&None, &None) => { // no tessellation nor geometry
      Program::new(None, &vs, None, &fs, get_uni.clone())
    },
    (&Some((ref tcs_path, ref tes_path)), &None) => { // tessellation without geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni.clone())
    },
    (&None, &Some(ref gs_path)) => { // geometry without tessellation
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(None, &vs, Some(&gs), &fs, get_uni.clone())
    },
    (&Some((ref tcs_path, ref tes_path)), &Some(ref gs_path)) => { // tessellation and geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni.clone())
    }
  }
}

pub fn read_stage<T>(path: &Path) -> Result<Stage<T>, StageError> where T: ShaderTypeable {
  info!("\tloading {:?} stage: \x1b[35m{:?}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

/// Add surveillance of a given `Program` by providing the path to all its shaders. When a change
/// occurs, the `Program` gets notified of the change via its `Receiver` channel part.
pub fn monitor_shader(tess: Option<(&Path, &Path)>, vs: &Path, gs: Option<&Path>, fs: &Path, sx: mpsc::Sender<()>) {
  let (wsx, wrx) = mpsc::channel();
  let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

  // vertex shader
  watcher.watch(vs);

  // fragment shader
  watcher.watch(fs);

  // tessellation, if needed
  if let Some((tcs, tes)) = tess {
    // tessellation control shader
    watcher.watch(tcs);
    // tessellation evaluation shader
    watcher.watch(tes);
  }

  // geometry shader, if needed
  if let Some(gs) = gs {
    watcher.watch(gs);
  }

  // start a new monitoring thread
  let _ = thread::spawn(move || {
    loop {
      if let Ok(notify::Event { path: Some(path), op: Ok(notify::op::WRITE) }) = wrx.recv() {
        deb!("{:?}’s content has changed!", path);
        sx.send(());
      }
    }
  });
}

/// A `Program` wrapped by **ion**.
///
/// That wrapper is used to enable hot-reloading of shader programs.
pub struct WrappedProgram<'a, T> {
  rx: mpsc::Receiver<()>,
  program: Program<T>,
  get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError> + 'a>,
  vs_path: PathBuf,
  fs_path: PathBuf,
  tess_path: Option<(PathBuf, PathBuf)>,
  gs_path: Option<PathBuf>
}

impl<'a, T> WrappedProgram<'a, T> {
  pub fn new<GetUni>(tess_path: Option<(&Path, &Path)>, vs_path: &Path, gs_path: Option<&Path>, fs_path: &Path, get_uni: GetUni) -> Result<Self, ProgramError>
      where GetUni: 'a + Fn(ProgramProxy) -> Result<T, ProgramError> + Clone {
    let program = try!(new_program_from_disk(tess_path, vs_path, gs_path, fs_path, get_uni.clone()));
    let (sx, rx) = mpsc::channel();

    monitor_shader(tess_path, vs_path, gs_path, fs_path, sx);

    let wrapped = WrappedProgram {
      rx: rx,
      program: program,
      get_uni: Box::new(get_uni),
      vs_path: vs_path.to_path_buf(),
      fs_path: fs_path.to_path_buf(),
      tess_path: tess_path.map(|(tcs, tes)| (tcs.to_path_buf(), tes.to_path_buf())),
      gs_path: gs_path.map(|gs| gs.to_path_buf())
    };

    Ok(wrapped)
  }

  //fn reload(&self mut) {
  //  let program =
  //}

  /// Sync the embedded `Program`.
  pub fn sync(&mut self) {
    if self.rx.try_recv().is_ok() {
    }
  }
}
<|endoftext|>


<commit_before>//! A Simple User interaction
//!
//! Implements a simple type of Q/A.  The question and answer are both text.  It presents the
//! question, waits for the user to press a key, shows the answer, and asks the user how well they
//! did.  Useful when the "answer" is a performance type of action, such as saying something out
//! loud, or playing something on a musical instrument.

use Result;
use Status;
use User;
use timelearn::Problem;

use std::io::{self, stdin, Stdin, stdout, Stdout, Write};
use termion::event::Key;
use termion::input::{Keys, TermRead};
use termion::raw::{IntoRawMode, RawTerminal};

pub struct Simple {
    keys: Keys<Stdin>,
    stdout: RawTerminal<Stdout>,
}

impl Simple {
    pub fn new() -> Result<Simple> {
        Ok(Simple {
            keys: stdin().keys(),
            stdout: stdout().into_raw_mode()?,
        })
    }
}

impl User for Simple {
    fn single(&mut self, word: &Problem) -> Result<Status> {
        write!(self, "Q: {}: ", word.question)?;
        self.flush()?;

        // Wait for a space or escape.
        loop {
            let c = match self.keys.next() {
                None => panic!("End of input"),
                Some(c) => c,
            };
            match c? {
                Key::Esc => return Ok(Status::Stopped),
                Key::Char(' ') => break,
                _ => {}
            }
        }

        write!(self, "\r\n\nQ: {} (1, bad, 4 - good): ", word.answer)?;
        self.flush()?;

        // Wait for the 1-4 answer or escape.
        loop {
            let c = match self.keys.next() {
                None => panic!("End of input"),
                Some(c) => c,
            };
            match c? {
                Key::Esc => return Ok(Status::Stopped),
                Key::Char(x) if x >= '1' && x <= '4' => {
                    let ch = (x as u8) - ('1' as u8) + 1;
                    write!(self, "\r\n(Learned: {})\r\n", ch)?;
                    write!(self, "\r\n\n")?;
                    return Ok(Status::Continue(ch));
                }
                _ => {}
            }
        }
    }
}

impl Write for Simple {
    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // TODO: We could put the '\n' here after we see a return.
        self.stdout.write(buf)
    }
}
<commit_msg>simple: Detect "play" answer<commit_after>//! A Simple User interaction
//!
//! Implements a simple type of Q/A.  The question and answer are both text.  It presents the
//! question, waits for the user to press a key, shows the answer, and asks the user how well they
//! did.  Useful when the "answer" is a performance type of action, such as saying something out
//! loud, or playing something on a musical instrument.

use Result;
use Status;
use User;
use timelearn::Problem;

use std::io::{self, stdin, Stdin, stdout, Stdout, Write};
use termion::event::Key;
use termion::input::{Keys, TermRead};
use termion::raw::{IntoRawMode, RawTerminal};

pub struct Simple {
    keys: Keys<Stdin>,
    stdout: RawTerminal<Stdout>,
}

impl Simple {
    pub fn new() -> Result<Simple> {
        Ok(Simple {
            keys: stdin().keys(),
            stdout: stdout().into_raw_mode()?,
        })
    }
}

impl User for Simple {
    fn single(&mut self, word: &Problem) -> Result<Status> {
        write!(self, "Q: {}: ", word.question)?;
        self.flush()?;

        // If the answer is the string "play", don't wait for space and an answer.
        if word.answer != "play" {
            loop {
                let c = match self.keys.next() {
                    None => panic!("End of input"),
                    Some(c) => c,
                };
                match c? {
                    Key::Esc => return Ok(Status::Stopped),
                    Key::Char(' ') => break,
                    _ => {}
                }
            }
            write!(self, "\r\n\nA: {} (1, bad, 4 - good): ", word.answer)?;
        } else {
            write!(self, "\r\n\n    (1 - bad, 4 - good): ")?;
        }
        self.flush()?;

        // Wait for the 1-4 answer or escape.
        loop {
            let c = match self.keys.next() {
                None => panic!("End of input"),
                Some(c) => c,
            };
            match c? {
                Key::Esc => return Ok(Status::Stopped),
                Key::Char(x) if x >= '1' && x <= '4' => {
                    let ch = (x as u8) - ('1' as u8) + 1;
                    write!(self, "\r\n(Learned: {})\r\n", ch)?;
                    write!(self, "\r\n\n")?;
                    return Ok(Status::Continue(ch));
                }
                _ => {}
            }
        }
    }
}

impl Write for Simple {
    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // TODO: We could put the '\n' here after we see a return.
        self.stdout.write(buf)
    }
}
<|endoftext|>