<commit_before>
extern crate gitlab_api as gitlab;

use std::env;
#[macro_use]
extern crate log;
extern crate env_logger;

use gitlab::GitLab;
// use gitlab::Pagination;
use gitlab::projects;

fn main() {
    env_logger::init().unwrap();
    info!("starting up");

    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

// // Projects
// // List projects
// let projects = gl.projects().list()
// let projects = gl.projects().archived(...).visibility(...).order_by(...).sort(...).search(...).simple(...).list()
// // List all projects (admin)
// let projects = gl.projects().all().list()
// let projects = gl.projects().all().archived(...).visibility(...).order_by(...).sort(...).search(...).list()
// // Single project
// let project = gl.projects().id(142).list()
// // Search
// let projects = gl.projects().search(...).list()
// // Owned
// let projects = gl.projects().owned().archived(...).visibility(...).order_by(...).sort(...).search(...).list()

    let gl = GitLab::new_insecure(&hostname, &token);

    // let projects = gl.projects().list();
    let projects = gl.projects().archived(false).list();
    println!("projects: {:?}", projects);

    // // for i in 1..82 {
    // //     gl.set_pagination(Pagination{page: i, per_page: 1});
    // //     println!("projects: {:?}", gl.projects_list().unwrap());
    // // }
    // // gl.set_pagination(Pagination {
    // //     page: 1,
    // //     per_page: 100,
    // // });
    // let projects = gl.projects_list(projects::Listing::new()).unwrap();
    // println!("projects: {:?}", projects);
    // // FIXME: Project's members are private
    // // for project in projects {
    // //     println!("{:?}", project.path_with_namespace);
    // // }
    //
    // let projects = gl.projects_all(projects::all::Listing::new()).unwrap();
    // println!("projects: {:?}", projects);
    //
    // let listing = projects::id::Listing::new(projects::id::ListingId::Id(10));
    // let projects = gl.project_id(listing).unwrap();
    // println!("projects: {:?}", projects);
}
<commit_msg>Use GitLab::new()<commit_after>
extern crate gitlab_api as gitlab;

use std::env;
#[macro_use]
extern crate log;
extern crate env_logger;

use gitlab::GitLab;
// use gitlab::Pagination;
use gitlab::projects;

fn main() {
    env_logger::init().unwrap();
    info!("starting up");

    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

// // Projects
// // List projects
// let projects = gl.projects().list()
// let projects = gl.projects().archived(...).visibility(...).order_by(...).sort(...).search(...).simple(...).list()
// // List all projects (admin)
// let projects = gl.projects().all().list()
// let projects = gl.projects().all().archived(...).visibility(...).order_by(...).sort(...).search(...).list()
// // Single project
// let project = gl.projects().id(142).list()
// // Search
// let projects = gl.projects().search(...).list()
// // Owned
// let projects = gl.projects().owned().archived(...).visibility(...).order_by(...).sort(...).search(...).list()

    let gl = GitLab::new(&hostname, &token);

    // let projects = gl.projects().list();
    let projects = gl.projects().archived(false).list();
    println!("projects: {:?}", projects);

    // // for i in 1..82 {
    // //     gl.set_pagination(Pagination{page: i, per_page: 1});
    // //     println!("projects: {:?}", gl.projects_list().unwrap());
    // // }
    // // gl.set_pagination(Pagination {
    // //     page: 1,
    // //     per_page: 100,
    // // });
    // let projects = gl.projects_list(projects::Listing::new()).unwrap();
    // println!("projects: {:?}", projects);
    // // FIXME: Project's members are private
    // // for project in projects {
    // //     println!("{:?}", project.path_with_namespace);
    // // }
    //
    // let projects = gl.projects_all(projects::all::Listing::new()).unwrap();
    // println!("projects: {:?}", projects);
    //
    // let listing = projects::id::Listing::new(projects::id::ListingId::Id(10));
    // let projects = gl.project_id(listing).unwrap();
    // println!("projects: {:?}", projects);
}
<|endoftext|>


<commit_before>#[cfg(windows)]
extern crate winapi;

#[cfg(not(windows))]
extern crate psutil;

pub trait ProcAccessor {
    type Item;

    fn enum_processes() -> std::io::Result<Vec<Self::Item>>;
    fn find_process_by_name(process_name : &str) -> Option<Self::Item>;

    fn get_process_name(&self) -> std::io::Result<String>;
}

pub mod sys {

    #[cfg(windows)]
    pub type Proc = crate::process_util::WinProc;
    #[cfg(not(windows))]
    pub type Proc = crate::process_util::LinProc;
}

#[cfg(windows)]
pub struct WinProc {
    pid : u16
}

#[cfg(windows)]
impl WinProc {
    fn str_to_wide(msg : &str) -> Vec<u16> {
        use std::os::windows::ffi::OsStrExt;

        std::ffi::OsStr::new(msg).encode_wide().chain(std::iter::once(0)).collect()
    }

    fn message_box(msg : &str) -> Result<(), std::io::Error> {
        use winapi::um::winuser::{MessageBoxW, MB_OK};

        let msg_wide = str_to_wide(msg);
        let ret = unsafe {
            MessageBoxW(std::ptr::null_mut(), msg_wide.as_ptr(), msg_wide.as_ptr(), MB_OK)
        };

        if ret == 0 {
            Err(std::io::Error::last_os_error())
        }
        else {
            Ok(())
        }
    }
}

#[cfg(windows)]
impl ProcAccessor for WinProc {
    type Item = WinProc;

    pub fn enum_processes() -> std::io::Result<Vec<Item>> {
        use winapi::shared::minwindef::DWORD;
        use winapi::um::psapi::EnumProcesses;

        let mut lpid_processes : [DWORD; 8192] = [0; 8192];
        let mut cb : DWORD = 8192 * std::mem::size_of::<DWORD>() as u32;

        let count = unsafe {
            let lpcb_needed : *mut DWORD = &mut cb;
            EnumProcesses(lpid_processes.as_mut_ptr(), cb, lpcb_needed as *mut DWORD)
        };
        if count == 0 {
            return Err(std::io::Error::last_os_error());
        }

        let mut ret : Vec<T> = Default::default();
        for process_id in lpid_processes.iter() {
            if *process_id != 0 {
                ret.push(WinProc{ pid: *process_id });
            }
        }

        Ok(ret)
    }

    pub fn get_process_name(&self) -> std::io::Result<String> {
        use winapi::um::processthreadsapi::OpenProcess;
        use winapi::um::psapi::{EnumProcessModules, GetModuleBaseNameW};
        use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_VM_READ};
        use winapi::shared::minwindef::{FALSE, HMODULE, DWORD};
        use winapi::shared::ntdef::NULL;

        // open process handle
        let h_process = unsafe {
            OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, self.pid)
        };
        if h_process == NULL {
            return Err(std::io::Error::last_os_error());
        }

        // find a module from process
        /*
        let mut h_module : HMODULE = std::ptr::null_mut();
        let mut cb : DWORD = 1;

        let ret = unsafe {
            let cb_needed : *mut DWORD = &mut cb;
            EnumProcessModules(h_process, h_module as *mut HMODULE, cb, cb_needed as *mut DWORD)
        };
        if ret == FALSE {
            return Err(std::io::Error::last_os_error());
        }
        */

        // get base name
        let mut base_name : [u16; 1024] = [0; 1024];

        let name_len = unsafe {
            //GetModuleBaseNameW(h_process, h_module, base_name.as_mut_ptr() as *mut u16, 1024)
            GetModuleBaseNameW(h_process, std::ptr::null_mut() as HMODULE, base_name.as_mut_ptr() as *mut u16, 1024)
        };
        if name_len == 0 {
            return Err(std::io::Error::last_os_error());
        }

        Ok(String::from_utf16_lossy(&base_name[0..name_len as usize]))
    }

    pub fn find_process_id_by_name(process_name : &str) -> Option<Item> {
        let proc_vec = match enum_processes() {
            Err(_) => { return None; },
            Ok(v) => v
        };

        for proc in proc_vec {
            let pname = match proc.get_process_name() {
                Err(_) => { continue },
                Ok(s) => s.to_ascii_lowercase()
            };

            if pname == process_name.to_ascii_lowercase() {
                return Some(proc.pid);
            }
        }

        None
    }
}

#[cfg(not(windows))]
pub struct LinProc {
    process: psutil::process::Process
}

#[cfg(not(windows))]
impl ProcAccessor for LinProc {
    type Item = LinProc;

    fn enum_processes() -> std::io::Result<Vec<Self::Item>> {
        use psutil::process;
        let mut all_procs : Vec<psutil::process::Process> = psutil::process::all()?;

        let mut ret : Vec<Self::Item> = Default::default();
        for process in all_procs {
            ret.push(LinProc { process: process });
        }

        Ok(ret)
    }

    fn find_process_by_name(process_name : &str) -> Option<Self::Item> {
        use psutil::process;
        let mut all_procs : Vec<psutil::process::Process> = match psutil::process::all() {
            Ok(procs) => procs,
            Err(e) => return None
        };

        for process in all_procs {
            if process.comm.to_ascii_lowercase() == process_name.to_ascii_lowercase() {
                return Some(LinProc { process : process });
            }
        }

        None
    }

    fn get_process_name(&self) -> std::io::Result<String> {
        Ok(self.process.comm.clone())
    }
}

<commit_msg>fix process_util.rs compilation errors in windows<commit_after>#[cfg(windows)]
extern crate winapi;

#[cfg(not(windows))]
extern crate psutil;

pub trait ProcAccessor {
    type Item;

    fn enum_processes() -> std::io::Result<Vec<Self::Item>>;
    fn find_process_by_name(process_name : &str) -> Option<Self::Item>;

    fn get_process_name(&self) -> std::io::Result<String>;
}

pub mod sys {

    #[cfg(windows)]
    pub type Proc = crate::process_util::WinProc;
    #[cfg(not(windows))]
    pub type Proc = crate::process_util::LinProc;
}

#[cfg(windows)]
pub struct WinProc {
    pid : u32
}

#[cfg(windows)]
impl WinProc {
    fn str_to_wide(msg : &str) -> Vec<u16> {
        use std::os::windows::ffi::OsStrExt;

        std::ffi::OsStr::new(msg).encode_wide().chain(std::iter::once(0)).collect()
    }

    fn message_box(msg : &str) -> Result<(), std::io::Error> {
        use winapi::um::winuser::{MessageBoxW, MB_OK};

        let msg_wide = Self::str_to_wide(msg);
        let ret = unsafe {
            MessageBoxW(std::ptr::null_mut(), msg_wide.as_ptr(), msg_wide.as_ptr(), MB_OK)
        };

        if ret == 0 {
            Err(std::io::Error::last_os_error())
        }
        else {
            Ok(())
        }
    }
}

#[cfg(windows)]
impl ProcAccessor for WinProc {
    type Item = WinProc;

    fn enum_processes() -> std::io::Result<Vec<Self::Item>> {
        use winapi::shared::minwindef::DWORD;
        use winapi::um::psapi::EnumProcesses;

        let mut lpid_processes : [DWORD; 8192] = [0; 8192];
        let mut cb : DWORD = 8192 * std::mem::size_of::<DWORD>() as u32;

        let count = unsafe {
            let lpcb_needed : *mut DWORD = &mut cb;
            EnumProcesses(lpid_processes.as_mut_ptr(), cb, lpcb_needed as *mut DWORD)
        };
        if count == 0 {
            return Err(std::io::Error::last_os_error());
        }

        let mut ret : Vec<Self::Item> = Default::default();
        for process_id in lpid_processes.iter() {
            if *process_id != 0 {
                ret.push(WinProc{ pid: *process_id });
            }
        }

        Ok(ret)
    }

    fn get_process_name(&self) -> std::io::Result<String> {
        use winapi::um::processthreadsapi::OpenProcess;
        use winapi::um::psapi::{EnumProcessModules, GetModuleBaseNameW};
        use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_VM_READ};
        use winapi::shared::minwindef::{FALSE, HMODULE, DWORD};
        use winapi::shared::ntdef::NULL;

        // open process handle
        let h_process = unsafe {
            OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, self.pid)
        };
        if h_process == NULL {
            return Err(std::io::Error::last_os_error());
        }

        // find a module from process
        /*
        let mut h_module : HMODULE = std::ptr::null_mut();
        let mut cb : DWORD = 1;

        let ret = unsafe {
            let cb_needed : *mut DWORD = &mut cb;
            EnumProcessModules(h_process, h_module as *mut HMODULE, cb, cb_needed as *mut DWORD)
        };
        if ret == FALSE {
            return Err(std::io::Error::last_os_error());
        }
        */

        // get base name
        let mut base_name : [u16; 1024] = [0; 1024];

        let name_len = unsafe {
            //GetModuleBaseNameW(h_process, h_module, base_name.as_mut_ptr() as *mut u16, 1024)
            GetModuleBaseNameW(h_process, std::ptr::null_mut() as HMODULE, base_name.as_mut_ptr() as *mut u16, 1024)
        };
        if name_len == 0 {
            return Err(std::io::Error::last_os_error());
        }

        Ok(String::from_utf16_lossy(&base_name[0..name_len as usize]))
    }

    fn find_process_id_by_name(process_name : &str) -> Option<Self::Item> {
        let proc_vec = match Self::enum_processes() {
            Err(_) => { return None; },
            Ok(v) => v
        };

        for proc in proc_vec {
            let pname = match proc.get_process_name() {
                Err(_) => { continue },
                Ok(s) => s.to_ascii_lowercase()
            };

            if pname == process_name.to_ascii_lowercase() {
                return Some(proc);
            }
        }

        None
    }
}

#[cfg(not(windows))]
pub struct LinProc {
    process: psutil::process::Process
}

#[cfg(not(windows))]
impl ProcAccessor for LinProc {
    type Item = LinProc;

    fn enum_processes() -> std::io::Result<Vec<Self::Item>> {
        use psutil::process;
        let mut all_procs : Vec<psutil::process::Process> = psutil::process::all()?;

        let mut ret : Vec<Self::Item> = Default::default();
        for process in all_procs {
            ret.push(LinProc { process: process });
        }

        Ok(ret)
    }

    fn find_process_by_name(process_name : &str) -> Option<Self::Item> {
        use psutil::process;
        let mut all_procs : Vec<psutil::process::Process> = match psutil::process::all() {
            Ok(procs) => procs,
            Err(e) => return None
        };

        for process in all_procs {
            if process.comm.to_ascii_lowercase() == process_name.to_ascii_lowercase() {
                return Some(LinProc { process : process });
            }
        }

        None
    }

    fn get_process_name(&self) -> std::io::Result<String> {
        Ok(self.process.comm.clone())
    }
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Extensions to the standard I/O utilities.
//!
//! This module essentially provides useful, RRG-specific utilities that are not
//! available in `std::io`, mostly operating on the standard `Read` and `Write`
//! traits.

use std::io::{Read, Write, Result};

// The same as in the Rust's standard library.
const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// Copies contents of one buffer into the other until a condition is met.
///
/// This function should behave similarly to the standard `std::io::copy` with
/// the difference that it can be given a condition when copying should stop.
///
/// Note that the predicate is not checked after each copied byte. Therefore,
/// there are no guarantees about when exactly and how often it will be called.
///
/// # Errors
///
/// The errors is reported immediately if there is an error when reading from
/// the input or writing to the output.
///
/// Like `std::io::copy`, this function will retry instances of `Interrupted`
/// errors.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
///
/// let mut rand = File::open("/dev/random").unwrap();
/// let mut buf = vec!();
///
/// rrg::io::copy_until(&mut rand, &mut buf, |_, writer| writer.len() >= 1024);
///
/// println!("random bytes: {:?}", buf);
/// ```
pub fn copy_until<R, W, P>(reader: &mut R, writer: &mut W, mut pred: P)
    -> Result<()>
where
    R: Read,
    W: Write,
    P: FnMut(&R, &W) -> bool,
{
    let mut buf = [0; DEFAULT_BUF_SIZE];
    loop {
        if pred(reader, writer) {
            break;
        }

        use std::io::ErrorKind::*;
        let len = match reader.read(&mut buf[..]) {
            Ok(0) => break,
            Ok(len) => len,
            Err(ref error) if error.kind() == Interrupted => continue,
            Err(error) => return Err(error),
        };

        writer.write_all(&buf[..len])?;
    }

    Ok(())
}

/// An reader implementation for a stream of readers.
///
/// It turns a stream of `Read` instances into one `Read` instance where bytes
/// are pulled sequentially from underlying readers. Once the first reader ends,
/// the next one starts to be read and so on.
///
/// # Examples
///
/// ```
/// use std::io::Read as _;
///
/// let items: Vec<&[u8]> = vec!(b"foo", b"bar", b"baz");
/// let mut reader = rrg::io::IterReader::new(items.into_iter());
///
/// let mut buf = vec!();
/// reader.read_to_end(&mut buf).unwrap();
///
/// assert_eq!(buf, b"foobarbaz");
/// ```
pub struct IterReader<I, R> {
    /// Underlying iterator with pending readers.
    iter: I,
    /// Currently active reader.
    curr: Option<R>,
}

impl<I, R> IterReader<I, R>
where
    I: Iterator<Item=R>,
    R: Read,
{
    /// Constructs a new iterator reader.
    pub fn new(iter: I) -> IterReader<I, R> {
        IterReader {
            iter: iter,
            curr: None,
        }
    }
}

impl<I, R> Read for IterReader<I, R>
where
    I: Iterator<Item=R>,
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        loop {
            if self.curr.is_none() {
                self.curr = self.iter.next();
            }

            // If after executing the previous line there is still no current
            // buffer to read from, it means the underlying iterator is finished
            // and there is no more data.
            let curr = match self.curr {
                Some(ref mut buf) => buf,
                None => return Ok(0),
            };

            // If we read 0 bytes from the current buffer, it means it is empty
            // now. By setting it to `None`, we will try to pull a new one in
            // the next iteration.
            match curr.read(buf)? {
                0 => self.curr = None,
                len => return Ok(len),
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_copy_until_with_empty_buffer() {
        let mut reader: &[u8] = b"";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| false).is_ok());
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_begin() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| true).is_ok());
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_end() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| false).is_ok());
        assert_eq!(writer, b"foobar");
    }

    #[test]
    fn test_copy_until_specific_size() {
        let limit = 4 * 1024 * 1024;

        let mut reader = std::io::repeat(0x42);
        let mut writer = vec!();

        // This should verify that copying eventually stops after the condition
        // is met since the reader is infinite.
        assert! {
            copy_until(&mut reader, &mut writer, |_, writer| {
                writer.len() > limit
            }).is_ok()
        };

        assert!(writer.iter().all(|item| *item == 0x42));
        assert!(writer.len() > limit);
    }

    #[test]
    fn test_iter_reader_with_empty_iter() {
        let mut reader = IterReader::new(std::iter::empty::<&[u8]>());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"");
    }

    #[test]
    fn test_iter_reader_with_empty_iter_items() {
        let items: Vec<&[u8]> = vec!(b"", b"", b"");

        let mut reader = IterReader::new(items.into_iter());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"");
    }

    #[test]
    fn test_iter_reader_with_single_iter_item() {
        let items: Vec<&[u8]> = vec!(b"foo");

        let mut reader = IterReader::new(items.into_iter());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"foo");
    }

    #[test]
    fn test_iter_reader_with_multiple_iter_items() {
        let items: Vec<&[u8]> = vec!(b"foo", b"bar", b"baz");

        let mut reader = IterReader::new(items.into_iter());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"foobarbaz");
    }
}
<commit_msg>Return written byte count when copying buffers.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Extensions to the standard I/O utilities.
//!
//! This module essentially provides useful, RRG-specific utilities that are not
//! available in `std::io`, mostly operating on the standard `Read` and `Write`
//! traits.

use std::io::{Read, Write, Result};

// The same as in the Rust's standard library.
const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// Copies contents of one buffer into the other until a condition is met.
///
/// This function should behave similarly to the standard `std::io::copy` with
/// the difference that it can be given a condition when copying should stop.
///
/// On success, the total number of bytes copied from `reader` to `writer` is
/// returned.
///
/// Note that the predicate is not checked after each copied byte. Therefore,
/// there are no guarantees about when exactly and how often it will be called.
///
/// # Errors
///
/// The errors is reported immediately if there is an error when reading from
/// the input or writing to the output.
///
/// Like `std::io::copy`, this function will retry instances of `Interrupted`
/// errors.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
///
/// let mut rand = File::open("/dev/random").unwrap();
/// let mut buf = vec!();
///
/// rrg::io::copy_until(&mut rand, &mut buf, |_, writer| writer.len() >= 1024);
///
/// println!("random bytes: {:?}", buf);
/// ```
pub fn copy_until<R, W, P>(reader: &mut R, writer: &mut W, mut pred: P)
    -> Result<u64>
where
    R: Read,
    W: Write,
    P: FnMut(&R, &W) -> bool,
{
    let mut buf = [0; DEFAULT_BUF_SIZE];
    let mut written = 0;

    loop {
        if pred(reader, writer) {
            break;
        }

        use std::io::ErrorKind::*;
        let len = match reader.read(&mut buf[..]) {
            Ok(0) => break,
            Ok(len) => len,
            Err(ref error) if error.kind() == Interrupted => continue,
            Err(error) => return Err(error),
        };

        writer.write_all(&buf[..len])?;
        written += len as u64;
    }

    Ok(written)
}

/// An reader implementation for a stream of readers.
///
/// It turns a stream of `Read` instances into one `Read` instance where bytes
/// are pulled sequentially from underlying readers. Once the first reader ends,
/// the next one starts to be read and so on.
///
/// # Examples
///
/// ```
/// use std::io::Read as _;
///
/// let items: Vec<&[u8]> = vec!(b"foo", b"bar", b"baz");
/// let mut reader = rrg::io::IterReader::new(items.into_iter());
///
/// let mut buf = vec!();
/// reader.read_to_end(&mut buf).unwrap();
///
/// assert_eq!(buf, b"foobarbaz");
/// ```
pub struct IterReader<I, R> {
    /// Underlying iterator with pending readers.
    iter: I,
    /// Currently active reader.
    curr: Option<R>,
}

impl<I, R> IterReader<I, R>
where
    I: Iterator<Item=R>,
    R: Read,
{
    /// Constructs a new iterator reader.
    pub fn new(iter: I) -> IterReader<I, R> {
        IterReader {
            iter: iter,
            curr: None,
        }
    }
}

impl<I, R> Read for IterReader<I, R>
where
    I: Iterator<Item=R>,
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        loop {
            if self.curr.is_none() {
                self.curr = self.iter.next();
            }

            // If after executing the previous line there is still no current
            // buffer to read from, it means the underlying iterator is finished
            // and there is no more data.
            let curr = match self.curr {
                Some(ref mut buf) => buf,
                None => return Ok(0),
            };

            // If we read 0 bytes from the current buffer, it means it is empty
            // now. By setting it to `None`, we will try to pull a new one in
            // the next iteration.
            match curr.read(buf)? {
                0 => self.curr = None,
                len => return Ok(len),
            }
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_copy_until_with_empty_buffer() {
        let mut reader: &[u8] = b"";
        let mut writer = vec!();

        let result = copy_until(&mut reader, &mut writer, |_, _| false);
        assert_eq!(result.unwrap(), 0);
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_begin() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        let result = copy_until(&mut reader, &mut writer, |_, _| true);
        assert_eq!(result.unwrap(), 0);
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_end() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        let result = copy_until(&mut reader, &mut writer, |_, _| false);
        assert_eq!(result.unwrap(), 6);
        assert_eq!(writer, b"foobar");
    }

    #[test]
    fn test_copy_until_specific_size() {
        let limit = 4 * 1024 * 1024;

        let mut reader = std::io::repeat(0x42);
        let mut writer = vec!();

        // This should verify that copying eventually stops after the condition
        // is met since the reader is infinite.
        assert! {
            copy_until(&mut reader, &mut writer, |_, writer| {
                writer.len() > limit
            }).is_ok()
        };

        assert!(writer.iter().all(|item| *item == 0x42));
        assert!(writer.len() > limit);
    }

    #[test]
    fn test_iter_reader_with_empty_iter() {
        let mut reader = IterReader::new(std::iter::empty::<&[u8]>());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"");
    }

    #[test]
    fn test_iter_reader_with_empty_iter_items() {
        let items: Vec<&[u8]> = vec!(b"", b"", b"");

        let mut reader = IterReader::new(items.into_iter());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"");
    }

    #[test]
    fn test_iter_reader_with_single_iter_item() {
        let items: Vec<&[u8]> = vec!(b"foo");

        let mut reader = IterReader::new(items.into_iter());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"foo");
    }

    #[test]
    fn test_iter_reader_with_multiple_iter_items() {
        let items: Vec<&[u8]> = vec!(b"foo", b"bar", b"baz");

        let mut reader = IterReader::new(items.into_iter());
        let mut buf = vec!();
        reader.read_to_end(&mut buf).unwrap();

        assert_eq!(buf, b"foobarbaz");
    }
}
<|endoftext|>


<commit_before>extern crate clingo;

use std::env;
use clingo::*;

fn print_model(model: &mut Model) {
    // retrieve the symbols in the model
    let atoms = model
        .symbols(&ShowType::SHOWN)
        .expect("Failed to retrieve symbols in the model.");

    print!("Model:");

    for atom in atoms {
        // retrieve and print the symbol's string
        print!(" {}", atom.to_string().unwrap());
    }
    println!();
}

fn solve(ctl: &mut Control) {
    // get a solve handle
    let handle = ctl.solve(&SolveMode::YIELD, &[])
        .expect("Failed retrieving solve handle.");

    // loop over all models
    loop {
        handle.resume().expect("Failed resume on solve handle.");
        match handle.model() {
            // print the model
            Ok(model) => print_model(model),
            // stop if there are no more models
            Err(_) => break,
        }
    }

    // close the solve handle
    let _result = handle
        .get()
        .expect("Failed to get result from solve handle.");
    handle.close().expect("Failed to close solve handle.");
}

fn get_theory_atom_literal(ctl: &mut Control) -> Option<Literal> {
    // get the theory atoms container
    let atoms = ctl.theory_atoms().unwrap();

    // print the number of grounded theory atoms
    let size = atoms.size().unwrap();
    println!("number of grounded theory atoms: {}", size);

    // verify that theory atom b has a guard
    for atom in UNSAFE_TheoryAtomsIterator::from(atoms) {
        // get the term associated with the theory atom
        let term = atoms.atom_term(atom as Id).unwrap();

        // get the name associated with the theory atom
        let name = atoms.term_name(term).unwrap();

        if name == "b" {
            // we got theory atom b/1 here
            let guard = atoms.atom_has_guard(atom as Id).unwrap();
            if guard {
                println!("theory atom b/1 has a guard: true");
            } else {
                println!("theory atom b/1 has a guard: false");
            }
            // get the literal associated with the theory atom
            return Some(atoms.atom_literal(atom as Id).unwrap());
        }
    }
    None
}

fn main() {
    // collect clingo options from the command line
    let options = env::args().skip(1).collect();

    // create a control object and pass command line arguments
    let mut ctl = Control::new(options, 20).expect("Failed creating clingo_control.");

    // add a logic program to the base part
    let parameters: Vec<&str> = Vec::new();
    ctl.add(
        "base",
        parameters,
        "#theory t {\
         term   { + : 1, binary, left };\
         &a/0 : term, any;\
         &b/1 : term, {=}, term, any\
         }.\
         x :- &a { 1+2 }.\
         y :- &b(3) { } = 17.",
    ).expect("Failed to add a logic program.");

    // ground the base part
    let part = Part::new("base", &[]);
    let parts = vec![part];
    ctl.ground(&parts)
        .expect("Failed to ground a logic program.");

    // use the backend to assume that the theory atom is true
    // (note that only symbolic literals can be passed as assumptions to a solve call;
    // the backend accepts any aspif literal)
    if let Some(lit) = get_theory_atom_literal(&mut ctl) {
        // get the backend
        let backend = ctl.backend().unwrap();
        // add the assumption
        backend.assume(&[lit]).expect("Failed to add assumption.");
    }

    // solve
    solve(&mut ctl);
}
<commit_msg>remove unused result variable<commit_after>extern crate clingo;

use std::env;
use clingo::*;

fn print_model(model: &mut Model) {
    // retrieve the symbols in the model
    let atoms = model
        .symbols(&ShowType::SHOWN)
        .expect("Failed to retrieve symbols in the model.");

    print!("Model:");

    for atom in atoms {
        // retrieve and print the symbol's string
        print!(" {}", atom.to_string().unwrap());
    }
    println!();
}

fn solve(ctl: &mut Control) {
    // get a solve handle
    let handle = ctl.solve(&SolveMode::YIELD, &[])
        .expect("Failed retrieving solve handle.");

    // loop over all models
    loop {
        handle.resume().expect("Failed resume on solve handle.");
        match handle.model() {
            // print the model
            Ok(model) => print_model(model),
            // stop if there are no more models
            Err(_) => break,
        }
    }

    // close the solve handle
    handle
        .get()
        .expect("Failed to get result from solve handle.");
    handle.close().expect("Failed to close solve handle.");
}

fn get_theory_atom_literal(ctl: &mut Control) -> Option<Literal> {
    // get the theory atoms container
    let atoms = ctl.theory_atoms().unwrap();

    // print the number of grounded theory atoms
    let size = atoms.size().unwrap();
    println!("number of grounded theory atoms: {}", size);

    // verify that theory atom b has a guard
    for atom in UNSAFE_TheoryAtomsIterator::from(atoms) {
        // get the term associated with the theory atom
        let term = atoms.atom_term(atom as Id).unwrap();

        // get the name associated with the theory atom
        let name = atoms.term_name(term).unwrap();

        if name == "b" {
            // we got theory atom b/1 here
            let guard = atoms.atom_has_guard(atom as Id).unwrap();
            if guard {
                println!("theory atom b/1 has a guard: true");
            } else {
                println!("theory atom b/1 has a guard: false");
            }
            // get the literal associated with the theory atom
            return Some(atoms.atom_literal(atom as Id).unwrap());
        }
    }
    None
}

fn main() {
    // collect clingo options from the command line
    let options = env::args().skip(1).collect();

    // create a control object and pass command line arguments
    let mut ctl = Control::new(options, 20).expect("Failed creating clingo_control.");

    // add a logic program to the base part
    let parameters: Vec<&str> = Vec::new();
    ctl.add(
        "base",
        parameters,
        "#theory t {\
         term   { + : 1, binary, left };\
         &a/0 : term, any;\
         &b/1 : term, {=}, term, any\
         }.\
         x :- &a { 1+2 }.\
         y :- &b(3) { } = 17.",
    ).expect("Failed to add a logic program.");

    // ground the base part
    let part = Part::new("base", &[]);
    let parts = vec![part];
    ctl.ground(&parts)
        .expect("Failed to ground a logic program.");

    // use the backend to assume that the theory atom is true
    // (note that only symbolic literals can be passed as assumptions to a solve call;
    // the backend accepts any aspif literal)
    if let Some(lit) = get_theory_atom_literal(&mut ctl) {
        // get the backend
        let backend = ctl.backend().unwrap();
        // add the assumption
        backend.assume(&[lit]).expect("Failed to add assumption.");
    }

    // solve
    solve(&mut ctl);
}
<|endoftext|>


<commit_before>use gtk::traits::*;
use gtk::widgets;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fs::{self};
use std::fs::metadata;
use std::ops::Deref;
use std::path::{Path, PathBuf};

fn path_sorter(a: &PathBuf, b: &PathBuf) -> Ordering {
    if let Some(a_os_str) = a.deref().file_name() {
        if let Some(b_os_str) = b.deref().file_name() {
            return a_os_str.cmp(&b_os_str);
        }
    }
    Ordering::Equal
}

fn sort_string_paths(paths: &HashSet<String>) -> Vec<PathBuf> {
    let mut paths_vec = Vec::new();
    for path_str in paths.iter() {
        paths_vec.push(PathBuf::from(path_str));
    }
    paths_vec.sort_by(path_sorter);
    paths_vec
}

fn update_project_buttons(ui: &::utils::UI, prefs: &::utils::Prefs) {
    if let Some(path_str) = ::utils::get_selected_path(ui) {
        let is_project = prefs.projects.contains(&path_str);
        let path = Path::new(&path_str);
        ui.rename_button.set_sensitive(!metadata(path).map(|m| m.is_dir()).unwrap_or(false));
        ui.remove_button.set_sensitive(!metadata(path).map(|m| m.is_dir()).unwrap_or(false) || is_project);
    } else {
        ui.rename_button.set_sensitive(false);
        ui.remove_button.set_sensitive(false);
    }
}

fn add_node(ui: &::utils::UI, node: &Path, parent: Option<&widgets::TreeIter>) {
    if let Some(full_path_str) = node.to_str() {
        if let Some(leaf_os_str) = node.file_name() {
            if let Some(leaf_str) = leaf_os_str.to_str() {
                if !leaf_str.starts_with(".") {
                    let iter = ui.tree_store.append(parent);
                    ui.tree_store.set_string(&iter, 0, leaf_str);
                    ui.tree_store.set_string(&iter, 1, full_path_str);

                    if metadata(node).map(|m| m.is_dir()).unwrap_or(false) {
                        match fs::read_dir(node) {
                            Ok(child_iter) => {
                                let mut child_vec = Vec::new();
                                for child in child_iter {
                                    if let Ok(dir_entry) = child {
                                        child_vec.push(dir_entry.path());
                                    }
                                }
                                child_vec.sort_by(path_sorter);
                                for child in child_vec.iter() {
                                    add_node(ui, child.deref(), Some(&iter));
                                }
                            },
                            Err(e) => println!("Error updating tree: {}", e)
                        }
                    }
                }
            }
        }
    }
}

fn expand_nodes(ui: &::utils::UI, prefs: &::utils::Prefs, parent: Option<&widgets::TreeIter>) {
    if let Some(mut iter) = ui.tree_model.iter_children(parent) {
        loop {
            if let Some(path_str) = unsafe { ui.tree_model.get_value(&iter, 1).get_string() } {
                if let Some(selection_str) = prefs.selection.clone() {
                    if path_str == selection_str {
                        if let Some(path) = ui.tree_model.get_path(&iter) {
                            ui.tree.set_cursor(&path, None, false);
                        }
                    }
                }

                if prefs.expansions.contains(&path_str) {
                    if let Some(path) = ui.tree_model.get_path(&iter) {
                        ui.tree.expand_row(&path, false);
                        expand_nodes(ui, prefs, Some(&iter));
                    }
                }
            }

            if !ui.tree_model.iter_next(&mut iter) {
                break;
            }
        }
    }
}

pub fn update_project_tree(ui: &::utils::UI, prefs: &::utils::Prefs) {
    ui.tree_store.clear();

    for path in sort_string_paths(&prefs.projects).iter() {
        add_node(ui, path, None);
    }

    expand_nodes(ui, prefs, None);

    update_project_buttons(ui, prefs);
}
<commit_msg>Improve how paths are compared<commit_after>use gtk::traits::*;
use gtk::widgets;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fs::{self};
use std::fs::metadata;
use std::ops::Deref;
use std::path::{Path, PathBuf};

fn path_sorter(a: &PathBuf, b: &PathBuf) -> Ordering {
    if let Some(a_os_str) = a.deref().file_name() {
        if let Some(b_os_str) = b.deref().file_name() {
            return a_os_str.cmp(&b_os_str);
        }
    }
    Ordering::Equal
}

fn sort_string_paths(paths: &HashSet<String>) -> Vec<PathBuf> {
    let mut paths_vec = Vec::new();
    for path_str in paths.iter() {
        paths_vec.push(PathBuf::from(path_str));
    }
    paths_vec.sort_by(path_sorter);
    paths_vec
}

fn update_project_buttons(ui: &::utils::UI, prefs: &::utils::Prefs) {
    if let Some(path_str) = ::utils::get_selected_path(ui) {
        let is_project = prefs.projects.contains(&path_str);
        let path = Path::new(&path_str);
        ui.rename_button.set_sensitive(!metadata(path).map(|m| m.is_dir()).unwrap_or(false));
        ui.remove_button.set_sensitive(!metadata(path).map(|m| m.is_dir()).unwrap_or(false) || is_project);
    } else {
        ui.rename_button.set_sensitive(false);
        ui.remove_button.set_sensitive(false);
    }
}

fn add_node(ui: &::utils::UI, node: &Path, parent: Option<&widgets::TreeIter>) {
    if let Some(full_path_str) = node.to_str() {
        if let Some(leaf_os_str) = node.file_name() {
            if let Some(leaf_str) = leaf_os_str.to_str() {
                if !leaf_str.starts_with(".") {
                    let iter = ui.tree_store.append(parent);
                    ui.tree_store.set_string(&iter, 0, leaf_str);
                    ui.tree_store.set_string(&iter, 1, full_path_str);

                    if metadata(node).map(|m| m.is_dir()).unwrap_or(false) {
                        match fs::read_dir(node) {
                            Ok(child_iter) => {
                                let mut child_vec = Vec::new();
                                for child in child_iter {
                                    if let Ok(dir_entry) = child {
                                        child_vec.push(dir_entry.path());
                                    }
                                }
                                child_vec.sort_by(path_sorter);
                                for child in child_vec.iter() {
                                    add_node(ui, child.deref(), Some(&iter));
                                }
                            },
                            Err(e) => println!("Error updating tree: {}", e)
                        }
                    }
                }
            }
        }
    }
}

fn expand_nodes(ui: &::utils::UI, prefs: &::utils::Prefs, parent: Option<&widgets::TreeIter>) {
    if let Some(mut iter) = ui.tree_model.iter_children(parent) {
        loop {
            if let Some(path_str) = unsafe { ui.tree_model.get_value(&iter, 1).get_string() } {
                if let Some(selection_str) = prefs.selection.clone() {
                    if Path::new(&path_str) == Path::new(&selection_str) {
                        if let Some(path) = ui.tree_model.get_path(&iter) {
                            ui.tree.set_cursor(&path, None, false);
                        }
                    }
                }

                if prefs.expansions.contains(&path_str) {
                    if let Some(path) = ui.tree_model.get_path(&iter) {
                        ui.tree.expand_row(&path, false);
                        expand_nodes(ui, prefs, Some(&iter));
                    }
                }
            }

            if !ui.tree_model.iter_next(&mut iter) {
                break;
            }
        }
    }
}

pub fn update_project_tree(ui: &::utils::UI, prefs: &::utils::Prefs) {
    ui.tree_store.clear();

    for path in sort_string_paths(&prefs.projects).iter() {
        add_node(ui, path, None);
    }

    expand_nodes(ui, prefs, None);

    update_project_buttons(ui, prefs);
}
<|endoftext|>


<commit_before>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// Licensed under the Apache License, version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     <http://www.apache.org/licenses/LICENSE-2.0>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use unicode_width::*;
use term::terminfo::TermInfo;

use std::collections::HashMap;
use std::borrow::Borrow;
use std::fmt::Write;
use std::iter::FromIterator;
use std::sync::Arc;

use std::cmp;

use constants::*;
use error::*;

#[derive(PartialEq, Clone, Debug)]
pub enum TermStack {
    // here for correctness
    #[allow(dead_code)]
    Str(String),
    Int(isize),
    // here for correctness
    #[allow(dead_code)]
    Bool(bool),
}

pub struct Line {
    line: Arc<String>,
}

pub struct Escape {
    strings: HashMap<String, String>,
}

pub struct Matches {
    matches: Vec<Line>,
}

impl FromIterator<Arc<String>> for Matches {
    fn from_iter<T>(matches: T) -> Matches
        where T: IntoIterator<Item = Arc<String>>
    {
        Matches { matches: matches.into_iter().map(|item| Line::new(item)).collect() }
    }
}

impl Matches {
    pub fn len(&self) -> usize {
        self.matches.len()
    }

    pub fn get(&self, selected: usize) -> Option<&Line> {
        self.matches.get(selected)
    }

    pub fn render(&self, width: usize, selected: usize) -> String {
        let mut result = format!("");

        for (i, line) in self.matches.iter().enumerate() {
            trysp!(write!(result, "{}", line.render(Some(width), i == selected)),
                   "Writes to strings should not fail");
        }

        result
    }
}

impl Line {
    pub fn new(line: Arc<String>) -> Line {
        Line { line: line }
    }

    pub fn get(&self) -> &String {
        self.line.borrow()
    }

    pub fn render(&self, width: Option<usize>, selected: bool) -> String {
        let mut result;

        if selected {
            result = format!("{}{}{}", MATCH_PRE, MATCH_SELECT, self.line);
        } else {
            result = format!("{}{}", MATCH_PRE, self.line);
        }

        width.map(|size| {
            while UnicodeWidthStr::width(result.as_str()) > size {
                result.pop();
            }
        });

        result
    }
}

impl Escape {
    pub fn create() -> StrResult<Escape> {
        let info = trys!(TermInfo::from_env(), "Failed to get TermInfo");
        let mut strings = HashMap::default();

        for (name, value) in info.strings.into_iter() {
            strings.insert(name, trys!(String::from_utf8(value), "value was not utf-8"));
        }

        Ok(Escape { strings: strings })
    }

    fn cursor_up(&self, by: usize) -> String {
        self.get_string("cuu", vec![TermStack::Int(by as isize)])
            .unwrap_or(format!(""))
    }

    pub fn restore_cursor(&self) -> String {
        self.get_string("rc", vec![]).unwrap_or(format!(""))
    }

    pub fn save_cursor(&self) -> String {
        self.get_string("sc", vec![]).unwrap_or(format!(""))
    }

    pub fn clear_screen(&self) -> String {
        self.get_string("clr_eos", vec![]).unwrap_or(format!(""))
    }

    pub fn make_space(&self, rows: usize) -> String {
        let number = cmp::min(MATCH_NUMBER, rows - 1);
        format!("{}{}",
                String::from_iter(vec!['\n'; number as usize].into_iter()),
                self.cursor_up(number))
    }

    pub fn move_back(&self, by: usize) -> String {
        format!("{}{}{}",
                self.get_string("cub", vec![TermStack::Int(by as isize)])
                    .unwrap_or(format!("")),
                self.save_cursor(),
                self.clear_screen())
    }

    pub fn query_output(&self, chr: char) -> String {
        format!("{}{}{}", chr, self.save_cursor(), self.clear_screen())
    }

    pub fn matches_output(&self, matches: &Matches, width: usize, selected: usize) -> String {
        format!("{}{}{}",
                self.clear_screen(),
                matches.render(width, selected),
                self.restore_cursor())
    }

    pub fn match_down(&self, matches: &Matches, width: usize, selected: usize) -> String {
        // this gets us to the first match
        let mut result = format!("");

        // move down to the line before the last selection
        trysp!(write!(result,
                      "{}",
                      String::from_iter(vec!['\n'; selected - 1].into_iter())),
               "Writes to strings should not fail");

        // render the last line as non-selected
        match matches.get(selected - 1) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected - 1);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), false),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // render the next line as selected
        match matches.get(selected) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), true),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // restore the cursor
        trysp!(write!(result, "{}", self.restore_cursor()),
               "Writes to strings should not fail");

        // return the result
        result
    }

    pub fn match_up(&self, matches: &Matches, width: usize, selected: usize) -> String {
        // this gets us to the first match
        let mut result = format!("");

        // move down to the line before the last selection
        trysp!(write!(result,
                      "{}",
                      String::from_iter(vec!['\n'; selected].into_iter())),
               "Writes to strings should not fail");

        // render the last line as selected
        match matches.get(selected) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), true),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // render the next line as selected
        match matches.get(selected + 1) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected + 1);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), false),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // restore the cursor
        trysp!(write!(result, "{}", self.restore_cursor()),
               "Writes to strings should not fail");

        // return the result
        result
    }

    pub fn best_match_output(&self, matches: &Matches, selected: usize, recent: bool) -> String {
        matches.get(selected).map_or(format!("\n{}", self.clear_screen()), |line| {
            if recent {
                format!("recent{}{}\n{}", FINISH, line.get(), self.clear_screen())
            } else {
                format!("{}{}\n{}", FINISH, line.get(), self.clear_screen())
            }
        })
    }

    pub fn render_prompt(&self, rows: usize) -> String {
        format!("{}{}{}", self.make_space(rows), PROMPT, self.save_cursor())
    }

    pub fn bell(&self) -> String {
        format!("{}", BEL)
    }

    fn get_string<T: Borrow<str>>(&self, name: T, params: Vec<TermStack>) -> Option<String> {
        // only implement what we're actually using in the UI
        let sequence = match self.strings.get(name.borrow()) {
            None => {
                trace!("No match for string: {:?}", name.borrow());
                return None;
            }
            Some(s) => {
                trace!("Matched string: {:?}", s);
                s.clone()
            }
        };

        let mut escaped = false;
        let mut stack: Vec<TermStack> = vec![];
        let mut result = String::default();
        let mut escape = String::default();

        // only implement the sequences we care about

        for c in sequence.chars() {
            if !escaped {
                if c == '%' {
                    escaped = true;
                } else {
                    result.push(c);
                }
            } else if escape.is_empty() {
                if c == 'd' {
                    match stack.pop() {
                        Some(TermStack::Int(c)) => {
                            result.push_str(format!("{}", c).as_ref());
                        }
                        Some(o) => {
                            error!("Numeric print on non-numeric type: {:?}", o);
                        }
                        None => {
                            error!("Stack was empty on print");
                        }
                    }
                    escaped = false;
                } else if c == 'p' {
                    escape.push('p');
                } else {
                    error!("Unknown escape character: {:?}", c);
                    escaped = false;
                }
            } else {
                if escape == "p" {
                    match c.to_digit(10) {
                        Some(idx) => {
                            if idx != 0 {
                                match params.get(idx as usize - 1) {
                                    Some(item) => stack.push(item.clone()),
                                    None => {
                                        error!("There was no parameter {}", idx);
                                    }
                                }
                            } else {
                                error!("Tried to print 0th paramater");
                            }
                        }
                        None => {
                            error!("Paramater number was not a digit");
                        }
                    }

                    escape.clear();
                    escaped = false;
                } else {
                    error!("Unknown escape sequence: {:?}", escape);
                    escape.clear();
                    escaped = false;
                }
            }
        }

        trace!("Returning result: {:?}", result);

        // return result
        Some(result)
    }
}
<commit_msg>Clear screen on draw prompt<commit_after>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// Licensed under the Apache License, version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     <http://www.apache.org/licenses/LICENSE-2.0>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use unicode_width::*;
use term::terminfo::TermInfo;

use std::collections::HashMap;
use std::borrow::Borrow;
use std::fmt::Write;
use std::iter::FromIterator;
use std::sync::Arc;

use std::cmp;

use constants::*;
use error::*;

#[derive(PartialEq, Clone, Debug)]
pub enum TermStack {
    // here for correctness
    #[allow(dead_code)]
    Str(String),
    Int(isize),
    // here for correctness
    #[allow(dead_code)]
    Bool(bool),
}

pub struct Line {
    line: Arc<String>,
}

pub struct Escape {
    strings: HashMap<String, String>,
}

pub struct Matches {
    matches: Vec<Line>,
}

impl FromIterator<Arc<String>> for Matches {
    fn from_iter<T>(matches: T) -> Matches
        where T: IntoIterator<Item = Arc<String>>
    {
        Matches { matches: matches.into_iter().map(|item| Line::new(item)).collect() }
    }
}

impl Matches {
    pub fn len(&self) -> usize {
        self.matches.len()
    }

    pub fn get(&self, selected: usize) -> Option<&Line> {
        self.matches.get(selected)
    }

    pub fn render(&self, width: usize, selected: usize) -> String {
        let mut result = format!("");

        for (i, line) in self.matches.iter().enumerate() {
            trysp!(write!(result, "{}", line.render(Some(width), i == selected)),
                   "Writes to strings should not fail");
        }

        result
    }
}

impl Line {
    pub fn new(line: Arc<String>) -> Line {
        Line { line: line }
    }

    pub fn get(&self) -> &String {
        self.line.borrow()
    }

    pub fn render(&self, width: Option<usize>, selected: bool) -> String {
        let mut result;

        if selected {
            result = format!("{}{}{}", MATCH_PRE, MATCH_SELECT, self.line);
        } else {
            result = format!("{}{}", MATCH_PRE, self.line);
        }

        width.map(|size| {
            while UnicodeWidthStr::width(result.as_str()) > size {
                result.pop();
            }
        });

        result
    }
}

impl Escape {
    pub fn create() -> StrResult<Escape> {
        let info = trys!(TermInfo::from_env(), "Failed to get TermInfo");
        let mut strings = HashMap::default();

        for (name, value) in info.strings.into_iter() {
            strings.insert(name, trys!(String::from_utf8(value), "value was not utf-8"));
        }

        Ok(Escape { strings: strings })
    }

    fn cursor_up(&self, by: usize) -> String {
        self.get_string("cuu", vec![TermStack::Int(by as isize)])
            .unwrap_or(format!(""))
    }

    pub fn restore_cursor(&self) -> String {
        self.get_string("rc", vec![]).unwrap_or(format!(""))
    }

    pub fn save_cursor(&self) -> String {
        self.get_string("sc", vec![]).unwrap_or(format!(""))
    }

    pub fn clear_screen(&self) -> String {
        self.get_string("clr_eos", vec![]).unwrap_or(format!(""))
    }

    pub fn make_space(&self, rows: usize) -> String {
        let number = cmp::min(MATCH_NUMBER, rows - 1);
        format!("{}{}",
                String::from_iter(vec!['\n'; number as usize].into_iter()),
                self.cursor_up(number))
    }

    pub fn move_back(&self, by: usize) -> String {
        format!("{}{}{}",
                self.get_string("cub", vec![TermStack::Int(by as isize)])
                    .unwrap_or(format!("")),
                self.save_cursor(),
                self.clear_screen())
    }

    pub fn query_output(&self, chr: char) -> String {
        format!("{}{}{}", chr, self.save_cursor(), self.clear_screen())
    }

    pub fn matches_output(&self, matches: &Matches, width: usize, selected: usize) -> String {
        format!("{}{}{}",
                self.clear_screen(),
                matches.render(width, selected),
                self.restore_cursor())
    }

    pub fn match_down(&self, matches: &Matches, width: usize, selected: usize) -> String {
        // this gets us to the first match
        let mut result = format!("");

        // move down to the line before the last selection
        trysp!(write!(result,
                      "{}",
                      String::from_iter(vec!['\n'; selected - 1].into_iter())),
               "Writes to strings should not fail");

        // render the last line as non-selected
        match matches.get(selected - 1) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected - 1);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), false),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // render the next line as selected
        match matches.get(selected) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), true),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // restore the cursor
        trysp!(write!(result, "{}", self.restore_cursor()),
               "Writes to strings should not fail");

        // return the result
        result
    }

    pub fn match_up(&self, matches: &Matches, width: usize, selected: usize) -> String {
        // this gets us to the first match
        let mut result = format!("");

        // move down to the line before the last selection
        trysp!(write!(result,
                      "{}",
                      String::from_iter(vec!['\n'; selected].into_iter())),
               "Writes to strings should not fail");

        // render the last line as selected
        match matches.get(selected) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), true),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // render the next line as selected
        match matches.get(selected + 1) {
            None => {
                // no such match, do nothing
                debug!("No such match: {}", selected + 1);
                return format!("");
            }
            Some(line) => {
                trysp!(write!(result,
                              "{}{}",
                              line.render(Some(width), false),
                              self.get_string("clr_eol", vec![]).unwrap_or(format!(""))),
                       "Writes to strings should not fail");
            }
        }

        // restore the cursor
        trysp!(write!(result, "{}", self.restore_cursor()),
               "Writes to strings should not fail");

        // return the result
        result
    }

    pub fn best_match_output(&self, matches: &Matches, selected: usize, recent: bool) -> String {
        matches.get(selected).map_or(format!("\n{}", self.clear_screen()), |line| {
            if recent {
                format!("recent{}{}\n{}", FINISH, line.get(), self.clear_screen())
            } else {
                format!("{}{}\n{}", FINISH, line.get(), self.clear_screen())
            }
        })
    }

    pub fn render_prompt(&self, rows: usize) -> String {
        format!("{}{}{}{}", self.make_space(rows), PROMPT, self.save_cursor(), self.clear_screen())
    }

    pub fn bell(&self) -> String {
        format!("{}", BEL)
    }

    fn get_string<T: Borrow<str>>(&self, name: T, params: Vec<TermStack>) -> Option<String> {
        // only implement what we're actually using in the UI
        let sequence = match self.strings.get(name.borrow()) {
            None => {
                trace!("No match for string: {:?}", name.borrow());
                return None;
            }
            Some(s) => {
                trace!("Matched string: {:?}", s);
                s.clone()
            }
        };

        let mut escaped = false;
        let mut stack: Vec<TermStack> = vec![];
        let mut result = String::default();
        let mut escape = String::default();

        // only implement the sequences we care about

        for c in sequence.chars() {
            if !escaped {
                if c == '%' {
                    escaped = true;
                } else {
                    result.push(c);
                }
            } else if escape.is_empty() {
                if c == 'd' {
                    match stack.pop() {
                        Some(TermStack::Int(c)) => {
                            result.push_str(format!("{}", c).as_ref());
                        }
                        Some(o) => {
                            error!("Numeric print on non-numeric type: {:?}", o);
                        }
                        None => {
                            error!("Stack was empty on print");
                        }
                    }
                    escaped = false;
                } else if c == 'p' {
                    escape.push('p');
                } else {
                    error!("Unknown escape character: {:?}", c);
                    escaped = false;
                }
            } else {
                if escape == "p" {
                    match c.to_digit(10) {
                        Some(idx) => {
                            if idx != 0 {
                                match params.get(idx as usize - 1) {
                                    Some(item) => stack.push(item.clone()),
                                    None => {
                                        error!("There was no parameter {}", idx);
                                    }
                                }
                            } else {
                                error!("Tried to print 0th paramater");
                            }
                        }
                        None => {
                            error!("Paramater number was not a digit");
                        }
                    }

                    escape.clear();
                    escaped = false;
                } else {
                    error!("Unknown escape sequence: {:?}", escape);
                    escape.clear();
                    escaped = false;
                }
            }
        }

        trace!("Returning result: {:?}", result);

        // return result
        Some(result)
    }
}
<|endoftext|>


<commit_before>use regex::Regex;

struct HtmlResponseHandler {
	raw_content: String,
}

impl HtmlResponseHandler {
	pub fn new(content: &str) -> HtmlResponseHandler {
		HtmlResponseHandler{
			raw_content: Self::compact(content),
		}
	}

	fn compact(what: &str) -> String {
		let regices = [
			(Regex::new(r#"\s+"#).unwrap(), " "),
			(Regex::new(r#">\s<"#).unwrap(), "><"),
			(Regex::new(r#"\s/>"#).unwrap(), "/>"),
			(Regex::new(r#"\s?\{\s?"#).unwrap(), "{"),
			(Regex::new(r#"\s?\}\s?"#).unwrap(), "}"),
		];

		regices.iter().fold(what.to_string(), |curr, ref tpl| tpl.0.replace_all(&curr[..], &tpl.1[..]))
	}
}
<commit_msg>Add encoding algorithm selection<commit_after>use hyper::header::{Headers, Encoding, AcceptEncoding};
use regex::Regex;

struct HtmlResponseHandler {
	raw_content: String,
}

impl HtmlResponseHandler {
	pub fn new(content: &str) -> HtmlResponseHandler {
		HtmlResponseHandler{
			raw_content: Self::compact(content),
		}
	}

	fn compact(what: &str) -> String {
		let regices = [
			(Regex::new(r#"\s+"#).unwrap(), " "),
			(Regex::new(r#">\s<"#).unwrap(), "><"),
			(Regex::new(r#"\s/>"#).unwrap(), "/>"),
			(Regex::new(r#"\s?\{\s?"#).unwrap(), "{"),
			(Regex::new(r#"\s?\}\s?"#).unwrap(), "}"),
		];

		regices.iter().fold(what.to_string(), |curr, ref tpl| tpl.0.replace_all(&curr[..], &tpl.1[..]))
	}

	fn encode_algo(headers: &Headers) -> Encoding {
		match headers.get::<AcceptEncoding>() {
			Some(&AcceptEncoding(ref encodings)) => {
				let mut encodings = encodings.clone();
				encodings.sort_by(|ref qil, ref qir| qil.quality.cmp(&qir.quality));

				let mut ret = Encoding::Identity;
				for enc in encodings {
					match enc.item {
						Encoding::Gzip => {
							ret = Encoding::Gzip;
							break;
						},
						Encoding::Deflate => {
							ret = Encoding::Deflate;
							break;
						},
						_ => (),
					}
				}
				ret
			},
			None => Encoding::Identity,
		}
	}
}
<|endoftext|>


<commit_before>use std::io::Result;
use std::collections::HashMap;
use std::cmp::{Eq, PartialEq};
use std::hash::{Hash, Hasher, SipHasher};

type Pixels = usize;
type FileName = String;
type FilePath = String;

#[derive(Clone, Eq, PartialEq, Hash)]
enum ResolutionUnits {
    PixelsPerInch,
    PixelsPerCentimeter,
}

#[derive(Clone, Eq, PartialEq, Hash)]
enum Direction {
    Horizonal,
    Vertical,
}

#[derive(Clone, Eq, PartialEq, Hash)]
enum ImageFileFormat {
    TIFF,
    PNG,
    JPEG,
    UNKNOWN,
}

#[derive(Clone, Eq, PartialEq, Hash)]
struct ImageDimensions {
    xPixels: Pixels,
    yPixels: Pixels,
}

#[derive(Clone, Eq, PartialEq, Hash)]
struct ImageResolution {
    amount: Pixels,
    units: ResolutionUnits,
}

impl ImageResolution {
    fn new(amount: usize, units: ResolutionUnits) -> ImageResolution {
        ImageResolution {
            amount: amount,
            units: units,
        }
    }
}

#[derive(Clone)]
enum PageOps {
    Identify(FilePath),
    Rescale(Pixels, Direction),
    ExpandLeftEdge(Pixels),
    ExpandRightEdge(Pixels),
    ExpandTopEdge(Pixels),
    ExpandBottomEdge(Pixels),
    TrimLeftEdge(Pixels),
    TrimRightEdge(Pixels),
    TrimTopEdge(Pixels),
    TrimBottomEdge(Pixels),
    SetResolution(ImageResolution),
}

trait ElementaryPageOperations {
    fn identify(path: &FilePath)               -> Result<String>;
    fn rescale(amount: Pixels, dir: Direction) -> Result<String>;
    fn expand_left_edge(amount: Pixels)        -> Result<String>;
    fn expand_right_edge(amount: Pixels)       -> Result<String>;
    fn expand_top_edge(amount: Pixels)         -> Result<String>;
    fn expand_bottom_edge(amount: Pixels)      -> Result<String>;
    fn trim_left_edge(amount: Pixels)          -> Result<String>;
    fn trim_right_edge(amount: Pixels)         -> Result<String>;
    fn trim_top_edge(amount: Pixels)           -> Result<String>;
    fn trim_bottom_edge(amount: Pixels)        -> Result<String>;
    fn set_resolution(res: ImageResolution)    -> Result<String>;
}

impl ElementaryPageOperations {

}

struct CompoundPageOperation {
    page_name: FileName,
    page_path: FilePath,
    ops: Vec<PageOps>,
}

impl CompoundPageOperation {
    fn new(page_name: FileName, page_path: FilePath, ops: &[PageOps]) -> CompoundPageOperation {
        unimplemented!();
    }

    fn run_operation(&self) -> Result<String> {
        unimplemented!();
    }
}

#[derive(Eq)]
struct Page {
    file_name: FileName,
    file_extension: ImageFileFormat,
    file_path: FilePath,
    dimensions: ImageDimensions,
    resolution: ImageResolution,
}

impl Page {
    fn new  (
                file_name: FileName,
                file_extension: ImageFileFormat,
                file_path: FilePath,
                dimensions: ImageDimensions,
                resolution: ImageResolution
            ) -> Page
    {
        Page {
            file_name: file_name,
            file_extension: file_extension,
            file_path: file_path,
            dimensions: dimensions,
            resolution: resolution,
        }
    }
}

impl PartialEq for Page {
    fn eq(&self, other: &Page) -> bool {
            self.file_name == other.file_name
        &&  self.file_extension == other.file_extension
        &&  self.file_path == other.file_path
        &&  self.dimensions == other.dimensions
        &&  self.resolution == other.resolution
    }
}

impl Hash for Page {
    fn hash<H>(&self, state: &mut H)
        where H: Hasher {

        self.file_name.hash(state);
        self.file_extension.hash(state);
        self.file_path.hash(state);
        self.dimensions.hash(state);
        self.resolution.hash(state);
    }
}

struct OperationSchedule {
    schedule: HashMap<Page, CompoundPageOperation>,
}
/*
struct OperationResult {
    // Results from each page operation
}
*/
impl OperationSchedule {
    fn new() -> Self {
        OperationSchedule {
            schedule: HashMap::new(),
        }
    }
    /*
    fn run_schedule(schedule: OperationSchedule) -> OperationResult {
        unimplemented!();
    }
    */
}

<commit_msg>Implement run_operation for ElementaryPageOperations.<commit_after>use std::io::Result;
use std::collections::HashMap;
use std::cmp::{Eq, PartialEq};
use std::hash::{Hash, Hasher, SipHasher};

type Pixels = usize;
type FileName = String;
type FilePath = String;

#[derive(Clone, Eq, PartialEq, Hash)]
enum ResolutionUnits {
    PixelsPerInch,
    PixelsPerCentimeter,
}

#[derive(Clone, Eq, PartialEq, Hash)]
enum Direction {
    Horizonal,
    Vertical,
}

#[derive(Clone, Eq, PartialEq, Hash)]
enum ImageFileFormat {
    TIFF,
    PNG,
    JPEG,
    UNKNOWN,
}

#[derive(Clone, Eq, PartialEq, Hash)]
struct ImageDimensions {
    xPixels: Pixels,
    yPixels: Pixels,
}

#[derive(Clone, Eq, PartialEq, Hash)]
struct ImageResolution {
    amount: Pixels,
    units: ResolutionUnits,
}

impl ImageResolution {
    fn new(amount: usize, units: ResolutionUnits) -> ImageResolution {
        ImageResolution {
            amount: amount,
            units: units,
        }
    }
}

#[derive(Clone)]
enum PageOps {
    Identify(FilePath),
    Rescale(Pixels, Direction),
    ExpandLeftEdge(Pixels),
    ExpandRightEdge(Pixels),
    ExpandTopEdge(Pixels),
    ExpandBottomEdge(Pixels),
    TrimLeftEdge(Pixels),
    TrimRightEdge(Pixels),
    TrimTopEdge(Pixels),
    TrimBottomEdge(Pixels),
    SetResolution(ImageResolution),
}

trait ElementaryPageOperations {
    fn identify(path: FilePath)                -> Result<String>;
    fn rescale(amount: Pixels, dir: Direction) -> Result<String>;
    fn expand_left_edge(amount: Pixels)        -> Result<String>;
    fn expand_right_edge(amount: Pixels)       -> Result<String>;
    fn expand_top_edge(amount: Pixels)         -> Result<String>;
    fn expand_bottom_edge(amount: Pixels)      -> Result<String>;
    fn trim_left_edge(amount: Pixels)          -> Result<String>;
    fn trim_right_edge(amount: Pixels)         -> Result<String>;
    fn trim_top_edge(amount: Pixels)           -> Result<String>;
    fn trim_bottom_edge(amount: Pixels)        -> Result<String>;
    fn set_resolution(res: ImageResolution)    -> Result<String>;
}

impl ElementaryPageOperations {
    fn run_operation<Op>(page_op: PageOps) -> Result<String>
        where Op: ElementaryPageOperations {

        match page_op {
            PageOps::Identify(path)           => Op::identify(path),
            PageOps::Rescale(amount, dir)     => Op::rescale(amount, dir),
            PageOps::ExpandLeftEdge(amount)   => Op::expand_left_edge(amount),
            PageOps::ExpandRightEdge(amount)  => Op::expand_right_edge(amount),
            PageOps::ExpandTopEdge(amount)    => Op::expand_top_edge(amount),
            PageOps::ExpandBottomEdge(amount) => Op::expand_bottom_edge(amount),
            PageOps::TrimLeftEdge(amount)     => Op::trim_left_edge(amount),
            PageOps::TrimRightEdge(amount)    => Op::trim_right_edge(amount),
            PageOps::TrimTopEdge(amount)      => Op::trim_top_edge(amount),
            PageOps::TrimBottomEdge(amount)   => Op::trim_bottom_edge(amount),
            PageOps::SetResolution(res)       => Op::set_resolution(res),
        }
    }
}

struct CompoundPageOperation {
    page_name: FileName,
    page_path: FilePath,
    ops: Vec<PageOps>,
}

impl CompoundPageOperation {
    fn new(page_name: FileName, page_path: FilePath, ops: &[PageOps]) -> CompoundPageOperation {
        unimplemented!();
    }

    fn run_operation(&self) -> Result<String> {
        unimplemented!();
    }
}

#[derive(Eq)]
struct Page {
    file_name: FileName,
    file_extension: ImageFileFormat,
    file_path: FilePath,
    dimensions: ImageDimensions,
    resolution: ImageResolution,
}

impl Page {
    fn new  (
                file_name: FileName,
                file_extension: ImageFileFormat,
                file_path: FilePath,
                dimensions: ImageDimensions,
                resolution: ImageResolution
            ) -> Page
    {
        Page {
            file_name: file_name,
            file_extension: file_extension,
            file_path: file_path,
            dimensions: dimensions,
            resolution: resolution,
        }
    }
}

impl PartialEq for Page {
    fn eq(&self, other: &Page) -> bool {
            self.file_name == other.file_name
        &&  self.file_extension == other.file_extension
        &&  self.file_path == other.file_path
        &&  self.dimensions == other.dimensions
        &&  self.resolution == other.resolution
    }
}

impl Hash for Page {
    fn hash<H>(&self, state: &mut H)
        where H: Hasher {

        self.file_name.hash(state);
        self.file_extension.hash(state);
        self.file_path.hash(state);
        self.dimensions.hash(state);
        self.resolution.hash(state);
    }
}

struct OperationSchedule {
    schedule: HashMap<Page, CompoundPageOperation>,
}

struct OperationResult {
    results: Vec<Result<String>>,
}

impl OperationSchedule {
    fn new() -> Self {
        OperationSchedule {
            schedule: HashMap::new(),
        }
    }

    fn run_schedule(schedule: OperationSchedule) -> OperationResult {
        unimplemented!();
    }

}

<|endoftext|>


<commit_before>//! Applies pooling to the input.
//!
//! This layers looks at adjectant values of the input and then computes a
//! simple pooling operation over them (e.g. taking their maximum or average value).
//! *See [PoolingMode][pooling_mode]*
//!
//! [pooling_mode]: ./enum.PoolingMode.html
//!
//! ## Input Data
//!
//! The layer expects the input to be in either 4D NCHW (2 spatial dimensions)
//! or 5D NCDHW (3 spatial dimensions) format.
use std::rc::Rc;
use co::{IBackend, SharedTensor};
use co::plugin::Float;
use conn;
use layer::*;
use util::{ArcLock, cast_vec_usize_to_i32};
use super::FilterLayer;

#[derive(Debug, Clone)]
/// [Pooling](./index.html) Layer
pub struct Pooling<T: Float, B: conn::Pooling<T>> {
    mode: PoolingMode,

    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    pooling_configs: Vec<Rc<B::CPOOL>>,
}

impl<T: Float, B: conn::Pooling<T>> Pooling<T, B> {
    /// Create a Pooling layer from a PoolingConfig.
    pub fn from_config(config: &PoolingConfig) -> Pooling<T, B> {
        Pooling {
            mode: config.mode,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            pooling_configs: vec![],
        }
    }
}

impl<T: Float, B: conn::Pooling<T>> FilterLayer for Pooling<T, B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            5 => 3,
            _ => panic!("A pooling layer currently only supports 4D or 5D input.")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..2].to_vec() {
            output_shape.push(*dim);
        }
        println!("FILTER SHAPE 1 {:?}", output_shape);
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }
        println!("FILTER OUT SHAPE {:?}", output_shape);

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Pooling<f32>> ILayer<B> for Pooling<f32, B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data[0].write().unwrap().resize(&output_shape).unwrap();
            output_gradient[0].write().unwrap().resize(&output_shape).unwrap();

            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let filter = cast_vec_usize_to_i32(self.spatial_filter_dims(num_spatial_dims));
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            let config = backend.new_pooling_config(&filter, &padding, &stride).unwrap();
            self.pooling_configs.push(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeOutput<f32, B> for Pooling<f32, B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_plain(input_data[0], output_data[0], &*config).unwrap(),
            // TODO: implement average pooling
            // PoolingMode::Average => unimplemented!(),
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeInputGradient<f32, B> for Pooling<f32, B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              _weights_data: &[&SharedTensor<f32>],
                              output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_grad_plain(output_data[0], output_gradients[0], input_data[0], input_gradients[0], config).unwrap()
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeParametersGradient<f32, B> for Pooling<f32, B> { }

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Pooling Layer.
pub struct PoolingConfig {
    /// The PoolingMode to use
    pub mode: PoolingMode,
    /// The shape of the filter
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
}

#[derive(Debug, Copy, Clone)]
/// The different modes of pooling that can be calculated.
pub enum PoolingMode {
    /// The maximum value inside the pooling window will be used as result.
    Max,
    // /// The average of all values inside the pooling window will be used as result.
    // Average,
}
<commit_msg>Auto merge of #51 - autumnai:chore/cleanup, r=hobofan<commit_after>//! Applies pooling to the input.
//!
//! This layers looks at adjectant values of the input and then computes a
//! simple pooling operation over them (e.g. taking their maximum or average value).
//! *See [PoolingMode][pooling_mode]*
//!
//! [pooling_mode]: ./enum.PoolingMode.html
//!
//! ## Input Data
//!
//! The layer expects the input to be in either 4D NCHW (2 spatial dimensions)
//! or 5D NCDHW (3 spatial dimensions) format.
use std::rc::Rc;
use co::{IBackend, SharedTensor};
use co::plugin::Float;
use conn;
use layer::*;
use util::{ArcLock, cast_vec_usize_to_i32};
use super::FilterLayer;

#[derive(Debug, Clone)]
/// [Pooling](./index.html) Layer
pub struct Pooling<T: Float, B: conn::Pooling<T>> {
    mode: PoolingMode,

    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    pooling_configs: Vec<Rc<B::CPOOL>>,
}

impl<T: Float, B: conn::Pooling<T>> Pooling<T, B> {
    /// Create a Pooling layer from a PoolingConfig.
    pub fn from_config(config: &PoolingConfig) -> Pooling<T, B> {
        Pooling {
            mode: config.mode,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            pooling_configs: vec![],
        }
    }
}

impl<T: Float, B: conn::Pooling<T>> FilterLayer for Pooling<T, B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            5 => 3,
            _ => panic!("A pooling layer currently only supports 4D or 5D input.")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..2].to_vec() {
            output_shape.push(*dim);
        }
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Pooling<f32>> ILayer<B> for Pooling<f32, B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data[0].write().unwrap().resize(&output_shape).unwrap();
            output_gradient[0].write().unwrap().resize(&output_shape).unwrap();

            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let filter = cast_vec_usize_to_i32(self.spatial_filter_dims(num_spatial_dims));
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            let config = backend.new_pooling_config(&filter, &padding, &stride).unwrap();
            self.pooling_configs.push(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeOutput<f32, B> for Pooling<f32, B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_plain(input_data[0], output_data[0], &*config).unwrap(),
            // TODO: implement average pooling
            // PoolingMode::Average => unimplemented!(),
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeInputGradient<f32, B> for Pooling<f32, B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              _weights_data: &[&SharedTensor<f32>],
                              output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_grad_plain(output_data[0], output_gradients[0], input_data[0], input_gradients[0], config).unwrap()
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeParametersGradient<f32, B> for Pooling<f32, B> { }

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Pooling Layer.
pub struct PoolingConfig {
    /// The PoolingMode to use
    pub mode: PoolingMode,
    /// The shape of the filter
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
}

#[derive(Debug, Copy, Clone)]
/// The different modes of pooling that can be calculated.
pub enum PoolingMode {
    /// The maximum value inside the pooling window will be used as result.
    Max,
    // /// The average of all values inside the pooling window will be used as result.
    // Average,
}
<|endoftext|>