<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/. */

//! A task that takes a URL and streams back the binary data.

use about_loader;
use data_loader;
use file_loader;
use http_loader;
use cookie_storage::CookieStorage;
use cookie;
use mime_classifier::MIMEClassifier;

use net_traits::{ControlMsg, LoadData, LoadResponse};
use net_traits::{Metadata, ProgressMsg, ResourceTask};
use net_traits::ProgressMsg::Done;
use util::opts;
use util::task::spawn_named;

use hyper::header::{ContentType, Header, SetCookie, UserAgent};
use hyper::mime::{Mime, TopLevel, SubLevel};

use std::borrow::ToOwned;
use std::boxed;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read};
use std::str::FromStr;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thunk::Invoke;

static mut HOST_TABLE: Option<*mut HashMap<String, String>> = None;

pub fn global_init() {
    //TODO: handle bad file path
    let path = match env::var("HOST_FILE") {
        Ok(host_file_path) => host_file_path,
        Err(_) => return,
    };

    let mut file = match File::open(&path) {
        Ok(f) => BufReader::new(f),
        Err(_) => return,
    };

    let mut lines = String::new();
    match file.read_to_string(&mut lines) {
        Ok(()) => (),
        Err(_) => return,
    };

    unsafe {
        let host_table = boxed::into_raw(parse_hostsfile(&lines));
        HOST_TABLE = Some(host_table);
    }
}

/// For use by loaders in responding to a Load message.
pub fn start_sending(start_chan: Sender<LoadResponse>, metadata: Metadata) -> Sender<ProgressMsg> {
    start_sending_opt(start_chan, metadata).ok().unwrap()
}

/// For use by loaders in responding to a Load message that allows content sniffing.
pub fn start_sending_sniffed(start_chan: Sender<LoadResponse>, metadata: Metadata,
                             classifier: Arc<MIMEClassifier>, partial_body: &Vec<u8>)
                             -> Sender<ProgressMsg> {
    start_sending_sniffed_opt(start_chan, metadata, classifier, partial_body).ok().unwrap()
}

/// For use by loaders in responding to a Load message that allows content sniffing.
pub fn start_sending_sniffed_opt(start_chan: Sender<LoadResponse>, mut metadata: Metadata,
                                 classifier: Arc<MIMEClassifier>, partial_body: &Vec<u8>)
                                 -> Result<Sender<ProgressMsg>, ()> {
    if opts::get().sniff_mime_types {
        // TODO: should be calculated in the resource loader, from pull requeset #4094
        let nosniff = false;
        let check_for_apache_bug = false;

        metadata.content_type = match metadata.content_type {
            Some(ContentType(Mime(toplevel, sublevel, _))) => {
                let content_type = classifier.classify(nosniff, check_for_apache_bug,
                                                       &Some((format!("{}", toplevel), format!("{}", sublevel))), &partial_body);
                match content_type {
                    Some((tp, sb)) => {
                        let mime_tp: TopLevel = FromStr::from_str(&tp).unwrap();
                        let mime_sb: SubLevel = FromStr::from_str(&sb).unwrap();
                        Some(ContentType(Mime(mime_tp, mime_sb, vec!())))
                    }
                    None => None
                }
            }
            None => {
                let content_type = classifier.classify(nosniff, check_for_apache_bug,
                                                       &None, &partial_body);

                match content_type {
                    Some((tp, sb)) => {
                        let mime_tp: TopLevel = FromStr::from_str(&tp).unwrap();
                        let mime_sb: SubLevel = FromStr::from_str(&sb).unwrap();
                        Some(ContentType(Mime(mime_tp, mime_sb, vec!())))
                    }
                    None => None
                }
            }
        }

    }

    start_sending_opt(start_chan, metadata)
}

/// For use by loaders in responding to a Load message.
pub fn start_sending_opt(start_chan: Sender<LoadResponse>, metadata: Metadata) -> Result<Sender<ProgressMsg>, ()> {
    let (progress_chan, progress_port) = channel();
    let result = start_chan.send(LoadResponse {
        metadata:      metadata,
        progress_port: progress_port,
    });
    match result {
        Ok(_) => Ok(progress_chan),
        Err(_) => Err(())
    }
}

/// Create a ResourceTask
pub fn new_resource_task(user_agent: Option<String>) -> ResourceTask {
    let (setup_chan, setup_port) = channel();
    let setup_chan_clone = setup_chan.clone();
    spawn_named("ResourceManager".to_owned(), move || {
        ResourceManager::new(setup_port, user_agent, setup_chan_clone).start();
    });
    setup_chan
}

pub fn parse_hostsfile(hostsfile_content: &str) -> Box<HashMap<String, String>> {
    let ipv4_regex = regex!(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    let ipv6_regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$");
    let mut host_table = HashMap::new();
    let lines: Vec<&str> = hostsfile_content.split('\n').collect();

    for line in lines.iter() {
        let ip_host: Vec<&str> = line.trim().split(|c: char| c == ' ' || c == '\t').collect();
        if ip_host.len() > 1 {
            if !ipv4_regex.is_match(ip_host[0]) && !ipv6_regex.is_match(ip_host[0]) { continue; }
            let address = ip_host[0].to_owned();

            for token in ip_host.iter().skip(1) {
                if token.as_bytes()[0] == b'#' {
                    break;
                }
                host_table.insert(token.to_owned().to_string(), address.clone());
            }
        }
    }
    box host_table
}

pub fn replace_hosts(mut load_data: LoadData, host_table: *mut HashMap<String, String>) -> LoadData {
    if let Some(h) = load_data.url.domain_mut() {
        unsafe {
            if let Some(ip) = (*host_table).get(h) {
                *h = ip.clone();
            }
        }
    }
    return load_data;
}

struct ResourceManager {
    from_client: Receiver<ControlMsg>,
    user_agent: Option<String>,
    cookie_storage: CookieStorage,
    resource_task: Sender<ControlMsg>,
    mime_classifier: Arc<MIMEClassifier>,
}

impl ResourceManager {
    fn new(from_client: Receiver<ControlMsg>, user_agent: Option<String>,
           resource_task: Sender<ControlMsg>) -> ResourceManager {
        ResourceManager {
            from_client: from_client,
            user_agent: user_agent,
            cookie_storage: CookieStorage::new(),
            resource_task: resource_task,
            mime_classifier: Arc::new(MIMEClassifier::new()),
        }
    }
}

impl ResourceManager {
    fn start(&mut self) {
        loop {
            match self.from_client.recv().unwrap() {
              ControlMsg::Load(load_data) => {
                self.load(load_data)
              }
              ControlMsg::SetCookiesForUrl(request, cookie_list, source) => {
                let header = Header::parse_header(&[cookie_list.into_bytes()]);
                if let Some(SetCookie(cookies)) = header {
                  for bare_cookie in cookies.into_iter() {
                    if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, &request, source) {
                      self.cookie_storage.push(cookie, source);
                    }
                  }
                }
              }
              ControlMsg::GetCookiesForUrl(url, consumer, source) => {
                consumer.send(self.cookie_storage.cookies_for_url(&url, source)).unwrap();
              }
              ControlMsg::Exit => {
                break
              }
            }
        }
    }

    fn load(&mut self, mut load_data: LoadData) {
        unsafe {
            if let Some(host_table) = HOST_TABLE {
                load_data = replace_hosts(load_data, host_table);
            }
        }

        self.user_agent.as_ref().map(|ua| load_data.headers.set(UserAgent(ua.clone())));

        fn from_factory(factory: fn(LoadData, Arc<MIMEClassifier>))
                        -> Box<Invoke<(LoadData, Arc<MIMEClassifier>)> + Send> {
            box move |(load_data, classifier)| {
                factory(load_data, classifier)
            }
        }

        let loader = match &*load_data.url.scheme {
            "file" => from_factory(file_loader::factory),
            "http" | "https" | "view-source" => http_loader::factory(self.resource_task.clone()),
            "data" => from_factory(data_loader::factory),
            "about" => from_factory(about_loader::factory),
            _ => {
                debug!("resource_task: no loader for scheme {}", load_data.url.scheme);
                start_sending(load_data.consumer, Metadata::default(load_data.url))
                    .send(ProgressMsg::Done(Err("no loader for scheme".to_string()))).unwrap();
                return
            }
        };
        debug!("resource_task: loading url: {}", load_data.url.serialize());

        loader.invoke((load_data, self.mime_classifier.clone()));
    }
}
<commit_msg>Reduce duplication<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/. */

//! A task that takes a URL and streams back the binary data.

use about_loader;
use data_loader;
use file_loader;
use http_loader;
use cookie_storage::CookieStorage;
use cookie;
use mime_classifier::MIMEClassifier;

use net_traits::{ControlMsg, LoadData, LoadResponse};
use net_traits::{Metadata, ProgressMsg, ResourceTask};
use net_traits::ProgressMsg::Done;
use util::opts;
use util::task::spawn_named;

use hyper::header::{ContentType, Header, SetCookie, UserAgent};
use hyper::mime::{Mime, TopLevel, SubLevel};

use std::borrow::ToOwned;
use std::boxed;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read};
use std::str::FromStr;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thunk::Invoke;

static mut HOST_TABLE: Option<*mut HashMap<String, String>> = None;

pub fn global_init() {
    //TODO: handle bad file path
    let path = match env::var("HOST_FILE") {
        Ok(host_file_path) => host_file_path,
        Err(_) => return,
    };

    let mut file = match File::open(&path) {
        Ok(f) => BufReader::new(f),
        Err(_) => return,
    };

    let mut lines = String::new();
    match file.read_to_string(&mut lines) {
        Ok(()) => (),
        Err(_) => return,
    };

    unsafe {
        let host_table = boxed::into_raw(parse_hostsfile(&lines));
        HOST_TABLE = Some(host_table);
    }
}

/// For use by loaders in responding to a Load message.
pub fn start_sending(start_chan: Sender<LoadResponse>, metadata: Metadata) -> Sender<ProgressMsg> {
    start_sending_opt(start_chan, metadata).ok().unwrap()
}

/// For use by loaders in responding to a Load message that allows content sniffing.
pub fn start_sending_sniffed(start_chan: Sender<LoadResponse>, metadata: Metadata,
                             classifier: Arc<MIMEClassifier>, partial_body: &Vec<u8>)
                             -> Sender<ProgressMsg> {
    start_sending_sniffed_opt(start_chan, metadata, classifier, partial_body).ok().unwrap()
}

/// For use by loaders in responding to a Load message that allows content sniffing.
pub fn start_sending_sniffed_opt(start_chan: Sender<LoadResponse>, mut metadata: Metadata,
                                 classifier: Arc<MIMEClassifier>, partial_body: &Vec<u8>)
                                 -> Result<Sender<ProgressMsg>, ()> {
    if opts::get().sniff_mime_types {
        // TODO: should be calculated in the resource loader, from pull requeset #4094
        let nosniff = false;
        let check_for_apache_bug = false;

        let supplied_type = metadata.content_type.map(|ContentType(Mime(toplevel, sublevel, _))| {
            (format!("{}", toplevel), format!("{}", sublevel))
        });
        metadata.content_type = classifier.classify(nosniff, check_for_apache_bug, &supplied_type, &partial_body).map(|(toplevel, sublevel)| {
            let mime_tp: TopLevel = FromStr::from_str(&toplevel).unwrap();
            let mime_sb: SubLevel = FromStr::from_str(&sublevel).unwrap();
            ContentType(Mime(mime_tp, mime_sb, vec!()))
        });

    }

    start_sending_opt(start_chan, metadata)
}

/// For use by loaders in responding to a Load message.
pub fn start_sending_opt(start_chan: Sender<LoadResponse>, metadata: Metadata) -> Result<Sender<ProgressMsg>, ()> {
    let (progress_chan, progress_port) = channel();
    let result = start_chan.send(LoadResponse {
        metadata:      metadata,
        progress_port: progress_port,
    });
    match result {
        Ok(_) => Ok(progress_chan),
        Err(_) => Err(())
    }
}

/// Create a ResourceTask
pub fn new_resource_task(user_agent: Option<String>) -> ResourceTask {
    let (setup_chan, setup_port) = channel();
    let setup_chan_clone = setup_chan.clone();
    spawn_named("ResourceManager".to_owned(), move || {
        ResourceManager::new(setup_port, user_agent, setup_chan_clone).start();
    });
    setup_chan
}

pub fn parse_hostsfile(hostsfile_content: &str) -> Box<HashMap<String, String>> {
    let ipv4_regex = regex!(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    let ipv6_regex = regex!(r"^([a-fA-F0-9]{0,4}[:]?){1,8}(/\d{1,3})?$");
    let mut host_table = HashMap::new();
    let lines: Vec<&str> = hostsfile_content.split('\n').collect();

    for line in lines.iter() {
        let ip_host: Vec<&str> = line.trim().split(|c: char| c == ' ' || c == '\t').collect();
        if ip_host.len() > 1 {
            if !ipv4_regex.is_match(ip_host[0]) && !ipv6_regex.is_match(ip_host[0]) { continue; }
            let address = ip_host[0].to_owned();

            for token in ip_host.iter().skip(1) {
                if token.as_bytes()[0] == b'#' {
                    break;
                }
                host_table.insert(token.to_owned().to_string(), address.clone());
            }
        }
    }
    box host_table
}

pub fn replace_hosts(mut load_data: LoadData, host_table: *mut HashMap<String, String>) -> LoadData {
    if let Some(h) = load_data.url.domain_mut() {
        unsafe {
            if let Some(ip) = (*host_table).get(h) {
                *h = ip.clone();
            }
        }
    }
    return load_data;
}

struct ResourceManager {
    from_client: Receiver<ControlMsg>,
    user_agent: Option<String>,
    cookie_storage: CookieStorage,
    resource_task: Sender<ControlMsg>,
    mime_classifier: Arc<MIMEClassifier>,
}

impl ResourceManager {
    fn new(from_client: Receiver<ControlMsg>, user_agent: Option<String>,
           resource_task: Sender<ControlMsg>) -> ResourceManager {
        ResourceManager {
            from_client: from_client,
            user_agent: user_agent,
            cookie_storage: CookieStorage::new(),
            resource_task: resource_task,
            mime_classifier: Arc::new(MIMEClassifier::new()),
        }
    }
}

impl ResourceManager {
    fn start(&mut self) {
        loop {
            match self.from_client.recv().unwrap() {
              ControlMsg::Load(load_data) => {
                self.load(load_data)
              }
              ControlMsg::SetCookiesForUrl(request, cookie_list, source) => {
                let header = Header::parse_header(&[cookie_list.into_bytes()]);
                if let Some(SetCookie(cookies)) = header {
                  for bare_cookie in cookies.into_iter() {
                    if let Some(cookie) = cookie::Cookie::new_wrapped(bare_cookie, &request, source) {
                      self.cookie_storage.push(cookie, source);
                    }
                  }
                }
              }
              ControlMsg::GetCookiesForUrl(url, consumer, source) => {
                consumer.send(self.cookie_storage.cookies_for_url(&url, source)).unwrap();
              }
              ControlMsg::Exit => {
                break
              }
            }
        }
    }

    fn load(&mut self, mut load_data: LoadData) {
        unsafe {
            if let Some(host_table) = HOST_TABLE {
                load_data = replace_hosts(load_data, host_table);
            }
        }

        self.user_agent.as_ref().map(|ua| load_data.headers.set(UserAgent(ua.clone())));

        fn from_factory(factory: fn(LoadData, Arc<MIMEClassifier>))
                        -> Box<Invoke<(LoadData, Arc<MIMEClassifier>)> + Send> {
            box move |(load_data, classifier)| {
                factory(load_data, classifier)
            }
        }

        let loader = match &*load_data.url.scheme {
            "file" => from_factory(file_loader::factory),
            "http" | "https" | "view-source" => http_loader::factory(self.resource_task.clone()),
            "data" => from_factory(data_loader::factory),
            "about" => from_factory(about_loader::factory),
            _ => {
                debug!("resource_task: no loader for scheme {}", load_data.url.scheme);
                start_sending(load_data.consumer, Metadata::default(load_data.url))
                    .send(ProgressMsg::Done(Err("no loader for scheme".to_string()))).unwrap();
                return
            }
        };
        debug!("resource_task: loading url: {}", load_data.url.serialize());

        loader.invoke((load_data, self.mime_classifier.clone()));
    }
}
<|endoftext|>


<commit_before>extern crate gtk;

use gui::about;

use gtk::prelude::*;
use gtk::{
    IconSize, Image, Label, Menu, MenuBar, MenuItem, Window,
    WindowPosition, WindowType
};

pub fn main_menu() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }

    let window = Window::new(WindowType::Toplevel);

    window.set_title("Snowball List");
    window.set_position(WindowPosition::Center);
    window.set_size_request(690, 420);

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

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 10);
    let menu_bar = MenuBar::new();
//file menu

    let file = MenuItem::new_with_label("File");
    let file_menu = Menu::new();
    let new = MenuItem::new_with_label("New");
    let open = MenuItem::new_with_label("Open");
    let save = MenuItem::new_with_label("Save");
    let save_as = MenuItem::new_with_label("Save As");
    let settings = MenuItem::new_with_label("Settings");
    let quit = MenuItem::new_with_label("Quit");

    let new_item = MenuItem::new();
    let new_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);

    let new_label = Label::new(Some("New"));
    new_box.pack_start(&new_label, true, true, 0);

    new_item.add(&new_box);

    file_menu.append(&new);
    file_menu.append(&open);
    file_menu.append(&save);
    file_menu.append(&save_as);
    file_menu.append(&settings);
    file_menu.append(&quit);
    file.set_submenu(Some(&file_menu));
    menu_bar.append(&file);

//task menu

    let task = MenuItem::new_with_label("Task");

    let task_menu = Menu::new();
    let new_task = MenuItem::new_with_label("New Task");
    let edit_task = MenuItem::new_with_label("Edit Task");
    let delete_task = MenuItem::new_with_label("Delete Task");
    let take_a_break = MenuItem::new_with_label("Take a break");
    let finish_task = MenuItem::new_with_label("Finish Task");

    let new_item = MenuItem::new();
    let new_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);

    let new_label = Label::new(Some("New"));
    new_box.pack_start(&new_label, true, true, 0);

    new_item.add(&new_box);

    task_menu.append(&new_task);
    task_menu.append(&edit_task);
    task_menu.append(&delete_task);
    task_menu.append(&take_a_break);
    task_menu.append(&finish_task);
    task.set_submenu(Some(&task_menu));

    //end of file

    let task_item = MenuItem::new();
    let task_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    let task_label = Label::new(Some("Task"));
    task_box.pack_start(&task_label, true, true, 0);
    task_item.add(&task_box);

    task_menu.append(&new_task);
    task_menu.append(&edit_task);
    task_menu.append(&delete_task);
    task_menu.append(&take_a_break);
    task_menu.append(&finish_task);
    task.set_submenu(Some(&task_menu));
    menu_bar.append(&task);

    //About Menu
    let about = MenuItem::new_with_label("About");
    let about_label = MenuItem::new_with_label("About");
    let about_menu = Menu::new();
    about_menu.append(&about_label);
    about.set_submenu(Some(&about_menu));
    menu_bar.append(&about);

    //Operations
    quit.connect_activate(|_|
        {
            gtk::main_quit();
        });

    about_label.connect_activate( move |_|
        {
            about::about();
        });

    v_box.pack_start(&menu_bar, false, false, 0);
    window.add(&v_box);
    window.show_all();

    gtk::main();
}
<commit_msg>Removed unneccessery code and edited the menu bar<commit_after>extern crate gtk;

use gui::about;

use gtk::prelude::*;
use gtk::{
    IconSize, Image, Label, Menu, MenuBar, MenuItem, Window,
    WindowPosition, WindowType
};

pub fn main_menu() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }

    let window = Window::new(WindowType::Toplevel);

    window.set_title("Snowball List");
    window.set_position(WindowPosition::Center);
    window.set_size_request(690, 420);

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

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 10);
    let menu_bar = MenuBar::new();
//file menu

    let file = MenuItem::new_with_label("File");
    let file_menu = Menu::new();
    let new = MenuItem::new_with_label("New");
    let open = MenuItem::new_with_label("Open");
    let save = MenuItem::new_with_label("Save");
    let save_as = MenuItem::new_with_label("Save As");
    let settings = MenuItem::new_with_label("Settings");
    let quit = MenuItem::new_with_label("Quit");

    let new_item = MenuItem::new();
    let new_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);

    let new_label = Label::new(Some("New"));
    new_box.pack_start(&new_label, true, true, 0);

    new_item.add(&new_box);

    file_menu.append(&new);
    file_menu.append(&open);
    file_menu.append(&save);
    file_menu.append(&save_as);
    file_menu.append(&settings);
    file_menu.append(&quit);
    file.set_submenu(Some(&file_menu));
    menu_bar.append(&file);

//task menu

    let task = MenuItem::new_with_label("Task");

    let task_menu = Menu::new();
    let new_task = MenuItem::new_with_label("New Task");
    let edit_task = MenuItem::new_with_label("Edit Task");
    let delete_task = MenuItem::new_with_label("Delete Task");
    let finish_task = MenuItem::new_with_label("Finish Task");
    let show_graph = MenuItem::new_with_label("Show Graph");
    let take_a_break = MenuItem::new_with_label("Take a break");

    let new_item = MenuItem::new();
    let new_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);

    let new_label = Label::new(Some("New"));
    new_box.pack_start(&new_label, true, true, 0);

    new_item.add(&new_box);

    let task_item = MenuItem::new();
    let task_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    let task_label = Label::new(Some("Task"));
    task_box.pack_start(&task_label, true, true, 0);
    task_item.add(&task_box);

    task_menu.append(&new_task);
    task_menu.append(&edit_task);
    task_menu.append(&delete_task);
    task_menu.append(&finish_task);
    task_menu.append(&show_graph);
    task_menu.append(&take_a_break);
    task.set_submenu(Some(&task_menu));
    menu_bar.append(&task);

    //About Menu
    let about = MenuItem::new_with_label("About");
    let about_label = MenuItem::new_with_label("About");
    let about_menu = Menu::new();
    about_menu.append(&about_label);
    about.set_submenu(Some(&about_menu));
    menu_bar.append(&about);

    //Operations
    quit.connect_activate(|_|
        {
            gtk::main_quit();
        });

    about_label.connect_activate( move |_|
        {
            about::about();
        });

    v_box.pack_start(&menu_bar, false, false, 0);
    window.add(&v_box);
    window.show_all();

    gtk::main();
}
<|endoftext|>


<commit_before>use feeds::Envelope;
use feeds::Message;
use xmlhelper::encode;

#[allow(non_snake_case)]
#[derive(Debug, PartialEq, Serialize)]
pub struct InventoryMessage {
  pub message_id: String,
  /// Used to identify an individual product. Each product must have a SKU, and each SKU must
  /// be unique.
  pub sku: String,

  /// Indicates whether or not an item is available (any positive number = available; 0 = not
  /// available). Every time a quantity is sent for an item, the existing quantity is replaced by the
  /// new quantity in the feed.
  pub quantity: i32,

  /// The number of days between the order date and the ship date (a whole number between 1
  /// and 30)
  pub fulfillment_latency: i32,
}

impl Message for InventoryMessage {
  fn get_message_type() -> &'static str {
    "Inventory"
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<InventoryMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      write_xml!(w,
        Messages[][
          [{
            for message in self.messages.iter() {
              let sku: &str = message.data.sku.as_ref();
              let quantity = message.data.quantity.to_string();
              let fulfillment_latency = message.data.fulfillment_latency.to_string();
              write_xml!(w,
                Message[][
                  MessageID[][
                    (&message.data.message_id)
                  ]
                  SKU[][sku]
                  Quantity[][(&quantity)]
                  FulfillmentLatency[][(&fulfillment_latency)]
                ]
              )?;
            }
            Ok(())
          }]
        ]
      )?;
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use feeds::OperationType;
  use xmlhelper::encode::XmlWrite;
  use xmlhelper::encode::{EmitterConfig, EventWriter};

  #[test]
  fn test_inventory_feed() {
    let mut writer =
      EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<InventoryMessage>::new("1234567890".to_owned());
      e.add_message(
        InventoryMessage {
          SKU: "p1".to_owned(),
          Quantity: 100,
          FulfillmentLatency: 0,
        },
        Some(OperationType::PartialUpdate),
      )
      .add_message(
        InventoryMessage {
          SKU: "p2".to_owned(),
          Quantity: 200,
          FulfillmentLatency: 0,
        },
        Some(OperationType::PartialUpdate),
      );
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(
      xml,
      r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>Inventory</MessageType>
  <Messages>
    <Message>
      <SKU>p1</SKU>
      <Quantity>100</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
    <Message>
      <SKU>p2</SKU>
      <Quantity>200</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
  </Messages>
</AmazonEnvelope>"#
    );
  }
}
<commit_msg>fix: Fix inventory feed and its test.<commit_after>use feeds::Envelope;
use feeds::Message;
use xmlhelper::encode;

#[allow(non_snake_case)]
#[derive(Debug, PartialEq, Serialize)]
pub struct InventoryMessage {
  pub message_id: String,
  /// Used to identify an individual product. Each product must have a SKU, and each SKU must
  /// be unique.
  pub sku: String,

  /// Indicates whether or not an item is available (any positive number = available; 0 = not
  /// available). Every time a quantity is sent for an item, the existing quantity is replaced by the
  /// new quantity in the feed.
  pub quantity: i32,

  /// The number of days between the order date and the ship date (a whole number between 1
  /// and 30)
  pub fulfillment_latency: i32,
}

impl Message for InventoryMessage {
  fn get_message_type() -> &'static str {
    "Inventory"
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<InventoryMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      for message in self.messages.iter() {
        let sku: &str = message.data.sku.as_ref();
        let quantity = message.data.quantity.to_string();
        let fulfillment_latency = message.data.fulfillment_latency.to_string();
        write_xml!(w,
          Message[][
            MessageID[][
              (&message.data.message_id)
            ]
            SKU[][sku]
            Quantity[][(&quantity)]
            FulfillmentLatency[][(&fulfillment_latency)]
          ]
        )?;
      }
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use feeds::OperationType;
  use xmlhelper::encode::XmlWrite;
  use xmlhelper::encode::{EmitterConfig, EventWriter};

  #[test]
  fn test_inventory_feed() {
    let mut writer =
      EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<InventoryMessage>::new("1234567890".to_owned());
      e.add_message(
        InventoryMessage {
          message_id: "1".to_owned(),
          sku: "p1".to_owned(),
          quantity: 100,
          fulfillment_latency: 0,
        },
        Some(OperationType::PartialUpdate),
      )
      .add_message(
        InventoryMessage {
          message_id: "2".to_owned(),
          sku: "p2".to_owned(),
          quantity: 200,
          fulfillment_latency: 0,
        },
        Some(OperationType::PartialUpdate),
      );
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(
      xml,
      r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>Inventory</MessageType>
  <Message>
    <MessageID>1</MessageID>
    <SKU>p1</SKU>
    <Quantity>100</Quantity>
    <FulfillmentLatency>0</FulfillmentLatency>
  </Message>
  <Message>
    <MessageID>2</MessageID>
    <SKU>p2</SKU>
    <Quantity>200</Quantity>
    <FulfillmentLatency>0</FulfillmentLatency>
  </Message>
</AmazonEnvelope>"#
    );
  }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use crate::{DiskUsage, Pid, ProcessExt, Signal};

use std::path::Path;

impl fmt::Display for ProcessStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Unknown")
    }
}

#[doc = include_str!("../../md_doc/process.md")]
#[derive(Clone)]
pub struct Process {
    pid: Pid,
    parent: Option<Pid>,
}

impl ProcessExt for Process {
    fn new(pid: Pid, parent: Option<Pid>, _start_time: u64) -> Process {
        Process { pid, parent }
    }

    fn kill(&self, _signal: Signal) -> bool {
        false
    }

    fn name(&self) -> &str {
        ""
    }

    fn cmd(&self) -> &[String] {
        &[]
    }

    fn exe(&self) -> &Path {
        &Path::new("")
    }

    fn pid(&self) -> Pid {
        self.pid
    }

    fn environ(&self) -> &[String] {
        &[]
    }

    fn cwd(&self) -> &Path {
        &Path::new("")
    }

    fn root(&self) -> &Path {
        &Path::new("")
    }

    fn memory(&self) -> u64 {
        0
    }

    fn virtual_memory(&self) -> u64 {
        0
    }

    fn parent(&self) -> Option<Pid> {
        self.parent
    }

    fn status(&self) -> ProcessStatus {
        ProcessStatus
    }

    fn start_time(&self) -> u64 {
        0
    }

    fn cpu_usage(&self) -> f32 {
        0.0
    }

    fn disk_usage(&self) -> DiskUsage {
        DiskUsage::default()
    }
}
<commit_msg>Fix build for unknown targets<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use crate::{DiskUsage, Pid, ProcessExt, Signal};

use std::path::Path;

impl fmt::Display for ProcessStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Unknown")
    }
}

#[doc = include_str!("../../md_doc/process.md")]
#[derive(Clone)]
pub struct Process {
    pid: Pid,
    parent: Option<Pid>,
}

impl ProcessExt for Process {
    fn new(pid: Pid, parent: Option<Pid>, _start_time: u64) -> Process {
        Process { pid, parent }
    }

    fn kill(&self, _signal: Signal) -> bool {
        false
    }

    fn name(&self) -> &str {
        ""
    }

    fn cmd(&self) -> &[String] {
        &[]
    }

    fn exe(&self) -> &Path {
        &Path::new("")
    }

    fn pid(&self) -> Pid {
        self.pid
    }

    fn environ(&self) -> &[String] {
        &[]
    }

    fn cwd(&self) -> &Path {
        &Path::new("")
    }

    fn root(&self) -> &Path {
        &Path::new("")
    }

    fn memory(&self) -> u64 {
        0
    }

    fn virtual_memory(&self) -> u64 {
        0
    }

    fn parent(&self) -> Option<Pid> {
        self.parent
    }

    fn status(&self) -> ProcessStatus {
        ProcessStatus::Unknown(0)
    }

    fn start_time(&self) -> u64 {
        0
    }

    fn cpu_usage(&self) -> f32 {
        0.0
    }

    fn disk_usage(&self) -> DiskUsage {
        DiskUsage::default()
    }
}
<|endoftext|>


<commit_before>// use to create a .so/.dll
#![crate_type = "dylib"]

use std::c_str::CString;

/// create a new vector with some values inside for test
///
/// note: we can return directly a Box<Vec<>> and use it
/// as a pointer from C, because as Vec is not a dynamically sized
/// type, we're garantueed that Box is a single pointer
///
/// note2: after using vector_create from C, we will need to destroy
/// the value ourselves
#[no_mangle]
pub extern fn vector_create() -> Box<Vec<String>> {

    let vector : Box<Vec<String>> = box vec![
        "你好".to_string(),
        "好".to_string()
    ];

    vector
}

/// get the size of the vector given in parameter
///
///
#[no_mangle]
pub extern fn vector_size(vector: &Vec<String>) -> u32 {

    vector.len() as u32
}

/// permit to do vector[index] from C
///
/// note: to be 100% correct we should returned
/// *const libc::c_char, but that would required to use the
/// crate libc
///
/// note2: we need to free the pointer returned by this function
/// ourselves
#[no_mangle]
pub extern fn vector_value_get(
    vector: &Vec<String> ,
    index: u32
) -> *const i8 {

    // (*vector) should not be necessary, there's a bug in current
    // rust (as of end of september 2014) which force us to do that
    unsafe { (*vector)[index as uint].to_c_str().unwrap() }

}

///
///
///
#[no_mangle]
pub extern fn vector_value_free (buffer: *const i8) {
    unsafe { CString::new(buffer, true); }
}

/// simple debug function to print the content of a vector
///
///
#[no_mangle]
pub extern fn vector_print(
    vector: &Vec<String>
) {

    for value in vector.iter() {
        println!("from rust {}", value);
    }
}

///
///
///
#[no_mangle]
pub extern fn vector_free(
    vector: Box<Vec<String>>
) {
    let _ = vector;
}
<commit_msg>added comment n rust code<commit_after>// use to create a .so/.dll
#![crate_type = "dylib"]

use std::c_str::CString;

/// create a new vector with some values inside for test
///
/// note: we can return directly a Box<Vec<>> and use it
/// as a pointer from C, because as Vec is not a dynamically sized
/// type, we're garantueed that Box is a single pointer
///
/// note2: after using vector_create from C, we will need to destroy
/// the value ourselves using vector_free function
#[no_mangle]
pub extern fn vector_create() -> Box<Vec<String>> {

    let vector : Box<Vec<String>> = box vec![
        "你好".to_string(),
        "好".to_string()
    ];

    vector
}

/// get the size of the vector given in parameter
///
///
#[no_mangle]
pub extern fn vector_size(vector: &Vec<String>) -> u32 {

    vector.len() as u32
}

/// permit to do vector[index] from C
///
/// note: to be 100% correct we should returned
/// *const libc::c_char, but that would required to use the
/// crate libc
///
/// note2: we need to free the pointer returned by this function
/// ourselves, using the function vector_value_free
#[no_mangle]
pub extern fn vector_value_get(
    vector: &Vec<String> ,
    index: u32
) -> *const i8 {

    // (*vector) should not be necessary, there's a bug in current
    // rust (as of end of september 2014) which force us to do that
    unsafe { (*vector)[index as uint].to_c_str().unwrap() }

}

/// retake ownership, so that we can let rust automatically
/// free the variable at the end of this function scope
///
#[no_mangle]
pub extern fn vector_value_free (buffer: *const i8) {
    unsafe { CString::new(buffer, true); }
}

/// simple debug function to print the content of a vector
///
///
#[no_mangle]
pub extern fn vector_print(
    vector: &Vec<String>
) {

    for value in vector.iter() {
        println!("from rust {}", value);
    }
}

/// Give back the ownership of the vector to rust
/// so that rust can free it
///
#[no_mangle]
pub extern fn vector_free(
    vector: Box<Vec<String>>
) {
    let _ = vector;
}
<|endoftext|>


<commit_before>extern crate caesarcy;

use caesarcy::{encipher, decipher};

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn ciphered_text_can_be_deciphered() {
        let enciphered = encipher(13, "Toto");
        assert_eq!("Toto", decipher(13, &enciphered));
    }
    #[test]
    fn ciphered_text_is_different_with_regards_to_offset() {
        assert_ne!(encipher(13, "Toto"), encipher(14, "Toto"));
    }
    #[test]
    fn ciphered_text_can_contains_unknown_chars() {
        let enciphered = encipher(13, "Foo:bar.");
        assert_eq!("Foo:bar.", decipher(13, &enciphered));
    }
}
<commit_msg>Cleaning french culture.<commit_after>extern crate caesarcy;

use caesarcy::{encipher, decipher};

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn ciphered_text_can_be_deciphered() {
        let enciphered = encipher(13, "FooBar");
        assert_eq!("FooBar", decipher(13, &enciphered));
    }
    #[test]
    fn ciphered_text_is_different_with_regards_to_offset() {
        assert_ne!(encipher(13, "FooBar"), encipher(14, "FooBar"));
    }
    #[test]
    fn ciphered_text_can_contains_unknown_chars() {
        let enciphered = encipher(13, "Foo:bar.");
        assert_eq!("Foo:bar.", decipher(13, &enciphered));
    }
}
<|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 app_units::Au;
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};
use webrender_traits::{NativeFontHandle, GlyphOptions};
use webrender_traits::{GlyphKey};

use freetype::freetype::{FT_Render_Mode, FT_Pixel_Mode};
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter};
use freetype::freetype::{FT_Library, FT_Set_Char_Size};
use freetype::freetype::{FT_Face, FT_Long, FT_UInt, FT_F26Dot6};
use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
use freetype::freetype::{FT_New_Memory_Face, FT_GlyphSlot, FT_LcdFilter};
use freetype::freetype::{FT_Done_Face, FT_Error};

use std::{cmp, mem, ptr, slice};
use std::collections::HashMap;

struct Face {
    face: FT_Face,
}

pub struct FontContext {
    lib: FT_Library,
    faces: HashMap<FontKey, Face>,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

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

fn float_to_fixed_ft(f: f64) -> i32 {
    float_to_fixed(6, f)
}

const SUCCESS: FT_Error = FT_Error(0);

impl FontContext {
    pub fn new() -> FontContext {
        let mut lib: FT_Library = ptr::null_mut();
        unsafe {
            let result = FT_Init_FreeType(&mut lib);
            assert!(result.succeeded(), "Unable to initialize FreeType library {:?}", result);

            // TODO(gw): Check result of this to determine if freetype build supports subpixel.
            let result = FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
            if !result.succeeded() {
                println!("WARN: Initializing a FreeType library build without subpixel AA enabled!");
            }
        }

        FontContext {
            lib: lib,
            faces: HashMap::new(),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: &[u8], index: u32) {
        if !self.faces.contains_key(&font_key) {
            let mut face: FT_Face = ptr::null_mut();
            let result = unsafe {
                FT_New_Memory_Face(self.lib,
                                   bytes.as_ptr(),
                                   bytes.len() as FT_Long,
                                   index as FT_Long,
                                   &mut face)
            };
            if result.succeeded() && !face.is_null() {
                self.faces.insert(*font_key, Face {
                    face: face,
                    //_bytes: bytes
                });
            } else {
                println!("WARN: webrender failed to load font {:?}", font_key);
            }
        }
    }

    pub fn add_native_font(&mut self, _font_key: &FontKey, _native_font_handle: NativeFontHandle) {
        panic!("TODO: Not supported on Linux");
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        if let Some(face) = self.faces.remove(font_key) {
            let result = unsafe {
                FT_Done_Face(face.face)
            };
            assert!(result.succeeded());
        }
    }

    fn load_glyph(&self,
                  font_key: FontKey,
                  size: Au,
                  character: u32) -> Option<FT_GlyphSlot> {

        debug_assert!(self.faces.contains_key(&font_key));
        let face = self.faces.get(&font_key).unwrap();
        let char_size = float_to_fixed_ft(size.to_f64_px());

        assert_eq!(SUCCESS, unsafe {
            FT_Set_Char_Size(face.face, char_size as FT_F26Dot6, 0, 0, 0)
        });

        let result = unsafe {
            FT_Load_Glyph(face.face, character as FT_UInt, 0)
        };

        if result == SUCCESS {
            let slot = unsafe { (*face.face).glyph };
            assert!(slot != ptr::null_mut());
            Some(slot)
        } else {
            error!("Unable to load glyph for {} of size {:?} from font {:?}, {:?}",
                character, size, font_key, result);
            None
        }
    }

    fn get_glyph_dimensions_impl(slot: FT_GlyphSlot) -> Option<GlyphDimensions> {
        let metrics = unsafe { &(*slot).metrics };
        if metrics.width == 0 || metrics.height == 0 {
            None
        } else {
            let left = metrics.horiBearingX >> 6;
            let top = metrics.horiBearingY >> 6;
            let right = (metrics.horiBearingX + metrics.width + 0x3f) >> 6;
            let bottom = (metrics.horiBearingY + metrics.height + 0x3f) >> 6;
            Some(GlyphDimensions {
                left: left as i32,
                top: top as i32,
                width: (right - left) as u32,
                height: (bottom - top) as u32,
            })
        }
    }

    pub fn get_glyph_dimensions(&mut self,
                                key: &GlyphKey) -> Option<GlyphDimensions> {
        self.load_glyph(key.font_key, key.size, key.index)
            .and_then(Self::get_glyph_dimensions_impl)
    }

    pub fn rasterize_glyph(&mut self,
                           key: &GlyphKey,
                           render_mode: FontRenderMode,
                           _glyph_options: Option<GlyphOptions>)
                           -> Option<RasterizedGlyph> {

        let slot = match self.load_glyph(key.font_key, key.size, key.index) {
            Some(slot) => slot,
            None => return None,
        };
        let render_mode = match render_mode {
            FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
            FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
            FontRenderMode::Subpixel => FT_Render_Mode::FT_RENDER_MODE_LCD,
        };

        let result = unsafe { FT_Render_Glyph(slot, render_mode) };
        if result != SUCCESS {
            error!("Unable to rasterize {:?} with {:?}, {:?}", key, render_mode, result);
            return None;
        }

        let dimensions = Self::get_glyph_dimensions_impl(slot).unwrap();
        let bitmap = unsafe { &(*slot).bitmap };
        let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
        info!("Rasterizing {:?} as {:?} with dimensions {:?}", key, render_mode, dimensions);
        // we may be filling only a part of the buffer, so initialize the whole thing with 0
        let mut final_buffer = Vec::with_capacity(dimensions.width as usize *
                                                  dimensions.height as usize *
                                                  4);

        let offset_x = dimensions.left - unsafe { (*slot).bitmap_left };

        for y in 0 .. dimensions.height {
            let src_y = y as i32 - dimensions.top + unsafe { (*slot).bitmap_top };
            if src_y < 0 || src_y >= bitmap.rows as i32 {
                for _x in 0 .. dimensions.width {
                    final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, 0]);
                }
                continue
            }
            let base = unsafe {
                bitmap.buffer.offset((src_y * bitmap.pitch) as isize)
            };
            // determine the destination range of texels that `bitmap` provides data for
            let dst_start = cmp::max(0, -offset_x);
            let dst_end = cmp::min(dimensions.width as i32, bitmap.width as i32 - offset_x);
            for _x in 0 .. dst_start {
                final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, 0]);
            }
            match pixel_mode {
                FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
                    for x in dst_start .. dst_end {
                        let src_x = x + offset_x;
                        let mask = 0x80 >> (src_x & 0x7);
                        let byte = unsafe {
                            *base.offset((src_x >> 3) as isize)
                        };
                        let alpha = if byte & mask != 0 { 0xff } else { 0 };
                        final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, alpha]);
                    }
                }
                FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
                    for x in dst_start .. dst_end {
                        let alpha = unsafe {
                            *base.offset((x + offset_x) as isize)
                        };
                        final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, alpha]);
                    }
                }
                FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
                    for x in dst_start .. dst_end {
                        let src_x = ((x + offset_x) * 3) as isize;
                        assert!(src_x+2 < bitmap.pitch as isize);
                        let t = unsafe {
                            slice::from_raw_parts(base.offset(src_x), 3)
                        };
                        final_buffer.extend_from_slice(&[t[2], t[1], t[0], 0xff]);
                    }
                }
                _ => panic!("Unsupported {:?}", pixel_mode)
            }
            for _x in dst_end .. dimensions.width as i32 {
                final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, 0]);
            }
            assert_eq!(final_buffer.len(), ((y+1) * dimensions.width * 4) as usize);
        }

        Some(RasterizedGlyph {
            width: dimensions.width as u32,
            height: dimensions.height as u32,
            bytes: final_buffer,
        })
    }
}

impl Drop for FontContext {
    fn drop(&mut self) {
        unsafe {
            FT_Done_FreeType(self.lib);
        }
    }
}
<commit_msg>Fixed freetype LCD loading<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 app_units::Au;
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};
use webrender_traits::{NativeFontHandle, GlyphOptions};
use webrender_traits::{GlyphKey};

use freetype::freetype::{FT_Render_Mode, FT_Pixel_Mode};
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter};
use freetype::freetype::{FT_Library, FT_Set_Char_Size};
use freetype::freetype::{FT_Face, FT_Long, FT_UInt, FT_F26Dot6};
use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
use freetype::freetype::{FT_New_Memory_Face, FT_GlyphSlot, FT_LcdFilter};
use freetype::freetype::{FT_Done_Face, FT_Error};

use std::{cmp, mem, ptr, slice};
use std::collections::HashMap;

struct Face {
    face: FT_Face,
}

pub struct FontContext {
    lib: FT_Library,
    faces: HashMap<FontKey, Face>,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

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

fn float_to_fixed_ft(f: f64) -> i32 {
    float_to_fixed(6, f)
}

const SUCCESS: FT_Error = FT_Error(0);

impl FontContext {
    pub fn new() -> FontContext {
        let mut lib: FT_Library = ptr::null_mut();
        unsafe {
            let result = FT_Init_FreeType(&mut lib);
            assert!(result.succeeded(), "Unable to initialize FreeType library {:?}", result);

            // TODO(gw): Check result of this to determine if freetype build supports subpixel.
            let result = FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
            if !result.succeeded() {
                println!("WARN: Initializing a FreeType library build without subpixel AA enabled!");
            }
        }

        FontContext {
            lib: lib,
            faces: HashMap::new(),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: &[u8], index: u32) {
        if !self.faces.contains_key(&font_key) {
            let mut face: FT_Face = ptr::null_mut();
            let result = unsafe {
                FT_New_Memory_Face(self.lib,
                                   bytes.as_ptr(),
                                   bytes.len() as FT_Long,
                                   index as FT_Long,
                                   &mut face)
            };
            if result.succeeded() && !face.is_null() {
                self.faces.insert(*font_key, Face {
                    face: face,
                    //_bytes: bytes
                });
            } else {
                println!("WARN: webrender failed to load font {:?}", font_key);
            }
        }
    }

    pub fn add_native_font(&mut self, _font_key: &FontKey, _native_font_handle: NativeFontHandle) {
        panic!("TODO: Not supported on Linux");
    }

    pub fn delete_font(&mut self, font_key: &FontKey) {
        if let Some(face) = self.faces.remove(font_key) {
            let result = unsafe {
                FT_Done_Face(face.face)
            };
            assert!(result.succeeded());
        }
    }

    fn load_glyph(&self,
                  font_key: FontKey,
                  size: Au,
                  character: u32) -> Option<FT_GlyphSlot> {

        debug_assert!(self.faces.contains_key(&font_key));
        let face = self.faces.get(&font_key).unwrap();
        let char_size = float_to_fixed_ft(size.to_f64_px());

        assert_eq!(SUCCESS, unsafe {
            FT_Set_Char_Size(face.face, char_size as FT_F26Dot6, 0, 0, 0)
        });

        let result = unsafe {
            FT_Load_Glyph(face.face, character as FT_UInt, 0)
        };

        if result == SUCCESS {
            let slot = unsafe { (*face.face).glyph };
            assert!(slot != ptr::null_mut());
            Some(slot)
        } else {
            error!("Unable to load glyph for {} of size {:?} from font {:?}, {:?}",
                character, size, font_key, result);
            None
        }
    }

    fn get_glyph_dimensions_impl(slot: FT_GlyphSlot) -> Option<GlyphDimensions> {
        let metrics = unsafe { &(*slot).metrics };
        if metrics.width == 0 || metrics.height == 0 {
            None
        } else {
            let left = metrics.horiBearingX >> 6;
            let top = metrics.horiBearingY >> 6;
            let right = (metrics.horiBearingX + metrics.width + 0x3f) >> 6;
            let bottom = (metrics.horiBearingY + metrics.height + 0x3f) >> 6;
            Some(GlyphDimensions {
                left: left as i32,
                top: top as i32,
                width: (right - left) as u32,
                height: (bottom - top) as u32,
            })
        }
    }

    pub fn get_glyph_dimensions(&mut self,
                                key: &GlyphKey) -> Option<GlyphDimensions> {
        self.load_glyph(key.font_key, key.size, key.index)
            .and_then(Self::get_glyph_dimensions_impl)
    }

    pub fn rasterize_glyph(&mut self,
                           key: &GlyphKey,
                           render_mode: FontRenderMode,
                           _glyph_options: Option<GlyphOptions>)
                           -> Option<RasterizedGlyph> {

        let slot = match self.load_glyph(key.font_key, key.size, key.index) {
            Some(slot) => slot,
            None => return None,
        };
        let render_mode = match render_mode {
            FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
            FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
            FontRenderMode::Subpixel => FT_Render_Mode::FT_RENDER_MODE_LCD,
        };

        let result = unsafe { FT_Render_Glyph(slot, render_mode) };
        if result != SUCCESS {
            error!("Unable to rasterize {:?} with {:?}, {:?}", key, render_mode, result);
            return None;
        }

        let dimensions = Self::get_glyph_dimensions_impl(slot).unwrap();
        let bitmap = unsafe { &(*slot).bitmap };
        let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
        info!("Rasterizing {:?} as {:?} with dimensions {:?}", key, render_mode, dimensions);
        // we may be filling only a part of the buffer, so initialize the whole thing with 0
        let mut final_buffer = Vec::with_capacity(dimensions.width as usize *
                                                  dimensions.height as usize *
                                                  4);

        let offset_x = dimensions.left - unsafe { (*slot).bitmap_left };
        let src_pixel_width = match pixel_mode {
            FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
                assert!(bitmap.width % 3 == 0);
                bitmap.width / 3
            },
            _ => bitmap.width,
        };
        // determine the destination range of texels that `bitmap` provides data for
        let dst_start = cmp::max(0, -offset_x);
        let dst_end = cmp::min(dimensions.width as i32, src_pixel_width as i32 - offset_x);

        for y in 0 .. dimensions.height {
            let src_y = y as i32 - dimensions.top + unsafe { (*slot).bitmap_top };
            if src_y < 0 || src_y >= bitmap.rows as i32 {
                for _x in 0 .. dimensions.width {
                    final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, 0]);
                }
                continue
            }
            let base = unsafe {
                bitmap.buffer.offset((src_y * bitmap.pitch) as isize)
            };
            for _x in 0 .. dst_start {
                final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, 0]);
            }
            match pixel_mode {
                FT_Pixel_Mode::FT_PIXEL_MODE_MONO => {
                    for x in dst_start .. dst_end {
                        let src_x = x + offset_x;
                        let mask = 0x80 >> (src_x & 0x7);
                        let byte = unsafe {
                            *base.offset((src_x >> 3) as isize)
                        };
                        let alpha = if byte & mask != 0 { 0xff } else { 0 };
                        final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, alpha]);
                    }
                }
                FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
                    for x in dst_start .. dst_end {
                        let alpha = unsafe {
                            *base.offset((x + offset_x) as isize)
                        };
                        final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, alpha]);
                    }
                }
                FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
                    for x in dst_start .. dst_end {
                        let src_x = ((x + offset_x) * 3) as isize;
                        assert!(src_x+2 < bitmap.pitch as isize);
                        let t = unsafe {
                            slice::from_raw_parts(base.offset(src_x), 3)
                        };
                        final_buffer.extend_from_slice(&[t[2], t[1], t[0], 0xff]);
                    }
                }
                _ => panic!("Unsupported {:?}", pixel_mode)
            }
            for _x in dst_end .. dimensions.width as i32 {
                final_buffer.extend_from_slice(&[0xff, 0xff, 0xff, 0]);
            }
            assert_eq!(final_buffer.len(), ((y+1) * dimensions.width * 4) as usize);
        }

        Some(RasterizedGlyph {
            width: dimensions.width as u32,
            height: dimensions.height as u32,
            bytes: final_buffer,
        })
    }
}

impl Drop for FontContext {
    fn drop(&mut self) {
        unsafe {
            FT_Done_FreeType(self.lib);
        }
    }
}
<|endoftext|>


<commit_before>fn on_osmain(f: fn~()) {
    let builder = task::builder();
    task::set_opts(builder, {
        sched: some({
            mode: task::osmain,
            native_stack_size: none
        })
        with task::get_opts(builder)
    });
    let po = comm::port();
    let ch = comm::chan(po);
    task::run(builder) {||
        f();
        comm::send(ch, ());
    }
    comm::recv(po);
}

// FIXME: Needs additional cocoa setup on OS X. rust-cocoa should probably just
// be a dependency
#[test]
#[ignore(cfg(target_os = "macos"))]
fn test_everything() {

    on_osmain() {||
        init([init_video, init_timer]);
        run_tests([
            general::test_was_init,
            general::test_set_error,
            general::test_error,
            general::test_clear_error,
            video::test_set_video_mode,
            // FIXME: Doesn't work when called from a directory that
            // doesn't contain the test image file
            //video::test_blit,
            test_event::test_poll_event_none,
            test_event::test_keyboard
        ]);
        quit();
    }
}

fn run_tests(tests: [fn()]) {
    vec::iter(tests) {|test| test()}
}

mod general {
    fn test_was_init() {
        assert vec::contains(was_init([init_timer]), init_timer);
    }

    fn test_set_error() {
        set_error("test");
        assert get_error() == "test";
    }

    fn test_error() {
        clear_error();
        assert str::is_empty(get_error());
        error(enomem);
        assert str::is_not_empty(get_error());
    }

    fn test_clear_error() {
        set_error("test");
        clear_error();
        assert str::is_empty(get_error());
    }
}

mod test_event {
    fn test_poll_event_none() {
        ::event::poll_event {|event|
            assert event == ::event::no_event;
        }
    }

    fn test_keyboard() {
        io::println("press a key in the window");
        let surface = ::video::set_video_mode(320, 200, 32,
            [::video::swsurface], [::video::doublebuf, ::video::resizable]);
        let mut keydown = false;
        let mut keyup = false;
        while !keydown || !keyup {
            ::event::poll_event {|event|
                alt event {
                  event::keyup_event(_) { keyup = true; }
                  event::keydown_event(_) { keydown = true; }
                  _ { }
                }
            }
        }
        ::video::free_surface(surface);
    }
}

mod video {

    fn test_set_video_mode() {
        let surface = ::video::set_video_mode(320, 200, 32,
            [::video::hwsurface], [::video::doublebuf]);
        assert surface != ptr::null();
        ::video::free_surface(surface);
    }

    fn test_blit() {
        let screen = ::video::set_video_mode(320, 200, 32,
            [::video::swsurface], [::video::doublebuf]);
        assert screen != ptr::null();

        let image = {
            // FIXME: We need to load this from the crate instead of
            // off the filesystem
            let tmp = ::video::load_bmp("rust-logo-128x128-blk.bmp");
            assert tmp != ptr::null();
            let image = ::video::display_format(tmp);
            assert image != ptr::null();
            ::video::free_surface(tmp);
            image
        };

        iter::repeat(1u) {||
            ::video::blit_surface(image, ptr::null(),
                                  screen, ptr::null());
            ::video::flip(screen);
            ::event::poll_event {|_event|
            }
        }

        ::video::free_surface(image);
        ::video::free_surface(screen);
    }
}
<commit_msg>Ignore a test that requires keyboard interaction<commit_after>fn on_osmain(f: fn~()) {
    let builder = task::builder();
    task::set_opts(builder, {
        sched: some({
            mode: task::osmain,
            native_stack_size: none
        })
        with task::get_opts(builder)
    });
    let po = comm::port();
    let ch = comm::chan(po);
    task::run(builder) {||
        f();
        comm::send(ch, ());
    }
    comm::recv(po);
}

// FIXME: Needs additional cocoa setup on OS X. rust-cocoa should probably just
// be a dependency
#[test]
#[ignore(cfg(target_os = "macos"))]
fn test_everything() {

    on_osmain() {||
        init([init_video, init_timer]);
        run_tests([
            general::test_was_init,
            general::test_set_error,
            general::test_error,
            general::test_clear_error,
            video::test_set_video_mode,
            // FIXME: Doesn't work when called from a directory that
            // doesn't contain the test image file
            //video::test_blit,
            test_event::test_poll_event_none
            // FIXME: This test is interactive
            //test_event::test_keyboard
        ]);
        quit();
    }
}

fn run_tests(tests: [fn()]) {
    vec::iter(tests) {|test| test()}
}

mod general {
    fn test_was_init() {
        assert vec::contains(was_init([init_timer]), init_timer);
    }

    fn test_set_error() {
        set_error("test");
        assert get_error() == "test";
    }

    fn test_error() {
        clear_error();
        assert str::is_empty(get_error());
        error(enomem);
        assert str::is_not_empty(get_error());
    }

    fn test_clear_error() {
        set_error("test");
        clear_error();
        assert str::is_empty(get_error());
    }
}

mod test_event {
    fn test_poll_event_none() {
        ::event::poll_event {|event|
            assert event == ::event::no_event;
        }
    }

    fn test_keyboard() {
        io::println("press a key in the window");
        let surface = ::video::set_video_mode(320, 200, 32,
            [::video::swsurface], [::video::doublebuf, ::video::resizable]);
        let mut keydown = false;
        let mut keyup = false;
        while !keydown || !keyup {
            ::event::poll_event {|event|
                alt event {
                  event::keyup_event(_) { keyup = true; }
                  event::keydown_event(_) { keydown = true; }
                  _ { }
                }
            }
        }
        ::video::free_surface(surface);
    }
}

mod video {

    fn test_set_video_mode() {
        let surface = ::video::set_video_mode(320, 200, 32,
            [::video::hwsurface], [::video::doublebuf]);
        assert surface != ptr::null();
        ::video::free_surface(surface);
    }

    fn test_blit() {
        let screen = ::video::set_video_mode(320, 200, 32,
            [::video::swsurface], [::video::doublebuf]);
        assert screen != ptr::null();

        let image = {
            // FIXME: We need to load this from the crate instead of
            // off the filesystem
            let tmp = ::video::load_bmp("rust-logo-128x128-blk.bmp");
            assert tmp != ptr::null();
            let image = ::video::display_format(tmp);
            assert image != ptr::null();
            ::video::free_surface(tmp);
            image
        };

        iter::repeat(1u) {||
            ::video::blit_surface(image, ptr::null(),
                                  screen, ptr::null());
            ::video::flip(screen);
            ::event::poll_event {|_event|
            }
        }

        ::video::free_surface(image);
        ::video::free_surface(screen);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fs;
use std::path::Path;

pub mod tree;
pub mod print;
use self::tree::{DirectoryNode, FileNode, FSNode};

pub fn read_recursive(path: &String) -> FSNode {
    let path = fs::canonicalize(Path::new(&path)).unwrap();
    let mut node = DirectoryNode::new(path.file_name().unwrap().to_str().unwrap().to_owned());

    for entry in fs::read_dir(path).unwrap() {
        let entry = entry.unwrap();
        let meta = entry.metadata().unwrap();
        let name = entry.file_name().to_str().unwrap().to_owned();

        if meta.is_file() {
            node.children.push(FSNode::File(FileNode {
                name: name,
                size: meta.len(),
            }));
            node.size += meta.len();
        } else if meta.is_dir() {
            let path = entry.path().to_str().unwrap().to_owned();
            let dir = read_recursive(&path);
            node.size += dir.size();
            node.children.push(dir);
        }
    }

    node.children.sort_by(biggest_size_first);
    return FSNode::Directory(node);
}

fn biggest_size_first(lhs: &FSNode, rhs: &FSNode) -> Ordering {
    let lhs_size = match lhs {
        &FSNode::Directory(ref d) => d.size,
        &FSNode::File(ref f) => f.size,
    };
    let rhs_size = match rhs {
        &FSNode::Directory(ref d) => d.size,
        &FSNode::File(ref f) => f.size,
    };
    return rhs_size.cmp(&lhs_size);
}
<commit_msg>simplify sorting tree by size<commit_after>use std::cmp::Ordering;
use std::fs;
use std::path::Path;

pub mod tree;
pub mod print;
use self::tree::{DirectoryNode, FileNode, FSNode};

pub fn read_recursive(path: &String) -> FSNode {
    let path = fs::canonicalize(Path::new(&path)).unwrap();
    let mut node = DirectoryNode::new(path.file_name().unwrap().to_str().unwrap().to_owned());

    for entry in fs::read_dir(path).unwrap() {
        let entry = entry.unwrap();
        let meta = entry.metadata().unwrap();
        let name = entry.file_name().to_str().unwrap().to_owned();

        if meta.is_file() {
            node.children.push(FSNode::File(FileNode {
                name: name,
                size: meta.len(),
            }));
            node.size += meta.len();
        } else if meta.is_dir() {
            let path = entry.path().to_str().unwrap().to_owned();
            let dir = read_recursive(&path);
            node.size += dir.size();
            node.children.push(dir);
        }
    }

    node.children.sort_by(biggest_size_first);
    return FSNode::Directory(node);
}

fn biggest_size_first(lhs: &FSNode, rhs: &FSNode) -> Ordering {
    return lhs.size().cmp(&rhs.size()).reverse();
}
<|endoftext|>


<commit_before>pub mod error;

use rustc_serialize::json;
use std::env;
use std::path::PathBuf;
use std::fs::File;
use std::io::Error as StdIoError;
use std::io::ErrorKind;

use std::io::prelude::*; // Required for read_to_string use later.

use self::error::ConfigError;

use cli::arg_types::AccountType;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub auth_token: String,
    pub current: String,
    pub savings: String,
    pub business: String,
}

impl Config {
    pub fn new<S: Into<String>>(auth_token: S, current: S, savings: S, business: S) -> Config {
        Config {
            auth_token: auth_token.into(),
            current: current.into(),
            savings: savings.into(),
            business: business.into(),
        }
    }

    pub fn new_with_auth_token_only<S: Into<String>>(auth_token: S) -> Config {
        Config::new(auth_token.into(),
                    "".to_string(),
                    "".to_string(),
                    "".to_string())
    }

    pub fn get_account_id(&self, account: &AccountType) -> String {
        let default_account_id = self.current.to_owned();
        match *account {
            AccountType::Current => self.current.to_owned(),
            AccountType::Savings => self.savings.to_owned(),
            AccountType::Business => self.business.to_owned(),
            _ => default_account_id,
        }
    }

    pub fn get_account_alias_for_id<'a>(&self, account_id: &str) -> &'a str {
        if *account_id == self.current {
            "(current)"
        } else if *account_id == self.savings {
            "(savings)"
        } else if *account_id == self.business {
            "(business)"
        } else {
            ""
        }
    }
}

pub fn get_config_path() -> PathBuf {
    let fallback_config_path = PathBuf::from("./.tellerrc");
    let append_config_file = |mut p: PathBuf| {
        p.push(".tellerrc");
        p
    };
    env::home_dir().map_or(fallback_config_path, append_config_file)
}

pub fn get_config_file(config_path: &PathBuf) -> Option<File> {
    let config_path_str = config_path.to_str().unwrap_or("[error: config_path#to_str fails]");
    info!("Checking whether config file within {} exists",
          config_path_str);
    let config_file = File::open(&config_path);
    match config_file {
        Err(ref e) if ErrorKind::NotFound == e.kind() => {
            debug!("No config file found");
            None
        }
        Err(_) => panic!("Unable to read config!"),
        Ok(config_file) => Some(config_file),
    }
}

pub fn get_config_file_to_write(config_path: &PathBuf) -> Result<File, StdIoError> {
    let config_file = File::create(&config_path);
    match config_file {
        Err(ref e) if ErrorKind::PermissionDenied == e.kind() => {
            panic!("Permission to read config denied")
        }
        _ => config_file,
    }
}

pub fn get_config() -> Option<Config> {
    let config_file_path = get_config_path();
    match get_config_file(&config_file_path) {
        None => None,
        Some(mut config_file) => {
            match read_config(&mut config_file) {
                Ok(config) => Some(config),
                Err(e) => {
                    panic!("ERROR: attempting to read file {}: {}",
                           config_file_path.display(),
                           e)
                }
            }
        }
    }
}

pub fn read_config(config_file: &mut File) -> Result<Config, ConfigError> {
    let mut content_str = String::new();
    try!(config_file.read_to_string(&mut content_str));

    debug!("config read as: {}", content_str);

    let config: Config = try!(json::decode(&content_str));

    Ok(config)
}

pub fn write_config(config_file: &mut File, config: &Config) -> Result<(), ConfigError> {
    let content_str = try!(json::encode(&config));

    try!(config_file.write_all(content_str.as_bytes()));

    Ok(())
}

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

    #[test]
    fn can_instantiate_config() {
        let expected_auth_token = "fake-auth-token";
        let expected_current = "current-id";
        let expected_savings = "savings-id";
        let expected_business = "business-id";

        let config = Config::new(expected_auth_token, expected_current, expected_savings, expected_business);

        assert_eq!(expected_auth_token, config.auth_token);
        assert_eq!(expected_current, config.current);
        assert_eq!(expected_savings, config.savings);
        assert_eq!(expected_business, config.business);
    }

}
<commit_msg>tests(config): test config helpers<commit_after>pub mod error;

use rustc_serialize::json;
use std::env;
use std::path::PathBuf;
use std::fs::File;
use std::io::Error as StdIoError;
use std::io::ErrorKind;

use std::io::prelude::*; // Required for read_to_string use later.

use self::error::ConfigError;

use cli::arg_types::AccountType;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub auth_token: String,
    pub current: String,
    pub savings: String,
    pub business: String,
}

impl Config {
    pub fn new<S: Into<String>>(auth_token: S, current: S, savings: S, business: S) -> Config {
        Config {
            auth_token: auth_token.into(),
            current: current.into(),
            savings: savings.into(),
            business: business.into(),
        }
    }

    pub fn new_with_auth_token_only<S: Into<String>>(auth_token: S) -> Config {
        Config::new(auth_token.into(),
                    "".to_string(),
                    "".to_string(),
                    "".to_string())
    }

    pub fn get_account_id(&self, account: &AccountType) -> String {
        let default_account_id = self.current.to_owned();
        match *account {
            AccountType::Current => self.current.to_owned(),
            AccountType::Savings => self.savings.to_owned(),
            AccountType::Business => self.business.to_owned(),
            _ => default_account_id,
        }
    }

    pub fn get_account_alias_for_id<'a>(&self, account_id: &str) -> &'a str {
        if *account_id == self.current {
            "(current)"
        } else if *account_id == self.savings {
            "(savings)"
        } else if *account_id == self.business {
            "(business)"
        } else {
            ""
        }
    }
}

pub fn get_config_path() -> PathBuf {
    let fallback_config_path = PathBuf::from("./.tellerrc");
    let append_config_file = |mut p: PathBuf| {
        p.push(".tellerrc");
        p
    };
    env::home_dir().map_or(fallback_config_path, append_config_file)
}

pub fn get_config_file(config_path: &PathBuf) -> Option<File> {
    let config_path_str = config_path.to_str().unwrap_or("[error: config_path#to_str fails]");
    info!("Checking whether config file within {} exists",
          config_path_str);
    let config_file = File::open(&config_path);
    match config_file {
        Err(ref e) if ErrorKind::NotFound == e.kind() => {
            debug!("No config file found");
            None
        }
        Err(_) => panic!("Unable to read config!"),
        Ok(config_file) => Some(config_file),
    }
}

pub fn get_config_file_to_write(config_path: &PathBuf) -> Result<File, StdIoError> {
    let config_file = File::create(&config_path);
    match config_file {
        Err(ref e) if ErrorKind::PermissionDenied == e.kind() => {
            panic!("Permission to read config denied")
        }
        _ => config_file,
    }
}

pub fn get_config() -> Option<Config> {
    let config_file_path = get_config_path();
    match get_config_file(&config_file_path) {
        None => None,
        Some(mut config_file) => {
            match read_config(&mut config_file) {
                Ok(config) => Some(config),
                Err(e) => {
                    panic!("ERROR: attempting to read file {}: {}",
                           config_file_path.display(),
                           e)
                }
            }
        }
    }
}

pub fn read_config(config_file: &mut File) -> Result<Config, ConfigError> {
    let mut content_str = String::new();
    try!(config_file.read_to_string(&mut content_str));

    debug!("config read as: {}", content_str);

    let config: Config = try!(json::decode(&content_str));

    Ok(config)
}

pub fn write_config(config_file: &mut File, config: &Config) -> Result<(), ConfigError> {
    let content_str = try!(json::encode(&config));

    try!(config_file.write_all(content_str.as_bytes()));

    Ok(())
}

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

    use cli::arg_types::AccountType;

    use std::env;
    use std::path::PathBuf;
    use super::get_config_path;

    #[test]
    fn can_instantiate_config() {
        let expected_auth_token = "fake-auth-token";
        let expected_current = "current-id";
        let expected_savings = "savings-id";
        let expected_business = "business-id";

        let config = Config::new(expected_auth_token, expected_current, expected_savings, expected_business);

        assert_eq!(expected_auth_token, config.auth_token);
        assert_eq!(expected_current, config.current);
        assert_eq!(expected_savings, config.savings);
        assert_eq!(expected_business, config.business);
    }

    #[test]
    fn can_get_account_id_from_config() {
        let expected_auth_token = "fake-auth-token";
        let expected_current = "current-id";
        let expected_savings = "savings-id";
        let expected_business = "business-id";

        let config = Config::new(expected_auth_token, expected_current, expected_savings, expected_business);

        assert_eq!("savings-id", config.get_account_id(&AccountType::Savings));
    }

    #[test]
    fn can_get_account_alias_from_config() {
        let expected_auth_token = "fake-auth-token";
        let expected_current = "current-id";
        let expected_savings = "savings-id";
        let expected_business = "business-id";

        let config = Config::new(expected_auth_token, expected_current, expected_savings, expected_business);

        assert_eq!("(savings)", config.get_account_alias_for_id(&expected_savings));
    }

    // test:
    //
    // read_config: Read trait
    // write_config: Write trait
    //
    // get_config_file and get_config_file_to_write can't be tested afaik.
    // get_config: looks like it's not possible to test without get_config_file.

    #[test]
    fn can_get_config_path() {
        let config_path = get_config_path();
        let home_dir = env::home_dir().unwrap_or(PathBuf::from("."));
        assert_eq!(format!("{}/.tellerrc", home_dir.display()), config_path.to_str().unwrap());
    }

}
<|endoftext|>


<commit_before>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

// A result type that's specfici to the Reader module.
// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

// Reader struct of its basic properties.
pub struct Reader {
    // Path to file where the Reader is created.
    path: Path,
    // BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    // BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
}

// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> Box<File>;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
    // Encodes a record to Base64 (with standard encoding).
    fn encode_record(&self, String) -> String;
    // Decoes a record from Base64.
    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {
    // Creates a new Reader from the Path provided.
    // Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    // If the file doesn't exist, it is created.
    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    // This is a helder function that realistically shouldn't exist in production.
    // Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    // Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    // Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => Box::new(file),
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

// Test setup code. Current functions:
//  - Create a new file 'tests/base-test.txt'
//  - Write a 2x2 matrix of records into the base-test.txt file
//  - If 'tests/base-test-created.txt' is created, delete it
//  - Returns a Reader object to 'tests/base-test.txt'
#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("Unable to create test file");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<commit_msg>Added a read_line function to controller mod<commit_after>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

// A result type that's specfici to the Reader module.
// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

// Reader struct of its basic properties.
pub struct Reader {
    // Path to file where the Reader is created.
    path: Path,
    // BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    // BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
}

// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> Box<File>;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
    // Encodes a record to Base64 (with standard encoding).
    fn encode_record(&self, String) -> String;
    // Decoes a record from Base64.
    fn decode_record(&self, String) -> String; //TODO Maybe change this to JSON later?

}

impl Reader {
    // Creates a new Reader from the Path provided.
    // Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    // If the file doesn't exist, it is created.
    pub fn new(apath: Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => { panic!("Failed to create a read buffer to file path."); }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => { panic!("Failed to create a write buffer to file path."); }
                }
            }
        }
    }

    // This is a helder function that realistically shouldn't exist in production.
    // Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
        //    println!("{}", line_iter.unwrap());
        //    let line = String::from_str(file.read_line().ok().expect("Nothing to read.").trim());
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    // Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    // Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

    // Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => { panic!("Unable to read next line. BufferedReader error."); },
        }
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => Box::new(file),
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

    fn encode_record(&self, item: String) -> String {
        item.container_as_bytes().to_base64(STANDARD)
    }

    fn decode_record(&self, item: String) -> String {
        match item.as_slice().from_base64() {
            Ok(vec) => {
                match String::from_utf8(vec) {
                    Ok(e)       => e,
                    Err(..)  => panic!("Invalid UTF-8 sequence."),
                }
            }
            Err(..) => panic!("Corrupt data, unable to decode."),
        }
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    let path = Path::new("tests/base-test-created.txt");
    assert!(!path.exists());
    let reader = Reader::new(path.clone());
    assert!(path.exists());
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let mut reader = setup();
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_encode_string() {
    let reader = setup();
    let expected = "dGhpcyBpcyBhIGxpbmU=";
    let result = reader.encode_record("this is a line".to_string());
    assert_eq![expected, result];
}

#[test]
fn test_decode_string() {
    let reader = setup();
    let expected = "this is a line";
    let result = reader.decode_record("dGhpcyBpcyBhIGxpbmU=".to_string());
    assert_eq![expected, result];
}

// Test setup code. Current functions:
//  - Create a new file 'tests/base-test.txt'
//  - Write a 2x2 matrix of records into the base-test.txt file
//  - If 'tests/base-test-created.txt' is created, delete it
//  - Returns a Reader object to 'tests/base-test.txt'
#[allow(dead_code, unused_must_use)]
fn setup() -> Reader {
    use std::io::fs;

    let mut file = File::create(&Path::new("tests/base-test.txt")).ok().expect("Unable to create test file");
    file.write_str("10 11\n20 21\n");

    let p = Path::new("tests/base-test-created.txt");
    if p.exists() {
        fs::unlink(&p);
    }

    Reader::new(Path::new("tests/base-test.txt"))
}
<|endoftext|>