<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File as FSFile;
use std::ops::Deref;
use std::io::Write;
use std::io::Read;

pub mod path;
pub mod file;
pub mod parser;
pub mod json;

use module::Module;
use storage::file::File;
use storage::file::id::FileID;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use storage::parser::{FileHeaderParser, Parser};
use storage::file::header::data::FileHeaderData;

type Cache = HashMap<FileID, Rc<RefCell<File>>>;

pub struct Store {
    storepath: String,
    cache : RefCell<Cache>,
}

/**
 * Store object
 *
 * This object is an abstraction layer over FS and an interface to the object store of this
 * software.
 */
impl Store {

    pub fn new(storepath: String) -> Store {
        Store {
            storepath: storepath,
            cache: RefCell::new(HashMap::new()),
        }
    }

    /**
     * Put a file into the cache
     */
    fn put_in_cache(&self, f: File) -> FileID {
        let res = f.id().clone();
        self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f)));
        res
    }

    /**
     * Generate a new file for a module.
     *
     * Returns the new FileID object then
     */
    pub fn new_file(&self, module: &Module)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: String::from(""),
            id: self.get_new_file_id(),
        };

        debug!("Create new File object: {:?}", &f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file from a parser result.
     *
     * @deprecated This function shouldn't be needed anymore
     */
    pub fn new_file_from_parser_result(&self,
                                       module: &Module,
                                       id: FileID,
                                       header: FileHeaderData,
                                       data: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file for a module, providing some header data
     *
     * Returns the new FileID object then
     */
    pub fn new_file_with_header(&self,
                                module: &Module,
                                h: FileHeaderData)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: String::from(""),
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file for a module, providing some initial data
     *
     * Returns the new FileID object then
     */
    pub fn new_file_with_data(&self, module: &Module, d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file for a module, providing some initial data and some header
     *
     * Returns the new FileID object then
     */
    pub fn new_file_with_content(&self,
                                 module: &Module,
                                 h: FileHeaderData,
                                 d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Persist a File on the filesystem
     *
     * Returns true if this worked
     */
    pub fn persist<HP>(&self,
                       p: &Parser<HP>,
                       f: Rc<RefCell<File>>) -> bool
        where HP: FileHeaderParser
    {
        let file = f.deref().borrow();
        let text = p.write(file.contents());
        if text.is_err() {
            error!("Error: {}", text.err().unwrap());
            return false;
        }

        let path = {
            let ids : String = file.id().clone().into();
            format!("{}/{}-{}.imag", self.storepath, file.owning_module_name, ids)
        };

        self.ensure_store_path_exists();

        FSFile::create(&path).map(|mut fsfile| {
            fsfile.write_all(&text.unwrap().clone().into_bytes()[..])
        }).map_err(|writeerr|  {
            debug!("Could not create file at '{}'", path);
            debug!("    error: {:?}", writeerr);
        }).and(Ok(true)).unwrap()

        // TODO: Is this unwrap() save?
    }

    /**
     * Helper to generate the store path
     *
     * Kills the program if it fails
     */
    fn ensure_store_path_exists(&self) {
        use std::fs::create_dir_all;
        use std::process::exit;

        create_dir_all(&self.storepath).unwrap_or_else(|e| {
            error!("Could not create store: '{}'", self.storepath);
            error!("Error                 : '{}'", e);
            error!("Killing myself now");
            exit(1);
        })
    }

    /**
     * Load a file by ID into the cache and return it afterwards
     *
     * Returns None if the file could be loaded from the Filesystem
     */
    fn load_into_cache<HP>(&self, m: &Module, parser: &Parser<HP>, id: &FileID)
        -> bool
        where HP: FileHeaderParser
    {
        let idstr : String = id.clone().into();
        let path = format!("{}/{}-{}.imag", self.storepath, m.name(), idstr);
        debug!("Loading path = '{}'", path);
        let mut string = String::new();

        FSFile::open(&path).map(|mut file| {
            file.read_to_string(&mut string)
                .map_err(|e| {
                    error!("Failed reading file: '{}'", path);
                    debug!("    error {}", e);
                })
                .is_ok();
        })
        .map_err(|e| {
            error!("Error opening file: {}", path);
            debug!("Error opening file: {:?}", e);
        }).ok();

        parser.read(string).map(|(header, data)| {
            self.new_file_from_parser_result(m, id.clone(), header, data);
            true
        }).unwrap_or(false)
    }

    /**
     * Load a file from the cache by FileID
     *
     * TODO: Semantics: This function should load from FS if the file is not in the cache yet or
     * fail if the file is not available.
     */
    pub fn load<HP>(&self, m: &Module, parser: &Parser<HP>, id: &FileID)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        if !self.cache.borrow().contains_key(id) {
            self.load_into_cache(m, parser, id);
        }
        debug!("Loading '{:?}'", id);
        self.cache.borrow().get(id).cloned()
    }

    /**
     * Load a file from the filesystem/cache by a FileHash
     */
    pub fn load_by_hash<HP>(&self,
                            m: &Module,
                            parser: &Parser<HP>,
                            hash: FileHash)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        macro_rules! try_some {
            ($expr:expr) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return ::std::option::Option::None,
            });

            ($expr:expr => return) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return,
            })
        }

        use glob::glob;

        let hashstr : String = hash.into();
        let globstr = format!("{}/*-{}.imag", self.storepath, hashstr);
        debug!("glob({})", globstr);

        let globs = glob(&globstr[..]);
        if globs.is_err() {
            return None;
        }

        let path = globs.unwrap().last();
        debug!("path = {:?}", path);

        let pathbuf = try_some!(path);
        if pathbuf.is_err() { return None; }

        let pathbuf_un  = pathbuf.unwrap();
        let filename    = pathbuf_un.file_name();
        let s           = try_some!(filename).to_str();
        let string      = String::from(try_some!(s));
        let id          = try_some!(FileID::parse(&string));

        debug!("Loaded ID = '{:?}'", id);

        self.load(m, parser, &id)
    }

    /**
     * Load all files for a module
     */
    pub fn load_for_module<HP>(&self, m: &Module, parser: &Parser<HP>)
        -> Vec<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        use glob::glob;

        let globstr = format!("{}/{}-*.imag", self.storepath, m.name());
        let mut res = vec![];

        glob(&globstr[..]).map(|paths| {
            for path in paths {
                if let Ok(pathbuf) = path {
                    let fname = pathbuf.file_name().and_then(|s| s.to_str());
                    fname.map(|s| {
                        FileID::parse(&String::from(s)).map(|id| {
                            self.load(m, parser, &id).map(|file| {
                                res.push(file);
                            })
                        });
                    });
                }
            }
        });
        res
    }

    /**
     * Remove a file from the filesystem by FileID
     *
     * Returns true if this works.
     */
    pub fn remove(&self, id: FileID) -> bool {
        use std::fs::remove_file;

        self.cache
            .borrow_mut()
            .remove(&id)
            .map(|file| {
                let idstr : String = id.into();
                let path = format!("{}/{}-{}.imag",
                                   self.storepath,
                                   file.deref().borrow().owner_name(),
                                   idstr);
                debug!("Removing file NOW: '{}'", path);
                remove_file(path).is_ok()
            })
            .unwrap_or(false)
    }

    /**
     * Helper to generate a new FileID object
     */
    fn get_new_file_id(&self) -> FileID {
        use uuid::Uuid;
        let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
        FileID::new(FileIDType::UUID, hash)
    }

}
<commit_msg>Use unused return value: On glob() error, print error msg<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File as FSFile;
use std::ops::Deref;
use std::io::Write;
use std::io::Read;

pub mod path;
pub mod file;
pub mod parser;
pub mod json;

use module::Module;
use storage::file::File;
use storage::file::id::FileID;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use storage::parser::{FileHeaderParser, Parser};
use storage::file::header::data::FileHeaderData;

type Cache = HashMap<FileID, Rc<RefCell<File>>>;

pub struct Store {
    storepath: String,
    cache : RefCell<Cache>,
}

/**
 * Store object
 *
 * This object is an abstraction layer over FS and an interface to the object store of this
 * software.
 */
impl Store {

    pub fn new(storepath: String) -> Store {
        Store {
            storepath: storepath,
            cache: RefCell::new(HashMap::new()),
        }
    }

    /**
     * Put a file into the cache
     */
    fn put_in_cache(&self, f: File) -> FileID {
        let res = f.id().clone();
        self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f)));
        res
    }

    /**
     * Generate a new file for a module.
     *
     * Returns the new FileID object then
     */
    pub fn new_file(&self, module: &Module)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: String::from(""),
            id: self.get_new_file_id(),
        };

        debug!("Create new File object: {:?}", &f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file from a parser result.
     *
     * @deprecated This function shouldn't be needed anymore
     */
    pub fn new_file_from_parser_result(&self,
                                       module: &Module,
                                       id: FileID,
                                       header: FileHeaderData,
                                       data: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file for a module, providing some header data
     *
     * Returns the new FileID object then
     */
    pub fn new_file_with_header(&self,
                                module: &Module,
                                h: FileHeaderData)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: String::from(""),
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file for a module, providing some initial data
     *
     * Returns the new FileID object then
     */
    pub fn new_file_with_data(&self, module: &Module, d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Generate a new file for a module, providing some initial data and some header
     *
     * Returns the new FileID object then
     */
    pub fn new_file_with_content(&self,
                                 module: &Module,
                                 h: FileHeaderData,
                                 d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        self.put_in_cache(f)
    }

    /**
     * Persist a File on the filesystem
     *
     * Returns true if this worked
     */
    pub fn persist<HP>(&self,
                       p: &Parser<HP>,
                       f: Rc<RefCell<File>>) -> bool
        where HP: FileHeaderParser
    {
        let file = f.deref().borrow();
        let text = p.write(file.contents());
        if text.is_err() {
            error!("Error: {}", text.err().unwrap());
            return false;
        }

        let path = {
            let ids : String = file.id().clone().into();
            format!("{}/{}-{}.imag", self.storepath, file.owning_module_name, ids)
        };

        self.ensure_store_path_exists();

        FSFile::create(&path).map(|mut fsfile| {
            fsfile.write_all(&text.unwrap().clone().into_bytes()[..])
        }).map_err(|writeerr|  {
            debug!("Could not create file at '{}'", path);
            debug!("    error: {:?}", writeerr);
        }).and(Ok(true)).unwrap()

        // TODO: Is this unwrap() save?
    }

    /**
     * Helper to generate the store path
     *
     * Kills the program if it fails
     */
    fn ensure_store_path_exists(&self) {
        use std::fs::create_dir_all;
        use std::process::exit;

        create_dir_all(&self.storepath).unwrap_or_else(|e| {
            error!("Could not create store: '{}'", self.storepath);
            error!("Error                 : '{}'", e);
            error!("Killing myself now");
            exit(1);
        })
    }

    /**
     * Load a file by ID into the cache and return it afterwards
     *
     * Returns None if the file could be loaded from the Filesystem
     */
    fn load_into_cache<HP>(&self, m: &Module, parser: &Parser<HP>, id: &FileID)
        -> bool
        where HP: FileHeaderParser
    {
        let idstr : String = id.clone().into();
        let path = format!("{}/{}-{}.imag", self.storepath, m.name(), idstr);
        debug!("Loading path = '{}'", path);
        let mut string = String::new();

        FSFile::open(&path).map(|mut file| {
            file.read_to_string(&mut string)
                .map_err(|e| {
                    error!("Failed reading file: '{}'", path);
                    debug!("    error {}", e);
                })
                .is_ok();
        })
        .map_err(|e| {
            error!("Error opening file: {}", path);
            debug!("Error opening file: {:?}", e);
        }).ok();

        parser.read(string).map(|(header, data)| {
            self.new_file_from_parser_result(m, id.clone(), header, data);
            true
        }).unwrap_or(false)
    }

    /**
     * Load a file from the cache by FileID
     *
     * TODO: Semantics: This function should load from FS if the file is not in the cache yet or
     * fail if the file is not available.
     */
    pub fn load<HP>(&self, m: &Module, parser: &Parser<HP>, id: &FileID)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        if !self.cache.borrow().contains_key(id) {
            self.load_into_cache(m, parser, id);
        }
        debug!("Loading '{:?}'", id);
        self.cache.borrow().get(id).cloned()
    }

    /**
     * Load a file from the filesystem/cache by a FileHash
     */
    pub fn load_by_hash<HP>(&self,
                            m: &Module,
                            parser: &Parser<HP>,
                            hash: FileHash)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        macro_rules! try_some {
            ($expr:expr) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return ::std::option::Option::None,
            });

            ($expr:expr => return) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return,
            })
        }

        use glob::glob;

        let hashstr : String = hash.into();
        let globstr = format!("{}/*-{}.imag", self.storepath, hashstr);
        debug!("glob({})", globstr);

        let globs = glob(&globstr[..]);
        if globs.is_err() {
            return None;
        }

        let path = globs.unwrap().last();
        debug!("path = {:?}", path);

        let pathbuf = try_some!(path);
        if pathbuf.is_err() { return None; }

        let pathbuf_un  = pathbuf.unwrap();
        let filename    = pathbuf_un.file_name();
        let s           = try_some!(filename).to_str();
        let string      = String::from(try_some!(s));
        let id          = try_some!(FileID::parse(&string));

        debug!("Loaded ID = '{:?}'", id);

        self.load(m, parser, &id)
    }

    /**
     * Load all files for a module
     */
    pub fn load_for_module<HP>(&self, m: &Module, parser: &Parser<HP>)
        -> Vec<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        use glob::glob;

        let globstr = format!("{}/{}-*.imag", self.storepath, m.name());
        let mut res = vec![];

        glob(&globstr[..]).map(|paths| {
            for path in paths {
                if let Ok(pathbuf) = path {
                    let fname = pathbuf.file_name().and_then(|s| s.to_str());
                    fname.map(|s| {
                        FileID::parse(&String::from(s)).map(|id| {
                            self.load(m, parser, &id).map(|file| {
                                res.push(file);
                            })
                        });
                    });
                }
            }
        })
        .map_err(|e| {
            error!("Could not glob: '{}'", globstr);
            debug!("Could not glob(): {:?}", e);
        })
        .ok();
        res
    }

    /**
     * Remove a file from the filesystem by FileID
     *
     * Returns true if this works.
     */
    pub fn remove(&self, id: FileID) -> bool {
        use std::fs::remove_file;

        self.cache
            .borrow_mut()
            .remove(&id)
            .map(|file| {
                let idstr : String = id.into();
                let path = format!("{}/{}-{}.imag",
                                   self.storepath,
                                   file.deref().borrow().owner_name(),
                                   idstr);
                debug!("Removing file NOW: '{}'", path);
                remove_file(path).is_ok()
            })
            .unwrap_or(false)
    }

    /**
     * Helper to generate a new FileID object
     */
    fn get_new_file_id(&self) -> FileID {
        use uuid::Uuid;
        let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
        FileID::new(FileIDType::UUID, hash)
    }

}
<|endoftext|>


<commit_before>use std::str::from_utf8;

use parser::ArgumentParser;

pub fn check_ok(ap: &ArgumentParser, args: &[&str]) {
    let mut stdout = Vec::<u8>::new();
    let mut stderr = Vec::<u8>::new();
    let mut owned_args = Vec::new();
    for x in args.iter() {
        owned_args.push(x.to_string());
    }
    let res = ap.parse(owned_args, &mut stdout, &mut stderr);
    match res {
        Ok(()) => return,
        Err(x) => panic!(
            String::from_utf8(stderr).unwrap() +
            &format!("Expected ok, but found Exit({})", x)[..]),
    }
}

pub fn check_exit(ap: &ArgumentParser, args: &[&str]) {
    let mut stdout = Vec::<u8>::new();
    let mut stderr = Vec::<u8>::new();
    let mut owned_args = Vec::new();
    for x in args.iter() {
        owned_args.push(x.to_string());
    }
    let res = ap.parse(owned_args, &mut stdout, &mut stderr);
    match res {
        Err(0) => return,
        Err(x) => panic!(format!("Expected code {} got {}", 0usize, x)),
        Ok(()) => panic!(format!("Expected failure, got success")),
    }
}

pub fn check_err(ap: &ArgumentParser, args: &[&str]) {
    let mut stdout = Vec::<u8>::new();
    let mut stderr = Vec::<u8>::new();
    let mut owned_args = Vec::new();
    for x in args.iter() {
        owned_args.push(x.to_string());
    }
    let res = ap.parse(owned_args, &mut stdout, &mut stderr);
    match res {
        Err(2) => return,
        Err(x) => panic!(format!("Expected code {} got {}", 2usize, x)),
        Ok(()) => panic!(format!("Expected failure, got success")),
    }
}

#[test]
fn test_no_arg() {
    let ap = ArgumentParser::new();
    check_ok(&ap, &["./argparse_test"]);
    check_err(&ap, &["./argparse_test", "a"]);
    check_err(&ap, &["./argparse_test", "-a"]);
    check_err(&ap, &["./argparse_test", "--an-option"]);
}

#[test]
fn test_help() {
    let ap = ArgumentParser::new();
    check_ok(&ap, &["./argparse_test"]);
    check_exit(&ap, &["./argparse_test", "--help"]);
}
<commit_msg>Remove unused use statement<commit_after>
use parser::ArgumentParser;

pub fn check_ok(ap: &ArgumentParser, args: &[&str]) {
    let mut stdout = Vec::<u8>::new();
    let mut stderr = Vec::<u8>::new();
    let mut owned_args = Vec::new();
    for x in args.iter() {
        owned_args.push(x.to_string());
    }
    let res = ap.parse(owned_args, &mut stdout, &mut stderr);
    match res {
        Ok(()) => return,
        Err(x) => panic!(
            String::from_utf8(stderr).unwrap() +
            &format!("Expected ok, but found Exit({})", x)[..]),
    }
}

pub fn check_exit(ap: &ArgumentParser, args: &[&str]) {
    let mut stdout = Vec::<u8>::new();
    let mut stderr = Vec::<u8>::new();
    let mut owned_args = Vec::new();
    for x in args.iter() {
        owned_args.push(x.to_string());
    }
    let res = ap.parse(owned_args, &mut stdout, &mut stderr);
    match res {
        Err(0) => return,
        Err(x) => panic!(format!("Expected code {} got {}", 0usize, x)),
        Ok(()) => panic!(format!("Expected failure, got success")),
    }
}

pub fn check_err(ap: &ArgumentParser, args: &[&str]) {
    let mut stdout = Vec::<u8>::new();
    let mut stderr = Vec::<u8>::new();
    let mut owned_args = Vec::new();
    for x in args.iter() {
        owned_args.push(x.to_string());
    }
    let res = ap.parse(owned_args, &mut stdout, &mut stderr);
    match res {
        Err(2) => return,
        Err(x) => panic!(format!("Expected code {} got {}", 2usize, x)),
        Ok(()) => panic!(format!("Expected failure, got success")),
    }
}

#[test]
fn test_no_arg() {
    let ap = ArgumentParser::new();
    check_ok(&ap, &["./argparse_test"]);
    check_err(&ap, &["./argparse_test", "a"]);
    check_err(&ap, &["./argparse_test", "-a"]);
    check_err(&ap, &["./argparse_test", "--an-option"]);
}

#[test]
fn test_help() {
    let ap = ArgumentParser::new();
    check_ok(&ap, &["./argparse_test"]);
    check_exit(&ap, &["./argparse_test", "--help"]);
}
<|endoftext|>


<commit_before>//! # Toolbar, Scrollable Text View and File Chooser
//!
//! A simple text file viewer

#![feature(core)]

extern crate gtk;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::num::FromPrimitive;

use gtk::traits::*;
use gtk::signal::Inhibit;

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    window.set_title("Text File Viewer");
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(400, 300);

    let toolbar = gtk::Toolbar::new().unwrap();

    let open_icon = gtk::Image::new_from_icon_name("document-open", gtk::IconSize::SmallToolbar).unwrap();
    let text_view = gtk::TextView::new().unwrap();

    let open_button = gtk::ToolButton::new::<gtk::Image>(Some(&open_icon), Some("Open")).unwrap();
    open_button.set_is_important(true);

    toolbar.add(&open_button);

    let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll.set_policy(gtk::PolicyType::Automatic, gtk::PolicyType::Automatic);
    scroll.add(&text_view);

    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    vbox.pack_start(&toolbar, false, true, 0);
    vbox.pack_start(&scroll, true, true, 0);

    window.add(&vbox);

    open_button.connect_clicked(move |_| {
        // TODO move this to a impl?
        let file_chooser = gtk::FileChooserDialog::new(
            "Open File", None, gtk::FileChooserAction::Open,
            [("Open", gtk::ResponseType::Ok), ("Cancel", gtk::ResponseType::Cancel)]);
        let response: Option<gtk::ResponseType> = FromPrimitive::from_i32(file_chooser.run());

        match response {
            Some(gtk::ResponseType::Ok) => {
                let filename = file_chooser.get_filename().unwrap();
                let file = File::open(&filename).unwrap();

                let mut reader = BufReader::new(file);
                let mut contents = String::new();
                let _ = reader.read_to_string(&mut contents);

                text_view.get_buffer().unwrap().set_text(&contents);
            },
            _ => {}
        };

        file_chooser.destroy();
    });

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    window.show_all();
    gtk::main();
}
<commit_msg>Avoid using FromPrimitive<commit_after>//! # Toolbar, Scrollable Text View and File Chooser
//!
//! A simple text file viewer

extern crate gtk;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use gtk::traits::*;
use gtk::signal::Inhibit;

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    window.set_title("Text File Viewer");
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(400, 300);

    let toolbar = gtk::Toolbar::new().unwrap();

    let open_icon = gtk::Image::new_from_icon_name("document-open", gtk::IconSize::SmallToolbar).unwrap();
    let text_view = gtk::TextView::new().unwrap();

    let open_button = gtk::ToolButton::new::<gtk::Image>(Some(&open_icon), Some("Open")).unwrap();
    open_button.set_is_important(true);

    toolbar.add(&open_button);

    let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll.set_policy(gtk::PolicyType::Automatic, gtk::PolicyType::Automatic);
    scroll.add(&text_view);

    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    vbox.pack_start(&toolbar, false, true, 0);
    vbox.pack_start(&scroll, true, true, 0);

    window.add(&vbox);

    open_button.connect_clicked(move |_| {
        // TODO move this to a impl?
        let file_chooser = gtk::FileChooserDialog::new(
            "Open File", None, gtk::FileChooserAction::Open,
            [("Open", gtk::ResponseType::Ok), ("Cancel", gtk::ResponseType::Cancel)]);
        if file_chooser.run() == gtk::ResponseType::Ok as i32 {
            let filename = file_chooser.get_filename().unwrap();
            let file = File::open(&filename).unwrap();

            let mut reader = BufReader::new(file);
            let mut contents = String::new();
            let _ = reader.read_to_string(&mut contents);

            text_view.get_buffer().unwrap().set_text(&contents);
        }

        file_chooser.destroy();
    });

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>use std::boxed::FnBox;
use std::thread::{self, spawn};
use std::sync::mpsc::{channel, Sender, SendError, Receiver, TryRecvError};
use std::error::Error;
use std::fmt;

trait Runner {
    fn run(self: Box<Self>);
}

impl <F: FnBox()> Runner for F {
    fn run(self: Box<F>) {
        self.call_box(())
    }
}

/// Type used by ThreadPool to run closures, etc. on the spawned threads.
pub type Proc<'a> = Box<Runner + Send + 'a>;

/// Used to interact with the spawned threads returned by the ThreadPool.
///
/// See documentation for ThreadPool for more information.
pub struct Thread {
    inner: ThreadInner,
}

struct ThreadInner {
    sender: Sender<Proc<'static>>,
    result: Receiver<thread::Result<()>>,
}

impl Thread {
    fn new(sender: Sender<Proc<'static>>, result: Receiver<thread::Result<()>>) -> Thread {
        Thread {
            inner: ThreadInner {
                       sender: sender,
                       result: result,
                   },
        }
    }

    /// Sends the runnable object to a spawned thread to be run.
    pub fn start(&self, f: Proc<'static>) -> Result<(), SendError<Proc<'static>>> {
        self.inner.sender.send(f)
    }

    /// Blocks on the result of the started Proc.
    ///
    /// Do not use if no Proc is being run!
    pub fn join(&self) -> thread::Result<()> {
        self.inner.result.recv().expect("Could not get result")
    }
}

/// The ThreadPool that manages the state of the threads and spawns new ones.
///
/// ```
/// #![feature(box_syntax)]
/// #![feature(result_expect)]
/// use std::sync::mpsc::channel;
/// use ferrous_threads::thread_pool::ThreadPool;
///
/// let mut pool = ThreadPool::new(1, 2);
/// let thread = pool.thread().unwrap();
///
/// let (sn, rc) = channel();
/// thread.start(box move || { sn.send(9u8).unwrap();}).expect("Could not send Proc");
/// assert!(thread.join().is_ok());
/// assert!(rc.recv().unwrap() == 9u8);
/// ```
pub struct ThreadPool {
    free_sender: Sender<Thread>, // Keep this to spawn new threads
    free_threads: Receiver<Thread>, // Threads will send themselves when they are free.
    active_threads: usize,
    max_threads: usize,
}

fn spawn_thread(free: Sender<Thread>) {
        spawn(move || {
            let sentinel = Sentinel::new(free.clone());
            ThreadRunner::new(free).run();
            sentinel.done();
        });
}

impl ThreadPool {
    pub fn new(init_threads: usize, max_threads: usize) -> ThreadPool {
        let (sn, rc) = channel();
        let mut thrs = Vec::new();
        for _i in 0..init_threads {
            spawn_thread(sn.clone());
            let thr = rc.recv().expect("Could not receive initial thread");
            thrs.push(thr);
        }

        for t in thrs.into_iter() {
            sn.send(t).expect("Could not reinsert threads");
        }

        ThreadPool {
            free_sender: sn,
            free_threads: rc,
            active_threads: init_threads,
            max_threads: max_threads
        }
    }

    /// Returns a handle to a spawned thread or an error if there are no more threads available.
    pub fn thread(&mut self) -> Result<Thread, ThreadError> {
        let mut res = Err(TryRecvError::Disconnected);
        for _i in 0..9 {
            res = self.free_threads.try_recv();
            if res.is_ok() {
                break
            }
        }

        match res {
            Ok(thr) => Ok(thr),
            Err(TryRecvError::Empty) => {
                if self.active_threads >= self.max_threads {
                    Err(ThreadError)
                } else {
                    self.active_threads += 1;
                    spawn_thread(self.free_sender.clone());
                    let thr = self.free_threads.recv().expect("Could not receive thread");
                    Ok(thr)
                }
            }
            Err(TryRecvError::Disconnected) => panic!("channel closed"),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ThreadError;

impl Error for ThreadError {
    fn description(&self) -> &str {
        "Could not make any more threads."
    }
}

impl fmt::Display for ThreadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "Could not make any more threads.".fmt(f)
    }
}

struct Sentinel {
    free_threads: Sender<Thread>,
    active: bool,
}

// Idea taken from https://github.com/rust-lang/threadpool/blob/b9416b4cb591a3ac8bac8efef19e5cbf5e212a9d/src/lib.rs#L40
impl Sentinel {
    fn new(free_threads: Sender<Thread>) -> Sentinel {
        Sentinel {
            free_threads: free_threads,
            active: true,
        }
    }

    // Cancel and destroy this sentinel.
    fn done(mut self) {
        self.active = false;
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        if self.active {
            // Spawn new thread and remove old one.
            spawn_thread(self.free_threads.clone());
        }
    }
}

struct ThreadRunner {
    free_chan: Sender<Thread>, // ThreadRunner will send its Thread when it is ready to do work
}

impl ThreadRunner {
    pub fn new(free_chan: Sender<Thread>) -> ThreadRunner {
        ThreadRunner {
            free_chan: free_chan,
        }
    }

    fn run(self) {
        loop {
            let (thr, jobs) = channel();
            let (res_sender, res_recver) = channel();
            let thread = Thread::new(thr, res_recver);

            let res = self.free_chan.send(thread);
            if res.is_err() {
                // ThreadPool has disconnected
                return
            }
            let res = jobs.recv();
            if res.is_err() {
                // Thread has disconnected
                return
            }
            let job = res.unwrap();
            let res = thread::catch_panic(move || { job.run(); });
            res_sender.send(res).expect("Could not send result");
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::{channel};
    use thread_pool::{ThreadPool, Runner};

    #[test]
    fn test_runable() {
        let (sn, rc) = channel::<u8>();
        let f = box move || {
            sn.send(0u8).unwrap();
        };
        f.run();
        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_thread_and_start() {
        let (sn, rc) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f = box move || {
            sn.send(0u8).unwrap();
        };

        let thr1 = pool.thread();
        let _thr2 = pool.thread();
        let thr3 = pool.thread();
        assert!(thr3.is_err());

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        let res = thr1.start(f);
        assert!(res.is_ok());

        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_join() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        assert!(thr2.is_ok());
        let thr2 = thr2.ok().unwrap();

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);

        let res = thr2.join();
        assert!(res.is_err());
    }

    #[test]
    fn test_thread_pool_max_threads_panic() {
        let (sn1, rc1) = channel::<u8>();
        let (sn3, rc3) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f3 = box move || {
            sn3.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr2.join();
        assert!(res.is_err());

        let thr3 = pool.thread();
        // Can still get thread after panic
        assert!(thr3.is_ok());
        let thr3 = thr3.ok().unwrap();
        let res = thr3.start(f3);
        assert!(res.is_ok());
        let res = thr3.join();
        assert!(res.is_ok());
        assert!(rc3.recv().unwrap() == 0);

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);
    }
}
<commit_msg>Do not panic on sending result<commit_after>use std::boxed::FnBox;
use std::thread::{self, spawn};
use std::sync::mpsc::{channel, Sender, SendError, Receiver, TryRecvError};
use std::error::Error;
use std::fmt;

trait Runner {
    fn run(self: Box<Self>);
}

impl <F: FnBox()> Runner for F {
    fn run(self: Box<F>) {
        self.call_box(())
    }
}

/// Type used by ThreadPool to run closures, etc. on the spawned threads.
pub type Proc<'a> = Box<Runner + Send + 'a>;

/// Used to interact with the spawned threads returned by the ThreadPool.
///
/// See documentation for ThreadPool for more information.
pub struct Thread {
    inner: ThreadInner,
}

struct ThreadInner {
    sender: Sender<Proc<'static>>,
    result: Receiver<thread::Result<()>>,
}

impl Thread {
    fn new(sender: Sender<Proc<'static>>, result: Receiver<thread::Result<()>>) -> Thread {
        Thread {
            inner: ThreadInner {
                       sender: sender,
                       result: result,
                   },
        }
    }

    /// Sends the runnable object to a spawned thread to be run.
    pub fn start(&self, f: Proc<'static>) -> Result<(), SendError<Proc<'static>>> {
        self.inner.sender.send(f)
    }

    /// Blocks on the result of the started Proc.
    ///
    /// Do not use if no Proc is being run!
    pub fn join(&self) -> thread::Result<()> {
        self.inner.result.recv().expect("Could not get result")
    }
}

/// The ThreadPool that manages the state of the threads and spawns new ones.
///
/// ```
/// #![feature(box_syntax)]
/// #![feature(result_expect)]
/// use std::sync::mpsc::channel;
/// use ferrous_threads::thread_pool::ThreadPool;
///
/// let mut pool = ThreadPool::new(1, 2);
/// let thread = pool.thread().unwrap();
///
/// let (sn, rc) = channel();
/// thread.start(box move || { sn.send(9u8).unwrap();}).expect("Could not send Proc");
/// assert!(thread.join().is_ok());
/// assert!(rc.recv().unwrap() == 9u8);
/// ```
pub struct ThreadPool {
    free_sender: Sender<Thread>, // Keep this to spawn new threads
    free_threads: Receiver<Thread>, // Threads will send themselves when they are free.
    active_threads: usize,
    max_threads: usize,
}

fn spawn_thread(free: Sender<Thread>) {
        spawn(move || {
            let sentinel = Sentinel::new(free.clone());
            ThreadRunner::new(free).run();
            sentinel.done();
        });
}

impl ThreadPool {
    pub fn new(init_threads: usize, max_threads: usize) -> ThreadPool {
        let (sn, rc) = channel();
        let mut thrs = Vec::new();
        for _i in 0..init_threads {
            spawn_thread(sn.clone());
            let thr = rc.recv().expect("Could not receive initial thread");
            thrs.push(thr);
        }

        for t in thrs.into_iter() {
            sn.send(t).expect("Could not reinsert threads");
        }

        ThreadPool {
            free_sender: sn,
            free_threads: rc,
            active_threads: init_threads,
            max_threads: max_threads
        }
    }

    /// Returns a handle to a spawned thread or an error if there are no more threads available.
    pub fn thread(&mut self) -> Result<Thread, ThreadError> {
        let mut res = Err(TryRecvError::Disconnected);
        for _i in 0..9 {
            res = self.free_threads.try_recv();
            if res.is_ok() {
                break
            }
        }

        match res {
            Ok(thr) => Ok(thr),
            Err(TryRecvError::Empty) => {
                if self.active_threads >= self.max_threads {
                    Err(ThreadError)
                } else {
                    self.active_threads += 1;
                    spawn_thread(self.free_sender.clone());
                    let thr = self.free_threads.recv().expect("Could not receive thread");
                    Ok(thr)
                }
            }
            Err(TryRecvError::Disconnected) => panic!("channel closed"),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ThreadError;

impl Error for ThreadError {
    fn description(&self) -> &str {
        "Could not make any more threads."
    }
}

impl fmt::Display for ThreadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "Could not make any more threads.".fmt(f)
    }
}

struct Sentinel {
    free_threads: Sender<Thread>,
    active: bool,
}

// Idea taken from https://github.com/rust-lang/threadpool/blob/b9416b4cb591a3ac8bac8efef19e5cbf5e212a9d/src/lib.rs#L40
impl Sentinel {
    fn new(free_threads: Sender<Thread>) -> Sentinel {
        Sentinel {
            free_threads: free_threads,
            active: true,
        }
    }

    // Cancel and destroy this sentinel.
    fn done(mut self) {
        self.active = false;
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        if self.active {
            // Spawn new thread and remove old one.
            spawn_thread(self.free_threads.clone());
        }
    }
}

struct ThreadRunner {
    free_chan: Sender<Thread>, // ThreadRunner will send its Thread when it is ready to do work
}

impl ThreadRunner {
    pub fn new(free_chan: Sender<Thread>) -> ThreadRunner {
        ThreadRunner {
            free_chan: free_chan,
        }
    }

    fn run(self) {
        loop {
            let (thr, jobs) = channel();
            let (res_sender, res_recver) = channel();
            let thread = Thread::new(thr, res_recver);

            let res = self.free_chan.send(thread);
            if res.is_err() {
                // ThreadPool has disconnected
                return
            }
            let res = jobs.recv();
            if res.is_err() {
                // Thread has disconnected
                return
            }
            let job = res.unwrap();
            let res = thread::catch_panic(move || { job.run(); });
            let res = res_sender.send(res);
            if res.is_err() {
                // Thread has disconnected
                return
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::{channel};
    use thread_pool::{ThreadPool, Runner};

    #[test]
    fn test_runable() {
        let (sn, rc) = channel::<u8>();
        let f = box move || {
            sn.send(0u8).unwrap();
        };
        f.run();
        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_thread_and_start() {
        let (sn, rc) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f = box move || {
            sn.send(0u8).unwrap();
        };

        let thr1 = pool.thread();
        let _thr2 = pool.thread();
        let thr3 = pool.thread();
        assert!(thr3.is_err());

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        let res = thr1.start(f);
        assert!(res.is_ok());

        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_join() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        assert!(thr2.is_ok());
        let thr2 = thr2.ok().unwrap();

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);

        let res = thr2.join();
        assert!(res.is_err());
    }

    #[test]
    fn test_thread_pool_max_threads_panic() {
        let (sn1, rc1) = channel::<u8>();
        let (sn3, rc3) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f3 = box move || {
            sn3.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr2.join();
        assert!(res.is_err());

        let thr3 = pool.thread();
        // Can still get thread after panic
        assert!(thr3.is_ok());
        let thr3 = thr3.ok().unwrap();
        let res = thr3.start(f3);
        assert!(res.is_ok());
        let res = thr3.join();
        assert!(res.is_ok());
        assert!(rc3.recv().unwrap() == 0);

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);
    }
}
<|endoftext|>


<commit_before>pub trait _StrExt {
    fn _is_char_boundary(&self, index: usize) -> bool;
}

impl _StrExt for str {
    #[inline]
    fn _is_char_boundary(&self, index: usize) -> bool {
        if index == self.len() {
            return true;
        }
        match self.as_bytes().get(index) {
            None => false,
            Some(&b) => b < 128 || b >= 192,
        }
    }
}
<commit_msg>Use map_or instead of match<commit_after>pub trait _StrExt {
    fn _is_char_boundary(&self, index: usize) -> bool;
}

impl _StrExt for str {
    #[inline]
    fn _is_char_boundary(&self, index: usize) -> bool {
        if index == self.len() {
            return true;
        }

        self.as_bytes()
            .get(index)
            .map_or(false, |&b| b < 128 || b >= 192)
    }
}
<|endoftext|>


<commit_before>use types::Value;

use traits::Object;

/// Representation of any Ruby object while its type is unknown
///
/// As Ruby is a dynamically typed language, at some points Ruru does not know the exact Ruby type
/// of the object. It happens in the following cases:
///
/// - Retrieving an object from array
///
/// - Retrieving an object from hash
///
/// - Receiving arguments to callback
///
/// - Initializing new instance of a class which is not present in Ruru
///
/// - and some other places you can find in Ruru documentation
///
/// In these cases you should cast `AnyObject` to the type to which the object belongs
/// using functions below.
///
/// # Examples
///
/// ## Retrieving an object from `Array`
///
/// ```
/// use ruru::{Array, Fixnum, VM};
/// use ruru::traits::Object;
/// # VM::init();
///
/// let array = Array::new().push(Fixnum::new(1));
/// let value = array.at(0).try_convert_to::<Fixnum>(); // `Array::at()` returns `AnyObject`
///
/// assert_eq!(value, Ok(Fixnum::new(1)));
/// ```
///
/// ## Retrieving an object from `Hash`
///
/// ```no_run
/// use ruru::{Fixnum, Hash, Symbol, VM};
/// use ruru::traits::Object;
/// # VM::init();
///
/// let mut hash = Hash::new();
///
/// hash.store(Symbol::new("key"), Fixnum::new(1));
///
/// // `Hash::at()` returns `AnyObject`
/// let value = hash.at(Symbol::new("key")).try_convert_to::<Fixnum>();
///
/// assert_eq!(value, Ok(Fixnum::new(1)));
/// ```
///
/// ## Receiving arguments from Ruby to Ruru callback
///
/// Do not use create callbacks manually. Use `methods!` macro instead.
///
/// ```no_run
/// use ruru::types::Argc;
/// use ruru::{AnyObject, Boolean, Class, RString, VM};
/// use ruru::traits::Object;
///
/// #[no_mangle]
/// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
///     // `VM::parse_arguments()` returns `Vec<AnyObject>`
///     let argv = VM::parse_arguments(argc, argv);
///     let other_string = argv[0].try_convert_to::<RString>().unwrap();
///
///     Boolean::new(itself.to_string() == other_string.to_string())
/// }
///
/// fn main() {
///     Class::from_existing("String").define_method("==", string_eq);
/// }
/// ```
#[derive(Clone)]
pub struct AnyObject {
    value: Value,
}

impl From<Value> for AnyObject {
    fn from(value: Value) -> Self {
        AnyObject { value: value }
    }
}

impl Object for AnyObject {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Implement VerifiedObject for AnyObject<commit_after>use types::Value;

use traits::{Object, VerifiedObject};

/// Representation of any Ruby object while its type is unknown
///
/// As Ruby is a dynamically typed language, at some points Ruru does not know the exact Ruby type
/// of the object. It happens in the following cases:
///
/// - Retrieving an object from array
///
/// - Retrieving an object from hash
///
/// - Receiving arguments to callback
///
/// - Initializing new instance of a class which is not present in Ruru
///
/// - and some other places you can find in Ruru documentation
///
/// In these cases you should cast `AnyObject` to the type to which the object belongs
/// using functions below.
///
/// # Examples
///
/// ## Retrieving an object from `Array`
///
/// ```
/// use ruru::{Array, Fixnum, VM};
/// use ruru::traits::Object;
/// # VM::init();
///
/// let array = Array::new().push(Fixnum::new(1));
/// let value = array.at(0).try_convert_to::<Fixnum>(); // `Array::at()` returns `AnyObject`
///
/// assert_eq!(value, Ok(Fixnum::new(1)));
/// ```
///
/// ## Retrieving an object from `Hash`
///
/// ```no_run
/// use ruru::{Fixnum, Hash, Symbol, VM};
/// use ruru::traits::Object;
/// # VM::init();
///
/// let mut hash = Hash::new();
///
/// hash.store(Symbol::new("key"), Fixnum::new(1));
///
/// // `Hash::at()` returns `AnyObject`
/// let value = hash.at(Symbol::new("key")).try_convert_to::<Fixnum>();
///
/// assert_eq!(value, Ok(Fixnum::new(1)));
/// ```
///
/// ## Receiving arguments from Ruby to Ruru callback
///
/// Do not use create callbacks manually. Use `methods!` macro instead.
///
/// ```no_run
/// use ruru::types::Argc;
/// use ruru::{AnyObject, Boolean, Class, RString, VM};
/// use ruru::traits::Object;
///
/// #[no_mangle]
/// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
///     // `VM::parse_arguments()` returns `Vec<AnyObject>`
///     let argv = VM::parse_arguments(argc, argv);
///     let other_string = argv[0].try_convert_to::<RString>().unwrap();
///
///     Boolean::new(itself.to_string() == other_string.to_string())
/// }
///
/// fn main() {
///     Class::from_existing("String").define_method("==", string_eq);
/// }
/// ```
#[derive(Clone)]
pub struct AnyObject {
    value: Value,
}

impl From<Value> for AnyObject {
    fn from(value: Value) -> Self {
        AnyObject { value: value }
    }
}

impl Object for AnyObject {
    fn value(&self) -> Value {
        self.value
    }
}

impl VerifiedObject for AnyObject {
    fn is_correct_type<T: Object>(_: &T) -> bool {
        true
    }

    fn error_message() -> String {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  fn from_i32_lossy(sample: i32) -> Self;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u64, bit_count: usize) -> i64 {
  if bit_count >= 64 || value < (1 << (bit_count - 1)) {
    value as i64
  } else {
    (value as i64).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add documentation for `Sample::from_i32_lossy`<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u64, bit_count: usize) -> i64 {
  if bit_count >= 64 || value < (1 << (bit_count - 1)) {
    value as i64
  } else {
    (value as i64).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>
extern crate glob;

use std::fs::canonicalize;
use std::path::PathBuf;
use std::process::Command;
use glob::glob;

fn search_lib(libpath: &PathBuf, regex: &str) -> PathBuf {
    glob(libpath.join(regex).to_str().unwrap()).unwrap().last().unwrap().unwrap()
}

fn main() {
    let source = PathBuf::from("numpy");
    let libpath = canonicalize(PathBuf::from("numpy/build/lib.linux-x86_64-3.6/numpy/core")).unwrap();

    Command::new("python").args(&["setup.py", "build"]).current_dir(&source).status().expect("Failed to build numpy");
    let multiarray = search_lib(&libpath, "multiarray.*.so");
    let umath = search_lib(&libpath, "umath.*.so");

    Command::new("ln")
        .arg("-sf")
        .arg(multiarray.file_name().unwrap())
        .arg("libmultiarray.so")
        .current_dir(&libpath)
        .status()
        .expect("Failed to create symlink");
    Command::new("ln")
        .arg("-sf")
        .arg(umath.file_name().unwrap())
        .arg("libumath.so")
        .current_dir(&libpath)
        .status()
        .expect("Failed to create symlink");
    println!("cargo:rustc-link-search={}", libpath.display());
    println!("cargo:rustc-link-lib=dylib=multiarray");
    println!("cargo:rustc-link-lib=dylib=umath");
}
<commit_msg>Fix build script<commit_after>
extern crate glob;

use std::fs::canonicalize;
use std::path::PathBuf;
use std::process::Command;
use glob::glob;

fn search_lib(libpath: &PathBuf, regex: &str) -> PathBuf {
    glob(libpath.join(regex).to_str().unwrap()).unwrap().last().unwrap().unwrap()
}

fn create_symlink(libpath: &PathBuf, lib: &PathBuf, name: &str) {
    Command::new("ln")
        .arg("-sf")
        .arg(lib.file_name().unwrap())
        .arg(name)
        .current_dir(&libpath)
        .status()
        .expect("Failed to create symlink");
}

fn main() {
    let source = PathBuf::from("numpy");
    Command::new("python").args(&["setup.py", "build"]).current_dir(&source).status().expect("Failed to build numpy");
    let libpath = canonicalize(PathBuf::from("numpy/build/lib.linux-x86_64-3.6/numpy/core")).unwrap();
    let multiarray = search_lib(&libpath, "multiarray.*.so");
    let umath = search_lib(&libpath, "umath.*.so");
    create_symlink(&libpath, &multiarray, "libmultiarray.so");
    create_symlink(&libpath, &umath, "libumath.so");
    println!("cargo:rustc-link-search={}", libpath.display());
    println!("cargo:rustc-link-lib=dylib=multiarray");
    println!("cargo:rustc-link-lib=dylib=umath");
}
<|endoftext|>


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

use text::glyph::CharIndex;

#[deriving(PartialEq)]
pub enum CompressionMode {
    CompressNone,
    CompressWhitespace,
    CompressWhitespaceNewline,
    DiscardNewline
}

// ported from Gecko's nsTextFrameUtils::TransformText.
//
// High level TODOs:
//
// * Issue #113: consider incoming text state (arabic, etc)
//               and propagate outgoing text state (dual of above)
//
// * Issue #114: record skipped and kept chars for mapping original to new text
//
// * Untracked: various edge cases for bidi, CJK, etc.
pub fn transform_text(text: &str,
                      mode: CompressionMode,
                      incoming_whitespace: bool,
                      output_text: &mut String,
                      new_line_pos: &mut Vec<CharIndex>)
                      -> bool {
    let out_whitespace = match mode {
        CompressionMode::CompressNone | CompressionMode::DiscardNewline => {
            let mut new_line_index = CharIndex(0);
            for ch in text.chars() {
                if is_discardable_char(ch, mode) {
                    // TODO: record skipped char
                } else {
                    // TODO: record kept char
                    if ch == '\t' {
                        // TODO: set "has tab" flag
                    } else if ch == '\n' {
                        // Save new-line's position for line-break
                        // This value is relative(not absolute)
                        new_line_pos.push(new_line_index);
                        new_line_index = CharIndex(0);
                    }

                    if ch != '\n' {
                        new_line_index = new_line_index + CharIndex(1);
                    }
                    output_text.push(ch);
                }
            }
            text.len() > 0 && is_in_whitespace(text.char_at_reverse(0), mode)
        },

        CompressionMode::CompressWhitespace | CompressionMode::CompressWhitespaceNewline => {
            let mut in_whitespace: bool = incoming_whitespace;
            for ch in text.chars() {
                // TODO: discard newlines between CJK chars
                let mut next_in_whitespace: bool = is_in_whitespace(ch, mode);

                if !next_in_whitespace {
                    if is_always_discardable_char(ch) {
                        // revert whitespace setting, since this char was discarded
                        next_in_whitespace = in_whitespace;
                        // TODO: record skipped char
                    } else {
                        // TODO: record kept char
                        output_text.push(ch);
                    }
                } else { /* next_in_whitespace; possibly add a space char */
                    if in_whitespace {
                        // TODO: record skipped char
                    } else {
                        // TODO: record kept char
                        output_text.push(' ');
                    }
                }
                // save whitespace context for next char
                in_whitespace = next_in_whitespace;
            } /* /for str::each_char */
            in_whitespace
        }
    };

    return out_whitespace;

    fn is_in_whitespace(ch: char, mode: CompressionMode) -> bool {
        match (ch, mode) {
            (' ', _)  => true,
            ('\t', _) => true,
            ('\n', CompressionMode::CompressWhitespaceNewline) => true,
            (_, _)    => false
        }
    }

    fn is_discardable_char(ch: char, mode: CompressionMode) -> bool {
        if is_always_discardable_char(ch) {
            return true;
        }
        match mode {
            CompressionMode::DiscardNewline | CompressionMode::CompressWhitespaceNewline => ch == '\n',
            _ => false
        }
    }

    fn is_always_discardable_char(_ch: char) -> bool {
        // TODO: check for bidi control chars, soft hyphens.
        false
    }
}

pub fn float_to_fixed(before: int, f: f64) -> i32 {
    ((1i32 << before as uint) as f64 * f) as i32
}

pub fn fixed_to_float(before: int, f: i32) -> f64 {
    f as f64 * 1.0f64 / ((1i32 << before as uint) as f64)
}

pub fn fixed_to_rounded_int(before: int, f: i32) -> int {
    let half = 1i32 << (before-1) as uint;
    if f > 0i32 {
        ((half + f) >> before as uint) as int
    } else {
       -((half - f) >> before as uint) as int
    }
}

/* Generate a 32-bit TrueType tag from its 4 characters */
pub fn true_type_tag(a: char, b: char, c: char, d: char) -> u32 {
    let a = a as u32;
    let b = b as u32;
    let c = c as u32;
    let d = d as u32;
    (a << 24 | b << 16 | c << 8 | d) as u32
}

#[test]
fn test_true_type_tag() {
    assert_eq!(true_type_tag('c', 'm', 'a', 'p'), 0x_63_6D_61_70_u32);
}

#[test]
fn test_transform_compress_none() {
    let test_strs = vec!(
        "  foo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    );
    let mode = CompressionMode::CompressNone;

    for test in test_strs.iter() {
        let mut new_line_pos = vec!();
        let mut trimmed_str = String::new();
        transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(trimmed_str.as_slice(), *test)
    }
}

#[test]
fn test_transform_discard_newline() {
    let test_strs = vec!(
        "  foo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    );

    let oracle_strs = vec!(
        "  foo bar",
        "foo bar  ",
        "foo bar",
        "foo bar",
        "  foo  bar  baz",
        "foo bar baz",
        "foobarbaz"
    );

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::DiscardNewline;

    for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
        let mut new_line_pos = vec!();
        let mut trimmed_str = String::new();
        transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(trimmed_str.as_slice(), *oracle)
    }
}

/* FIXME: Fix and re-enable
#[test]
fn test_transform_compress_whitespace() {
    let  test_strs : ~[String] = ~["  foo bar".into_string(),
                                 "foo bar  ".into_string(),
                                 "foo\n bar".into_string(),
                                 "foo \nbar".into_string(),
                                 "  foo  bar  \nbaz".into_string(),
                                 "foo bar baz".into_string(),
                                 "foobarbaz\n\n".into_string()];

    let oracle_strs : ~[String] = ~[" foo bar".into_string(),
                                 "foo bar ".into_string(),
                                 "foo\n bar".into_string(),
                                 "foo \nbar".into_string(),
                                 " foo bar \nbaz".into_string(),
                                 "foo bar baz".into_string(),
                                 "foobarbaz\n\n".into_string()];

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressWhitespace;

    for i in range(0, test_strs.len()) {
        let mut new_line_pos = ~[];
        let (trimmed_str, _out) = transform_text(test_strs[i], mode, true, &mut new_line_pos);
        assert_eq!(&trimmed_str, &oracle_strs[i])
    }
}

#[test]
fn test_transform_compress_whitespace_newline() {
    let  test_strs : ~[String] = ~["  foo bar".into_string(),
                                 "foo bar  ".into_string(),
                                 "foo\n bar".into_string(),
                                 "foo \nbar".into_string(),
                                 "  foo  bar  \nbaz".into_string(),
                                 "foo bar baz".into_string(),
                                 "foobarbaz\n\n".into_string()];

    let oracle_strs : ~[String] = ~["foo bar".into_string(),
                                 "foo bar ".into_string(),
                                 "foo bar".into_string(),
                                 "foo bar".into_string(),
                                 " foo bar baz".into_string(),
                                 "foo bar baz".into_string(),
                                 "foobarbaz ".into_string()];

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::CompressWhitespaceNewline;

    for i in range(0, test_strs.len()) {
        let mut new_line_pos = ~[];
        let (trimmed_str, _out) = transform_text(test_strs[i], mode, true, &mut new_line_pos);
        assert_eq!(&trimmed_str, &oracle_strs[i])
    }
}
*/

#[test]
fn test_transform_compress_whitespace_newline_no_incoming() {
    let test_strs = vec!(
        "  foo bar",
        "\nfoo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    );

    let oracle_strs = vec!(
        " foo bar",
        " foo bar",
        "foo bar ",
        "foo bar",
        "foo bar",
        " foo bar baz",
        "foo bar baz",
        "foobarbaz "
    );

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::CompressWhitespaceNewline;

    for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
        let mut new_line_pos = vec!();
        let mut trimmed_str = String::new();
        transform_text(*test, mode, false, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(trimmed_str.as_slice(), *oracle)
    }
}
<commit_msg>Re-enable two transform_text unit tests.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use text::glyph::CharIndex;

#[deriving(PartialEq)]
pub enum CompressionMode {
    CompressNone,
    CompressWhitespace,
    CompressWhitespaceNewline,
    DiscardNewline
}

// ported from Gecko's nsTextFrameUtils::TransformText.
//
// High level TODOs:
//
// * Issue #113: consider incoming text state (arabic, etc)
//               and propagate outgoing text state (dual of above)
//
// * Issue #114: record skipped and kept chars for mapping original to new text
//
// * Untracked: various edge cases for bidi, CJK, etc.
pub fn transform_text(text: &str,
                      mode: CompressionMode,
                      incoming_whitespace: bool,
                      output_text: &mut String,
                      new_line_pos: &mut Vec<CharIndex>)
                      -> bool {
    let out_whitespace = match mode {
        CompressionMode::CompressNone | CompressionMode::DiscardNewline => {
            let mut new_line_index = CharIndex(0);
            for ch in text.chars() {
                if is_discardable_char(ch, mode) {
                    // TODO: record skipped char
                } else {
                    // TODO: record kept char
                    if ch == '\t' {
                        // TODO: set "has tab" flag
                    } else if ch == '\n' {
                        // Save new-line's position for line-break
                        // This value is relative(not absolute)
                        new_line_pos.push(new_line_index);
                        new_line_index = CharIndex(0);
                    }

                    if ch != '\n' {
                        new_line_index = new_line_index + CharIndex(1);
                    }
                    output_text.push(ch);
                }
            }
            text.len() > 0 && is_in_whitespace(text.char_at_reverse(0), mode)
        },

        CompressionMode::CompressWhitespace | CompressionMode::CompressWhitespaceNewline => {
            let mut in_whitespace: bool = incoming_whitespace;
            for ch in text.chars() {
                // TODO: discard newlines between CJK chars
                let mut next_in_whitespace: bool = is_in_whitespace(ch, mode);

                if !next_in_whitespace {
                    if is_always_discardable_char(ch) {
                        // revert whitespace setting, since this char was discarded
                        next_in_whitespace = in_whitespace;
                        // TODO: record skipped char
                    } else {
                        // TODO: record kept char
                        output_text.push(ch);
                    }
                } else { /* next_in_whitespace; possibly add a space char */
                    if in_whitespace {
                        // TODO: record skipped char
                    } else {
                        // TODO: record kept char
                        output_text.push(' ');
                    }
                }
                // save whitespace context for next char
                in_whitespace = next_in_whitespace;
            } /* /for str::each_char */
            in_whitespace
        }
    };

    return out_whitespace;

    fn is_in_whitespace(ch: char, mode: CompressionMode) -> bool {
        match (ch, mode) {
            (' ', _)  => true,
            ('\t', _) => true,
            ('\n', CompressionMode::CompressWhitespaceNewline) => true,
            (_, _)    => false
        }
    }

    fn is_discardable_char(ch: char, mode: CompressionMode) -> bool {
        if is_always_discardable_char(ch) {
            return true;
        }
        match mode {
            CompressionMode::DiscardNewline | CompressionMode::CompressWhitespaceNewline => ch == '\n',
            _ => false
        }
    }

    fn is_always_discardable_char(_ch: char) -> bool {
        // TODO: check for bidi control chars, soft hyphens.
        false
    }
}

pub fn float_to_fixed(before: int, f: f64) -> i32 {
    ((1i32 << before as uint) as f64 * f) as i32
}

pub fn fixed_to_float(before: int, f: i32) -> f64 {
    f as f64 * 1.0f64 / ((1i32 << before as uint) as f64)
}

pub fn fixed_to_rounded_int(before: int, f: i32) -> int {
    let half = 1i32 << (before-1) as uint;
    if f > 0i32 {
        ((half + f) >> before as uint) as int
    } else {
       -((half - f) >> before as uint) as int
    }
}

/* Generate a 32-bit TrueType tag from its 4 characters */
pub fn true_type_tag(a: char, b: char, c: char, d: char) -> u32 {
    let a = a as u32;
    let b = b as u32;
    let c = c as u32;
    let d = d as u32;
    (a << 24 | b << 16 | c << 8 | d) as u32
}

#[test]
fn test_true_type_tag() {
    assert_eq!(true_type_tag('c', 'm', 'a', 'p'), 0x_63_6D_61_70_u32);
}

#[test]
fn test_transform_compress_none() {
    let test_strs = vec!(
        "  foo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    );
    let mode = CompressionMode::CompressNone;

    for test in test_strs.iter() {
        let mut new_line_pos = vec!();
        let mut trimmed_str = String::new();
        transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(trimmed_str.as_slice(), *test)
    }
}

#[test]
fn test_transform_discard_newline() {
    let test_strs = vec!(
        "  foo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    );

    let oracle_strs = vec!(
        "  foo bar",
        "foo bar  ",
        "foo bar",
        "foo bar",
        "  foo  bar  baz",
        "foo bar baz",
        "foobarbaz"
    );

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::DiscardNewline;

    for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
        let mut new_line_pos = vec!();
        let mut trimmed_str = String::new();
        transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(trimmed_str.as_slice(), *oracle)
    }
}

#[test]
fn test_transform_compress_whitespace() {
    let test_strs = vec![
        "  foo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n",
    ];

    let oracle_strs = vec![
        "foo bar",
        "foo bar ",
        "foo\n bar",
        "foo \nbar",
        "foo bar \nbaz",
        "foo bar baz",
        "foobarbaz\n\n",
    ];

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::CompressWhitespace;

    for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
        let mut new_line_pos = vec![];
        let mut trimmed_str = String::new();
        transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(&*trimmed_str, *oracle)
    }
}

#[test]
fn test_transform_compress_whitespace_newline() {
    let test_strs = vec![
        "  foo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    ];

    let oracle_strs = vec![
        "foo bar",
        "foo bar ",
        "foo bar",
        "foo bar",
        "foo bar baz",
        "foo bar baz",
        "foobarbaz "
    ];

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::CompressWhitespaceNewline;

    for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
        let mut new_line_pos = vec![];
        let mut trimmed_str = String::new();
        transform_text(*test, mode, true, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(&*trimmed_str, *oracle)
    }
}

#[test]
fn test_transform_compress_whitespace_newline_no_incoming() {
    let test_strs = vec!(
        "  foo bar",
        "\nfoo bar",
        "foo bar  ",
        "foo\n bar",
        "foo \nbar",
        "  foo  bar  \nbaz",
        "foo bar baz",
        "foobarbaz\n\n"
    );

    let oracle_strs = vec!(
        " foo bar",
        " foo bar",
        "foo bar ",
        "foo bar",
        "foo bar",
        " foo bar baz",
        "foo bar baz",
        "foobarbaz "
    );

    assert_eq!(test_strs.len(), oracle_strs.len());
    let mode = CompressionMode::CompressWhitespaceNewline;

    for (test, oracle) in test_strs.iter().zip(oracle_strs.iter()) {
        let mut new_line_pos = vec!();
        let mut trimmed_str = String::new();
        transform_text(*test, mode, false, &mut trimmed_str, &mut new_line_pos);
        assert_eq!(trimmed_str.as_slice(), *oracle)
    }
}
<|endoftext|>