<commit_before>//! Functions related to determining if the current Event should be Handled

use Event;
use Filter::{Disabled, NotRefresh, Active};

pub enum Filter<'a> {
    Disabled,
    TooSoon(u64,  // current
            u64), // required
    NotRefresh(u64), // checks until next
    Active(&'a Event),
}

macro_rules! iron_filter{
    ($f:expr) => {
        match $f {
            Active(event) => event,
            _ => return $f
        }
    }
}

/// Run all filters in sequence
///
/// * `filter_disabled`
/// * `filter_repeated`
/// * `filter_silenced` (todo)
/// * `filter_dependencies` (todo)
///
/// in sequence.
pub fn run_filters<'a>(event: &'a Event) -> Filter<'a> {
    let mut event = iron_filter!(filter_disabled(event));
    event = iron_filter!(filter_repeated(event));

    Active(event)
}

/// Filter checks tha are self configured as disabled.
///
/// Checks self-register as disabled by setting `"alert": false` in their
/// configuration.
pub fn filter_disabled<'a>(event: &'a Event) -> Filter<'a> {
    match event.check.alert {
        Some(alert) => if alert { Active(event) } else { Disabled },
        None => Active(event)
    }
}

/// Allow events that:
///
/// * Are of any action other than `"create"`
/// * Have occured exactly `min_occurrences` times
/// * Are occuring exactly on the `refresh` border
///
/// Filter everything else.
pub fn filter_repeated<'a>(event: &'a Event) -> Filter<'a> {
    match event.action {
        Some(ref action) => if action.as_slice() != "create" {
            return Active(event)
        },
        None => {}
    };

    let min_occurrences = event.check.occurrences.unwrap_or(1);
    if event.occurrences == min_occurrences {
        return Active(event)
    }

    let interval = event.check.interval;
    let refresh = event.check.refresh;

    if event.occurrences > min_occurrences {
        // number of checks required to hit "refresh" duration
        let intervals = refresh / interval;
        let next = event.occurrences % intervals;
        if intervals != 0 && next != 0 {
            return NotRefresh(next);
        }
    }

    Active(event)
}
<commit_msg>Improve filter::Filter::NotRefresh<commit_after>//! Functions related to determining if the current Event should be Handled

use Event;
use Filter::{Disabled, NotRefresh, Active};

pub enum Filter<'a> {
    Disabled,
    TooSoon(u64,  // current
            u64), // required
    NotRefresh(u64, // interval
               u64), // checks until next
    Active(&'a Event),
}

macro_rules! iron_filter{
    ($f:expr) => {
        match $f {
            Active(event) => event,
            _ => return $f
        }
    }
}

/// Run all filters in sequence
///
/// * `filter_disabled`
/// * `filter_repeated`
/// * `filter_silenced` (todo)
/// * `filter_dependencies` (todo)
///
/// in sequence.
pub fn run_filters<'a>(event: &'a Event) -> Filter<'a> {
    let mut event = iron_filter!(filter_disabled(event));
    event = iron_filter!(filter_repeated(event));

    Active(event)
}

/// Filter checks tha are self configured as disabled.
///
/// Checks self-register as disabled by setting `"alert": false` in their
/// configuration.
pub fn filter_disabled<'a>(event: &'a Event) -> Filter<'a> {
    match event.check.alert {
        Some(alert) => if alert { Active(event) } else { Disabled },
        None => Active(event)
    }
}

/// Allow events that:
///
/// * Are of any action other than `"create"`
/// * Have occured exactly `min_occurrences` times
/// * Are occuring exactly on the `refresh` border
///
/// Filter everything else.
pub fn filter_repeated<'a>(event: &'a Event) -> Filter<'a> {
    match event.action {
        Some(ref action) => if action.as_slice() != "create" {
            return Active(event)
        },
        None => {}
    };

    let min_occurrences = event.check.occurrences.unwrap_or(1);
    if event.occurrences == min_occurrences {
        return Active(event)
    }

    let interval = event.check.interval;
    let refresh = event.check.refresh;

    if event.occurrences > min_occurrences {
        // number of checks required to hit "refresh" duration
        let intervals = refresh / interval;
        let next = event.occurrences % intervals;
        if intervals != 0 && next != 0 {
            return NotRefresh(interval, next);
        }
    }

    Active(event)
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{context::XContext, Result};
use anyhow::bail;
use log::{info, warn};
use structopt::{clap::arg_enum, StructOpt};

#[derive(Debug, StructOpt)]
pub struct Args {
    /// Mode to run in
    #[structopt(long, case_insensitive = true, possible_values = &WorkspaceHackMode::variants(), default_value = "write")]
    mode: WorkspaceHackMode,
}

arg_enum! {
    #[derive(Clone, Copy, Debug)]
    /// Valid modes for generate-workspace-hack
    pub enum WorkspaceHackMode {
        Write,
        Diff,
        Check,
        Verify,
        Disable,
    }
}

pub fn run(args: Args, xctx: XContext) -> Result<()> {
    let mut hakari_builder = xctx.core().hakari_builder()?;

    match args.mode {
        WorkspaceHackMode::Verify => {
            hakari_builder.set_verify_mode(true);
            let hakari = hakari_builder.compute();
            if hakari.output_map.is_empty() {
                info!("workspace-hack is valid");
            } else {
                for ((platform_idx, package_id), v) in &hakari.computed_map {
                    for &(build_platform, inner_map) in v.inner_maps().iter() {
                        if inner_map.len() > 1 {
                            println!(
                                "platform idx {:?} on {:?}, package ID: {}",
                                platform_idx, build_platform, package_id
                            );
                            for (feature_set, packages) in inner_map {
                                let features: Vec<_> = feature_set.iter().copied().collect();
                                println!("  for features {}:", features.join(", "));
                                for (package, f) in packages {
                                    println!("    * {} ({:?})", package.name(), f);
                                }
                            }
                        }
                    }
                }
                warn!("workspace-hack doesn't unify everything successfully");
            }
        }
        WorkspaceHackMode::Disable => {
            let existing_toml = hakari_builder
                .read_toml()
                .expect("hakari package specified by builder")?;
            let disabled_msg = "\n\
            # Disabled through `cargo x generate-workspace-hack --mode disable`.\n\
            # To re-enable, `run cargo x generate-workspace-hack`.\n\
            \n";
            existing_toml.write_to_file(disabled_msg)?;
        }
        _other => {
            let hakari = hakari_builder.compute();
            let existing_toml = hakari
                .read_toml()
                .expect("hakari package specified by builder")?;
            let new_toml = hakari.to_toml_string(&xctx.core().hakari_toml_options())?;

            match args.mode {
                WorkspaceHackMode::Write => {
                    // Write out the contents to the TOML file.
                    existing_toml.write_to_file(&new_toml)?;
                }
                WorkspaceHackMode::Diff => {
                    let patch = existing_toml.diff_toml(&new_toml);
                    // TODO: add global coloring options to x
                    let formatter = hakari::diffy::PatchFormatter::new().with_color();
                    let diff = formatter.fmt_patch(&patch);
                    println!("{}", diff);
                }
                WorkspaceHackMode::Check => {
                    if existing_toml.is_changed(&new_toml) {
                        bail!("existing TOML is different from generated version (run with --mode diff for diff)");
                    }
                }
                WorkspaceHackMode::Disable | WorkspaceHackMode::Verify => {
                    unreachable!("already processed in outer match")
                }
            }
        }
    };

    Ok(())
}
<commit_msg>[x] generate-workspace-hack: update Cargo.lock if contents changed<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{cargo::Cargo, context::XContext, Result};
use anyhow::bail;
use log::{info, warn};
use structopt::{clap::arg_enum, StructOpt};

#[derive(Debug, StructOpt)]
pub struct Args {
    /// Mode to run in
    #[structopt(long, case_insensitive = true, possible_values = &WorkspaceHackMode::variants(), default_value = "write")]
    mode: WorkspaceHackMode,
}

arg_enum! {
    #[derive(Clone, Copy, Debug)]
    /// Valid modes for generate-workspace-hack
    pub enum WorkspaceHackMode {
        Write,
        Diff,
        Check,
        Verify,
        Disable,
    }
}

pub fn run(args: Args, xctx: XContext) -> Result<()> {
    let mut hakari_builder = xctx.core().hakari_builder()?;
    let &hakari_package = hakari_builder
        .hakari_package()
        .expect("hakari package specified by builder");

    let update_cargo_lock = match args.mode {
        WorkspaceHackMode::Verify => {
            hakari_builder.set_verify_mode(true);
            let hakari = hakari_builder.compute();
            if hakari.output_map.is_empty() {
                info!("workspace-hack is valid");
            } else {
                for ((platform_idx, package_id), v) in &hakari.computed_map {
                    for &(build_platform, inner_map) in v.inner_maps().iter() {
                        if inner_map.len() > 1 {
                            println!(
                                "platform idx {:?} on {:?}, package ID: {}",
                                platform_idx, build_platform, package_id
                            );
                            for (feature_set, packages) in inner_map {
                                let features: Vec<_> = feature_set.iter().copied().collect();
                                println!("  for features {}:", features.join(", "));
                                for (package, f) in packages {
                                    println!("    * {} ({:?})", package.name(), f);
                                }
                            }
                        }
                    }
                }
                warn!("workspace-hack doesn't unify everything successfully");
            }

            false
        }
        WorkspaceHackMode::Disable => {
            let existing_toml = hakari_builder
                .read_toml()
                .expect("hakari package specified by builder")?;
            let disabled_msg = "\n\
            # Disabled through `cargo x generate-workspace-hack --mode disable`.\n\
            # To re-enable, `run cargo x generate-workspace-hack`.\n\
            \n";
            existing_toml.write_to_file(disabled_msg)?
        }
        _other => {
            let hakari = hakari_builder.compute();
            let existing_toml = hakari
                .read_toml()
                .expect("hakari package specified by builder")?;
            let new_toml = hakari.to_toml_string(&xctx.core().hakari_toml_options())?;

            match args.mode {
                WorkspaceHackMode::Write => {
                    // Write out the contents to the TOML file.
                    existing_toml.write_to_file(&new_toml)?
                }
                WorkspaceHackMode::Diff => {
                    let patch = existing_toml.diff_toml(&new_toml);
                    // TODO: add global coloring options to x
                    let formatter = hakari::diffy::PatchFormatter::new().with_color();
                    let diff = formatter.fmt_patch(&patch);
                    println!("{}", diff);
                    false
                }
                WorkspaceHackMode::Check => {
                    if existing_toml.is_changed(&new_toml) {
                        bail!("existing TOML is different from generated version (run with --mode diff for diff)");
                    }
                    false
                }
                WorkspaceHackMode::Disable | WorkspaceHackMode::Verify => {
                    unreachable!("already processed in outer match")
                }
            }
        }
    };

    // Update Cargo.lock if the file on disk changed.
    if update_cargo_lock {
        info!("Workspace hack contents changed, updating Cargo.lock");
        let mut cmd = Cargo::new(xctx.config().cargo_config(), "update", false);
        cmd.args(&["--package", hakari_package.name()]);
        cmd.run()?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use iron::prelude::*;
use persistent::{Write, State};
use rand::{thread_rng, Rng};

use rustorm::pool::ManagedPool;
use iron::typemap::Key;
use window_service::window::Window;
use rustorm::table::Table;
use std::collections::BTreeMap;
use rustorm::pool::Platform;
use rustorm::database::DbError;
use rustorm::database::Database;
use std::sync::{Arc,Mutex, RwLock};

pub struct GlobalPools{
	pub cache_map: BTreeMap<String, Cache>, //caches indexed by db_url
}

impl Key for GlobalPools{
	type Value = GlobalPools;
}

impl GlobalPools{

	/// initialize the pools
	pub fn new()->Self{
		GlobalPools{
			cache_map: BTreeMap::new()
		}
	}

	pub fn from_request(req: &mut Request)->Arc<RwLock<Self>>{
		let global = req.get::<State<GlobalPools>>().unwrap();
		global
	}

	pub fn has_cache(&self, db_url: &str)->bool{
		self.cache_map.contains_key(db_url)
	}
	pub fn has_cached_tables(&self, db_url: &str)->bool{
		match self.get_cache(db_url){
			Some(cache) => cache.tables.is_some(),
			None => false
		}
	}

	pub fn get_cache(&self, db_url: &str)->Option<&Cache>{
		self.cache_map.get(db_url)
	}
	pub fn get_cached_tables(&self, db_url: &str)->Option<Vec<Table>>{
		match self.get_cache(db_url){
			Some(cache) => {
				match cache.tables{
					Some(ref tables) => Some(tables.clone()),
					None => None
				}
			}
			None => None
		}
	}

	pub fn has_cached_windows(&self, db_url: &str)->bool{
		match self.get_cache(db_url){
			Some(cache) => cache.windows.is_some(),
			None => false
		}
	}
	pub fn get_cached_windows(&self, db_url: &str)->Option<Vec<Window>>{
		match self.get_cache(db_url){
			Some(cache) => {
				match cache.windows{
					Some(ref windows) => Some(windows.clone()),
					None => None
				}
			}
			None => None
		}
	}
    /// cache this window values to this db_url
	pub fn cache_windows(&mut self, db_url: &str, windows: Vec<Window>){
		if self.has_cache(db_url) {
			let mut cache =  self.cache_map.remove(db_url).unwrap();
			cache.set_windows(windows);
			self.cache_map.insert(db_url.to_owned(), cache);
		}
		else{
			let mut cache = Cache::new(db_url);
			cache.set_windows(windows);
			self.cache_map.insert(db_url.to_owned(), cache);
		}
    }

	pub fn get_connection(&mut self, db_url: &str)->Result<Platform, DbError>{
		if self.has_cache(db_url){
			let platform = self.get_cache(db_url).unwrap().get_connection();
			Ok(platform)
		}else{
			let cache = Cache::new(db_url);
			self.cache_map.insert(db_url.to_owned(), cache);
			//try again
			self.get_connection(db_url)
		}
	}

	pub fn cache_tables(&mut self, db_url: &str, tables: Vec<Table>){
		if self.has_cache(db_url){
			let mut cache = self.cache_map.remove(db_url).unwrap();
			cache.set_tables(tables);
			self.cache_map.insert(db_url.to_owned(), cache);
		}else{
			let mut cache = Cache::new(db_url);
			cache.set_tables(tables);
			self.cache_map.insert(db_url.to_owned(), cache);
		}
	}

}

/// items cached, unique for each db_url connection
pub struct Cache{
	/// connections are cached here as well
	pub managed_pool: ManagedPool,
    /// windows extraction is an expensive operation and doesn't change very often
	/// None indicates, that nothing is cached yet, empty can be indicated as cached
    pub windows: Option<Vec<Window>>,
    /// tables extraction is an expensive operation and doesn't change very often
    pub tables: Option<Vec<Table>>,
}

impl Cache{

	fn new(db_url:&str)->Self{
		let pool = ManagedPool::init(db_url, 10).unwrap();
		Cache{
			managed_pool: pool,
			windows: None,
			tables: None,
		}
	}

	fn set_windows(&mut self, windows: Vec<Window>){
		self.windows = Some(windows);
	}
	fn set_tables(&mut self, tables: Vec<Table>){
		self.tables = Some(tables);
	}

	pub fn get_connection(&self)->Platform{
		self.managed_pool.connect().unwrap()
	}
}

// the db_url is stored in the headers
pub fn get_db_url(req: &Request)->Option<String>{
	let db_url: Option<&[Vec<u8>]> = req.headers.get_raw("db_url");
	match db_url{
		Some(db_url) => {
			let first = &db_url[0];
			let url = String::from_utf8(first.clone()).unwrap();
			Some(url)
		},
		None => None
	}
}

<commit_msg>Made DB pool max to 100<commit_after>use iron::prelude::*;
use persistent::{Write, State};
use rand::{thread_rng, Rng};

use rustorm::pool::ManagedPool;
use iron::typemap::Key;
use window_service::window::Window;
use rustorm::table::Table;
use std::collections::BTreeMap;
use rustorm::pool::Platform;
use rustorm::database::DbError;
use rustorm::database::Database;
use std::sync::{Arc,Mutex, RwLock};

pub struct GlobalPools{
	pub cache_map: BTreeMap<String, Cache>, //caches indexed by db_url
}

impl Key for GlobalPools{
	type Value = GlobalPools;
}

impl GlobalPools{

	/// initialize the pools
	pub fn new()->Self{
		GlobalPools{
			cache_map: BTreeMap::new()
		}
	}

	pub fn from_request(req: &mut Request)->Arc<RwLock<Self>>{
		let global = req.get::<State<GlobalPools>>().unwrap();
		global
	}

	pub fn has_cache(&self, db_url: &str)->bool{
		self.cache_map.contains_key(db_url)
	}
	pub fn has_cached_tables(&self, db_url: &str)->bool{
		match self.get_cache(db_url){
			Some(cache) => cache.tables.is_some(),
			None => false
		}
	}

	pub fn get_cache(&self, db_url: &str)->Option<&Cache>{
		self.cache_map.get(db_url)
	}
	pub fn get_cached_tables(&self, db_url: &str)->Option<Vec<Table>>{
		match self.get_cache(db_url){
			Some(cache) => {
				match cache.tables{
					Some(ref tables) => Some(tables.clone()),
					None => None
				}
			}
			None => None
		}
	}

	pub fn has_cached_windows(&self, db_url: &str)->bool{
		match self.get_cache(db_url){
			Some(cache) => cache.windows.is_some(),
			None => false
		}
	}
	pub fn get_cached_windows(&self, db_url: &str)->Option<Vec<Window>>{
		match self.get_cache(db_url){
			Some(cache) => {
				match cache.windows{
					Some(ref windows) => Some(windows.clone()),
					None => None
				}
			}
			None => None
		}
	}
    /// cache this window values to this db_url
	pub fn cache_windows(&mut self, db_url: &str, windows: Vec<Window>){
		if self.has_cache(db_url) {
			let mut cache =  self.cache_map.remove(db_url).unwrap();
			cache.set_windows(windows);
			self.cache_map.insert(db_url.to_owned(), cache);
		}
		else{
			let mut cache = Cache::new(db_url);
			cache.set_windows(windows);
			self.cache_map.insert(db_url.to_owned(), cache);
		}
    }

	pub fn get_connection(&mut self, db_url: &str)->Result<Platform, DbError>{
		if self.has_cache(db_url){
			let platform = self.get_cache(db_url).unwrap().get_connection();
			Ok(platform)
		}else{
			let cache = Cache::new(db_url);
			self.cache_map.insert(db_url.to_owned(), cache);
			//try again
			self.get_connection(db_url)
		}
	}

	pub fn cache_tables(&mut self, db_url: &str, tables: Vec<Table>){
		if self.has_cache(db_url){
			let mut cache = self.cache_map.remove(db_url).unwrap();
			cache.set_tables(tables);
			self.cache_map.insert(db_url.to_owned(), cache);
		}else{
			let mut cache = Cache::new(db_url);
			cache.set_tables(tables);
			self.cache_map.insert(db_url.to_owned(), cache);
		}
	}

}

/// items cached, unique for each db_url connection
pub struct Cache{
	/// connections are cached here as well
	pub managed_pool: ManagedPool,
    /// windows extraction is an expensive operation and doesn't change very often
	/// None indicates, that nothing is cached yet, empty can be indicated as cached
    pub windows: Option<Vec<Window>>,
    /// tables extraction is an expensive operation and doesn't change very often
    pub tables: Option<Vec<Table>>,
}

impl Cache{

	fn new(db_url:&str)->Self{
		let pool = ManagedPool::init(db_url, 100).unwrap();
		Cache{
			managed_pool: pool,
			windows: None,
			tables: None,
		}
	}

	fn set_windows(&mut self, windows: Vec<Window>){
		self.windows = Some(windows);
	}
	fn set_tables(&mut self, tables: Vec<Table>){
		self.tables = Some(tables);
	}

	pub fn get_connection(&self)->Platform{
		self.managed_pool.connect().unwrap()
	}
}

// the db_url is stored in the headers
pub fn get_db_url(req: &Request)->Option<String>{
	let db_url: Option<&[Vec<u8>]> = req.headers.get_raw("db_url");
	match db_url{
		Some(db_url) => {
			let first = &db_url[0];
			let url = String::from_utf8(first.clone()).unwrap();
			Some(url)
		},
		None => None
	}
}

<|endoftext|>


<commit_before>use std::f32;
use std::ops::Index;
use std::cmp::PartialOrd;
use std::fmt;

use na::{Point3, Point2, Norm, BaseNum};
use num::Bounded;

use {Vector3f, Point3f, Point2f, Point2i, lerp, min, max};
use ray::Ray;
use stats;

pub type Bounds3f = Bounds3<f32>;

/// Axis Aligned Bounding Box
#[derive(Debug, Copy, Clone)]
pub struct Bounds3<T> {
    pub p_min: Point3<T>,
    pub p_max: Point3<T>,
}

impl<T> Bounds3<T>
    where T: BaseNum + Bounded + PartialOrd + Into<f32>
{
    pub fn new() -> Bounds3<T> {
        let min = T::min_value();
        let max = T::max_value();
        Bounds3 {
            p_min: Point3::new(max, max, max),
            p_max: Point3::new(min, min, min),
        }
    }

    pub fn from_point(point: &Point3<T>) -> Bounds3<T> {
        Bounds3 {
            p_min: *point,
            p_max: *point,
        }
    }

    pub fn from_points(p1: &Point3<T>, p2: &Point3<T>) -> Bounds3<T> {
        Bounds3 {
            p_min: Point3::new(min(p1.x, p2.x), min(p1.y, p2.y), min(p1.z, p2.z)),
            p_max: Point3::new(max(p1.x, p2.x), max(p1.y, p2.y), max(p1.z, p2.z)),
        }
    }

    pub fn corner(&self, corner: usize) -> Point3<T> {
        Point3::new(self[corner & 1].x,
                    self[if corner & 2 != 0 { 1 } else { 0 }].y,
                    self[if corner & 4 != 0 { 1 } else { 0 }].y)
    }

    pub fn extend(&mut self, p: Point3<T>) {
        if p.x < self.p_min.x {
            self.p_min.x = p.x
        }
        if p.y < self.p_min.y {
            self.p_min.y = p.y
        }
        if p.z < self.p_min.z {
            self.p_min.z = p.z
        }
        if p.x > self.p_max.x {
            self.p_max.x = p.x
        }
        if p.y > self.p_max.y {
            self.p_max.y = p.y
        }
        if p.z > self.p_max.z {
            self.p_max.z = p.z
        }
    }

    pub fn maximum_extent(&self) -> Axis {
        let v = self.p_max - self.p_min;
        if v.x > v.y {
            if v.x > v.z { Axis::X } else { Axis::Z }
        } else if v.y > v.z {
            Axis::Y
        } else {
            Axis::Z
        }
    }

    pub fn union(bbox1: &Bounds3<T>, bbox2: &Bounds3<T>) -> Bounds3<T> {
        let min = Point3::new(min(bbox1.p_min.x, bbox2.p_min.x),
                              min(bbox1.p_min.y, bbox2.p_min.y),
                              min(bbox1.p_min.z, bbox2.p_min.z));
        let max = Point3::new(max(bbox1.p_max.x, bbox2.p_max.x),
                              max(bbox1.p_max.y, bbox2.p_max.y),
                              max(bbox1.p_max.z, bbox2.p_max.z));

        Bounds3 {
            p_min: min,
            p_max: max,
        }
    }

    pub fn union_point(bbox: &Bounds3<T>, p: &Point3<T>) -> Bounds3<T> {
        let mut b = *bbox;
        b.extend(*p);
        b
    }

    pub fn intersect_p(&self, ray: &Ray) -> bool {
        let invdir = Vector3f::new(1.0 / ray.d.x, 1.0 / ray.d.y, 1.0 / ray.d.z);
        let sign = [(ray.d.x < 0.0) as usize, (ray.d.y < 0.0) as usize, (ray.d.z < 0.0) as usize];

        self.intersect_p_fast(ray, &invdir, &sign)
    }

    pub fn intersect_p_fast(&self, ray: &Ray, inv_dir: &Vector3f, dir_is_neg: &[usize; 3]) -> bool {
        stats::inc_fast_bbox_isect();
        // Check intersection with X and Y slab
        let mut tmin = (self[dir_is_neg[0]].x.into() - ray.o.x) * inv_dir.x;
        let mut tmax = (self[1 - dir_is_neg[0]].x.into() - ray.o.x) * inv_dir.x;
        let tymin = (self[dir_is_neg[1]].y.into() - ray.o.y) * inv_dir.y;
        let tymax = (self[1 - dir_is_neg[1]].y.into() - ray.o.y) * inv_dir.y;
        if (tmin > tymax) || (tymin > tmax) {
            return false;
        }
        if tymin > tmin {
            tmin = tymin;
        }
        if tymax < tmax {
            tmax = tymax;
        }
        // Check intersection with Z slab
        let tzmin = (self[dir_is_neg[2]].z.into() - ray.o.z) * inv_dir.z;
        let tzmax = (self[1 - dir_is_neg[2]].z.into() - ray.o.z) * inv_dir.z;
        if (tmin > tzmax) || (tzmin > tmax) {
            return false;
        }
        if tzmin > tmin {
            tmin = tzmin;
        }
        if tzmax < tmax {
            tmax = tzmax;
        }

        tmin < ray.t_max && tmax > 0.0
    }

    /// Linearly interpolate a point inside the bounds
    pub fn lerp(&self, t: &Point3<T>) -> Point3<T> {
        Point3::new(lerp(t.x, self.p_min.x, self.p_max.x),
                    lerp(t.y, self.p_min.y, self.p_max.y),
                    lerp(t.z, self.p_min.z, self.p_max.z))
    }

    pub fn inside(&self, p: &Point3<T>) -> bool {
        p.x >= self.p_min.x && p.x <= self.p_max.x && p.y >= self.p_min.y &&
        p.y <= self.p_max.y && p.z >= self.p_min.z && p.z <= self.p_max.z
    }
}

impl Bounds3<f32> {
    /// Compute the bounding sphere of the current bounding box, and returns its center and radius.
    pub fn bounding_sphere(&self) -> (Point3f, f32) {
        let center = Point3f::new((self.p_min.x + self.p_max.x) / 2.0,
                                  (self.p_min.y + self.p_max.y) / 2.0,
                                  (self.p_min.z + self.p_max.z) / 2.0);
        let radius = if self.inside(&center) {
            (self.p_max - center).norm()
        } else {
            0.0
        };

        (center, radius)
    }
}

pub type Bounds2i = Bounds2<u32>;
pub type Bounds2f = Bounds2<f32>;

#[derive(Debug, Copy, Clone)]
pub struct Bounds2<T> {
    pub p_min: Point2<T>,
    pub p_max: Point2<T>,
}

impl<T> Bounds2<T>
    where T: BaseNum + Bounded + PartialOrd + fmt::Display
{
    pub fn new() -> Bounds2<T> {
        let min = T::min_value();
        let max = T::max_value();
        Bounds2 {
            p_min: Point2::new(max, max),
            p_max: Point2::new(min, min),
        }
    }

    pub fn from_point(point: &Point2<T>) -> Bounds2<T> {
        Bounds2 {
            p_min: *point,
            p_max: *point,
        }
    }

    pub fn from_points(min: &Point2<T>, max: &Point2<T>) -> Bounds2<T> {
        assert!(min.x <= max.x && min.y <= max.y,
                format!("Invalid bounds: {} - {}", min, max));
        Bounds2 {
            p_min: *min,
            p_max: *max,
        }
    }

    // pub fn corner(&self, corner: usize) -> Point2<T> {
    //     Point3::new(self[corner & 1].x,
    //                 self[if corner & 2 != 0 { 1 } else { 0 }].y,
    //                 self[if corner & 4 != 0 { 1 } else { 0 }].y)
    // }

    pub fn extend(&mut self, p: Point2<T>) {
        if p.x < self.p_min.x {
            self.p_min.x = p.x
        }
        if p.y < self.p_min.y {
            self.p_min.y = p.y
        }
        if p.x > self.p_max.x {
            self.p_max.x = p.x
        }
        if p.y > self.p_max.y {
            self.p_max.y = p.y
        }
    }

    // pub fn maximum_extent(&self) -> Axis {
    //     let v = self.p_max - self.p_min;
    //     if v.x > v.y {
    //         if v.x > v.z { Axis::X } else { Axis::Z }
    //     } else if v.y > v.z {
    //         Axis::Y
    //     } else {
    //         Axis::Z
    //     }
    // }

    pub fn union(bbox1: &Bounds2<T>, bbox2: &Bounds2<T>) -> Bounds2<T> {
        let min = Point2::new(min(bbox1.p_min.x, bbox2.p_min.x),
                              min(bbox1.p_min.y, bbox2.p_min.y));
        let max = Point2::new(max(bbox1.p_max.x, bbox2.p_max.x),
                              max(bbox1.p_max.y, bbox2.p_max.y));

        Bounds2 {
            p_min: min,
            p_max: max,
        }
    }

    pub fn union_point(bbox: &Bounds2<T>, p: &Point2<T>) -> Bounds2<T> {
        let mut b = *bbox;
        b.extend(*p);
        b
    }

    /// Linearly interpolate a point inside the bounds
    pub fn lerp(&self, t: &Point2<T>) -> Point2<T> {
        Point2::new(lerp(t.x, self.p_min.x, self.p_max.x),
                    lerp(t.y, self.p_min.y, self.p_max.y))
    }

    pub fn inside(&self, p: &Point2<T>) -> bool {
        p.x >= self.p_min.x && p.x <= self.p_max.x && p.y >= self.p_min.y && p.y <= self.p_max.y
    }

    pub fn get_area(&self) -> T {
        (self.p_max.x - self.p_min.x) * (self.p_max.y - self.p_min.y)
    }

    pub fn intersect(bbox1: &Bounds2<T>, bbox2: &Bounds2<T>) -> Bounds2<T> {
        let p_min = Point2::new(max(bbox1.p_min.x, bbox2.p_min.x),
                                max(bbox1.p_min.y, bbox2.p_min.y));
        let p_max = Point2::new(min(bbox1.p_max.x, bbox2.p_max.x),
                                min(bbox1.p_max.y, bbox2.p_max.y));

        Bounds2 {
            p_min: p_min,
            p_max: p_max,
        }
    }
}

impl<T> Index<usize> for Bounds3<T> {
    type Output = Point3<T>;

    fn index(&self, i: usize) -> &Point3<T> {
        match i {
            0 => &self.p_min,
            1 => &self.p_max,
            _ => panic!("Invalid index!"),
        }
    }
}

pub struct Bounds2Iterator<'a> {
    p: Point2i,
    bounds: &'a Bounds2i,
}

impl<'a> Iterator for Bounds2Iterator<'a> {
    type Item = Point2i;

    fn next(&mut self) -> Option<Point2i> {
        self.p.x += 1;
        if self.p.x == self.bounds.p_max.x {
            self.p.x = self.bounds.p_min.x;
            self.p.y += 1;
        }
        if self.p.y == self.bounds.p_max.y {
            None
        } else {
            Some(self.p)
        }
    }
}

impl<'a> IntoIterator for &'a Bounds2<u32> {
    type Item = Point2i;
    type IntoIter = Bounds2Iterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Bounds2Iterator {
            p: self.p_min,
            bounds: self,
        }
    }
}

impl From<Bounds2i> for Bounds2f {
    fn from(b: Bounds2i) -> Self {
        Bounds2f::from_points(&Point2f::new(b.p_min.x as f32, b.p_min.y as f32),
                              &Point2f::new(b.p_max.x as f32, b.p_max.y as f32))
    }
}

impl From<Bounds2f> for Bounds2i {
    fn from(b: Bounds2f) -> Self {
        Bounds2i::from_points(&Point2i::new(b.p_min.x as u32, b.p_min.y as u32),
                              &Point2i::new(b.p_max.x as u32, b.p_max.y as u32))
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Axis {
    X,
    Y,
    Z,
}

impl Index<Axis> for Point3<f32> {
    type Output = f32;

    fn index(&self, axis: Axis) -> &f32 {
        match axis {
            Axis::X => &self.x,
            Axis::Y => &self.y,
            Axis::Z => &self.z,
        }
    }
}

impl<T> fmt::Display for Bounds2<T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} → {}", self.p_min, self.p_max)
    }
}
<commit_msg>Fix off-by-1 error in Bounds2i iterator<commit_after>use std::f32;
use std::ops::Index;
use std::cmp::PartialOrd;
use std::fmt;

use na::{Point3, Point2, Norm, BaseNum};
use num::Bounded;

use {Vector3f, Point3f, Point2f, Point2i, lerp, min, max};
use ray::Ray;
use stats;

pub type Bounds3f = Bounds3<f32>;

/// Axis Aligned Bounding Box
#[derive(Debug, Copy, Clone)]
pub struct Bounds3<T> {
    pub p_min: Point3<T>,
    pub p_max: Point3<T>,
}

impl<T> Bounds3<T>
    where T: BaseNum + Bounded + PartialOrd + Into<f32>
{
    pub fn new() -> Bounds3<T> {
        let min = T::min_value();
        let max = T::max_value();
        Bounds3 {
            p_min: Point3::new(max, max, max),
            p_max: Point3::new(min, min, min),
        }
    }

    pub fn from_point(point: &Point3<T>) -> Bounds3<T> {
        Bounds3 {
            p_min: *point,
            p_max: *point,
        }
    }

    pub fn from_points(p1: &Point3<T>, p2: &Point3<T>) -> Bounds3<T> {
        Bounds3 {
            p_min: Point3::new(min(p1.x, p2.x), min(p1.y, p2.y), min(p1.z, p2.z)),
            p_max: Point3::new(max(p1.x, p2.x), max(p1.y, p2.y), max(p1.z, p2.z)),
        }
    }

    pub fn corner(&self, corner: usize) -> Point3<T> {
        Point3::new(self[corner & 1].x,
                    self[if corner & 2 != 0 { 1 } else { 0 }].y,
                    self[if corner & 4 != 0 { 1 } else { 0 }].y)
    }

    pub fn extend(&mut self, p: Point3<T>) {
        if p.x < self.p_min.x {
            self.p_min.x = p.x
        }
        if p.y < self.p_min.y {
            self.p_min.y = p.y
        }
        if p.z < self.p_min.z {
            self.p_min.z = p.z
        }
        if p.x > self.p_max.x {
            self.p_max.x = p.x
        }
        if p.y > self.p_max.y {
            self.p_max.y = p.y
        }
        if p.z > self.p_max.z {
            self.p_max.z = p.z
        }
    }

    pub fn maximum_extent(&self) -> Axis {
        let v = self.p_max - self.p_min;
        if v.x > v.y {
            if v.x > v.z { Axis::X } else { Axis::Z }
        } else if v.y > v.z {
            Axis::Y
        } else {
            Axis::Z
        }
    }

    pub fn union(bbox1: &Bounds3<T>, bbox2: &Bounds3<T>) -> Bounds3<T> {
        let min = Point3::new(min(bbox1.p_min.x, bbox2.p_min.x),
                              min(bbox1.p_min.y, bbox2.p_min.y),
                              min(bbox1.p_min.z, bbox2.p_min.z));
        let max = Point3::new(max(bbox1.p_max.x, bbox2.p_max.x),
                              max(bbox1.p_max.y, bbox2.p_max.y),
                              max(bbox1.p_max.z, bbox2.p_max.z));

        Bounds3 {
            p_min: min,
            p_max: max,
        }
    }

    pub fn union_point(bbox: &Bounds3<T>, p: &Point3<T>) -> Bounds3<T> {
        let mut b = *bbox;
        b.extend(*p);
        b
    }

    pub fn intersect_p(&self, ray: &Ray) -> bool {
        let invdir = Vector3f::new(1.0 / ray.d.x, 1.0 / ray.d.y, 1.0 / ray.d.z);
        let sign = [(ray.d.x < 0.0) as usize, (ray.d.y < 0.0) as usize, (ray.d.z < 0.0) as usize];

        self.intersect_p_fast(ray, &invdir, &sign)
    }

    pub fn intersect_p_fast(&self, ray: &Ray, inv_dir: &Vector3f, dir_is_neg: &[usize; 3]) -> bool {
        stats::inc_fast_bbox_isect();
        // Check intersection with X and Y slab
        let mut tmin = (self[dir_is_neg[0]].x.into() - ray.o.x) * inv_dir.x;
        let mut tmax = (self[1 - dir_is_neg[0]].x.into() - ray.o.x) * inv_dir.x;
        let tymin = (self[dir_is_neg[1]].y.into() - ray.o.y) * inv_dir.y;
        let tymax = (self[1 - dir_is_neg[1]].y.into() - ray.o.y) * inv_dir.y;
        if (tmin > tymax) || (tymin > tmax) {
            return false;
        }
        if tymin > tmin {
            tmin = tymin;
        }
        if tymax < tmax {
            tmax = tymax;
        }
        // Check intersection with Z slab
        let tzmin = (self[dir_is_neg[2]].z.into() - ray.o.z) * inv_dir.z;
        let tzmax = (self[1 - dir_is_neg[2]].z.into() - ray.o.z) * inv_dir.z;
        if (tmin > tzmax) || (tzmin > tmax) {
            return false;
        }
        if tzmin > tmin {
            tmin = tzmin;
        }
        if tzmax < tmax {
            tmax = tzmax;
        }

        tmin < ray.t_max && tmax > 0.0
    }

    /// Linearly interpolate a point inside the bounds
    pub fn lerp(&self, t: &Point3<T>) -> Point3<T> {
        Point3::new(lerp(t.x, self.p_min.x, self.p_max.x),
                    lerp(t.y, self.p_min.y, self.p_max.y),
                    lerp(t.z, self.p_min.z, self.p_max.z))
    }

    pub fn inside(&self, p: &Point3<T>) -> bool {
        p.x >= self.p_min.x && p.x <= self.p_max.x && p.y >= self.p_min.y &&
        p.y <= self.p_max.y && p.z >= self.p_min.z && p.z <= self.p_max.z
    }
}

impl Bounds3<f32> {
    /// Compute the bounding sphere of the current bounding box, and returns its center and radius.
    pub fn bounding_sphere(&self) -> (Point3f, f32) {
        let center = Point3f::new((self.p_min.x + self.p_max.x) / 2.0,
                                  (self.p_min.y + self.p_max.y) / 2.0,
                                  (self.p_min.z + self.p_max.z) / 2.0);
        let radius = if self.inside(&center) {
            (self.p_max - center).norm()
        } else {
            0.0
        };

        (center, radius)
    }
}

pub type Bounds2i = Bounds2<u32>;
pub type Bounds2f = Bounds2<f32>;

#[derive(Debug, Copy, Clone)]
pub struct Bounds2<T> {
    pub p_min: Point2<T>,
    pub p_max: Point2<T>,
}

impl<T> Bounds2<T>
    where T: BaseNum + Bounded + PartialOrd + fmt::Display
{
    pub fn new() -> Bounds2<T> {
        let min = T::min_value();
        let max = T::max_value();
        Bounds2 {
            p_min: Point2::new(max, max),
            p_max: Point2::new(min, min),
        }
    }

    pub fn from_point(point: &Point2<T>) -> Bounds2<T> {
        Bounds2 {
            p_min: *point,
            p_max: *point,
        }
    }

    pub fn from_points(min: &Point2<T>, max: &Point2<T>) -> Bounds2<T> {
        assert!(min.x <= max.x && min.y <= max.y,
                format!("Invalid bounds: {} - {}", min, max));
        Bounds2 {
            p_min: *min,
            p_max: *max,
        }
    }

    // pub fn corner(&self, corner: usize) -> Point2<T> {
    //     Point3::new(self[corner & 1].x,
    //                 self[if corner & 2 != 0 { 1 } else { 0 }].y,
    //                 self[if corner & 4 != 0 { 1 } else { 0 }].y)
    // }

    pub fn extend(&mut self, p: Point2<T>) {
        if p.x < self.p_min.x {
            self.p_min.x = p.x
        }
        if p.y < self.p_min.y {
            self.p_min.y = p.y
        }
        if p.x > self.p_max.x {
            self.p_max.x = p.x
        }
        if p.y > self.p_max.y {
            self.p_max.y = p.y
        }
    }

    // pub fn maximum_extent(&self) -> Axis {
    //     let v = self.p_max - self.p_min;
    //     if v.x > v.y {
    //         if v.x > v.z { Axis::X } else { Axis::Z }
    //     } else if v.y > v.z {
    //         Axis::Y
    //     } else {
    //         Axis::Z
    //     }
    // }

    pub fn union(bbox1: &Bounds2<T>, bbox2: &Bounds2<T>) -> Bounds2<T> {
        let min = Point2::new(min(bbox1.p_min.x, bbox2.p_min.x),
                              min(bbox1.p_min.y, bbox2.p_min.y));
        let max = Point2::new(max(bbox1.p_max.x, bbox2.p_max.x),
                              max(bbox1.p_max.y, bbox2.p_max.y));

        Bounds2 {
            p_min: min,
            p_max: max,
        }
    }

    pub fn union_point(bbox: &Bounds2<T>, p: &Point2<T>) -> Bounds2<T> {
        let mut b = *bbox;
        b.extend(*p);
        b
    }

    /// Linearly interpolate a point inside the bounds
    pub fn lerp(&self, t: &Point2<T>) -> Point2<T> {
        Point2::new(lerp(t.x, self.p_min.x, self.p_max.x),
                    lerp(t.y, self.p_min.y, self.p_max.y))
    }

    pub fn inside(&self, p: &Point2<T>) -> bool {
        p.x >= self.p_min.x && p.x <= self.p_max.x && p.y >= self.p_min.y && p.y <= self.p_max.y
    }

    pub fn get_area(&self) -> T {
        (self.p_max.x - self.p_min.x) * (self.p_max.y - self.p_min.y)
    }

    pub fn intersect(bbox1: &Bounds2<T>, bbox2: &Bounds2<T>) -> Bounds2<T> {
        let p_min = Point2::new(max(bbox1.p_min.x, bbox2.p_min.x),
                                max(bbox1.p_min.y, bbox2.p_min.y));
        let p_max = Point2::new(min(bbox1.p_max.x, bbox2.p_max.x),
                                min(bbox1.p_max.y, bbox2.p_max.y));

        Bounds2 {
            p_min: p_min,
            p_max: p_max,
        }
    }
}

impl<T> Index<usize> for Bounds3<T> {
    type Output = Point3<T>;

    fn index(&self, i: usize) -> &Point3<T> {
        match i {
            0 => &self.p_min,
            1 => &self.p_max,
            _ => panic!("Invalid index!"),
        }
    }
}

pub struct Bounds2Iterator<'a> {
    p: Point2i,
    bounds: &'a Bounds2i,
}

impl<'a> Iterator for Bounds2Iterator<'a> {
    type Item = Point2i;

    fn next(&mut self) -> Option<Point2i> {
        self.p.x += 1;
        if self.p.x == self.bounds.p_max.x {
            self.p.x = self.bounds.p_min.x;
            self.p.y += 1;
        }
        if self.p.y == self.bounds.p_max.y {
            None
        } else {
            Some(self.p)
        }
    }
}

impl<'a> IntoIterator for &'a Bounds2<u32> {
    type Item = Point2i;
    type IntoIter = Bounds2Iterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        Bounds2Iterator {
            // Need to start 1 before p_min.x as next() will be called to get the first element
            p: Point2i::new(self.p_min.x - 1, self.p_min.y),
            bounds: self,
        }
    }
}

impl From<Bounds2i> for Bounds2f {
    fn from(b: Bounds2i) -> Self {
        Bounds2f::from_points(&Point2f::new(b.p_min.x as f32, b.p_min.y as f32),
                              &Point2f::new(b.p_max.x as f32, b.p_max.y as f32))
    }
}

impl From<Bounds2f> for Bounds2i {
    fn from(b: Bounds2f) -> Self {
        Bounds2i::from_points(&Point2i::new(b.p_min.x as u32, b.p_min.y as u32),
                              &Point2i::new(b.p_max.x as u32, b.p_max.y as u32))
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Axis {
    X,
    Y,
    Z,
}

impl Index<Axis> for Point3<f32> {
    type Output = f32;

    fn index(&self, axis: Axis) -> &f32 {
        match axis {
            Axis::X => &self.x,
            Axis::Y => &self.y,
            Axis::Z => &self.z,
        }
    }
}

impl<T> fmt::Display for Bounds2<T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} → {}", self.p_min, self.p_max)
    }
}
<|endoftext|>


<commit_before>pub mod requests;
pub use requests::*;

pub use telegram_bot_raw::{Integer, Float, True, Request};
pub use telegram_bot_raw::{Update, UpdateKind};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat};
pub use telegram_bot_raw::{Message, MessageKind, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue};

pub use telegram_bot_raw::{ParseMode, ChatId, UserId, MessageId};
pub use telegram_bot_raw::{ReplyMarkup, InlineKeyboardMarkup, ReplyKeyboardMarkup};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{ChatAction};
<commit_msg>refactor: do not export `True` type in telegram-bot<commit_after>pub mod requests;
pub use requests::*;

pub use telegram_bot_raw::{Integer, Float, Request};
pub use telegram_bot_raw::{Update, UpdateKind};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat};
pub use telegram_bot_raw::{Message, MessageKind, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue};

pub use telegram_bot_raw::{ParseMode, ChatId, UserId, MessageId};
pub use telegram_bot_raw::{ReplyMarkup, InlineKeyboardMarkup, ReplyKeyboardMarkup};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{ChatAction};
<|endoftext|>


<commit_before>use hb;
use std;

use font::Font;
use common::HarfbuzzObject;

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

fn language_to_string(tag: hb::hb_language_t) -> &'static str {
    let lang_string_ptr = unsafe { hb::hb_language_to_string(tag) };
    let cstring = unsafe { std::ffi::CStr::from_ptr(lang_string_ptr) };
    cstring.to_str().expect("harfbuzz error: language string is not valid utf-8!")
}

struct BufferRaw {
    hb_buffer: *mut hb::hb_buffer_t,
}
impl BufferRaw {
    fn new() -> BufferRaw {
        let buffer = unsafe { hb::hb_buffer_create() };

        BufferRaw { hb_buffer: buffer }
    }

    fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.hb_buffer
    }

    fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.hb_buffer) as usize }
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(self.hb_buffer,
                                   utf8_ptr,
                                   string.len() as i32,
                                   0,
                                   string.len() as i32);
        }
    }

    fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.hb_buffer, direction) };
    }

    /// Returns the `Buffer`'s text direction.
    fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.hb_buffer) }
    }

    fn get_language(&self) -> &'static str {
        let lang = unsafe { hb::hb_buffer_get_language(self.hb_buffer) };
        language_to_string(lang)
    }

    fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.hb_buffer) };
    }

    fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.hb_buffer, &mut segment_props as *mut _);
            segment_props
        }
    }

    fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(font.as_raw(),
                         self.hb_buffer,
                         features.as_ptr(),
                         features.len() as u32)
        };
    }

    fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.hb_buffer) };
    }

    fn get_glyph_positions(&self) -> &mut [GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos = hb::hb_buffer_get_glyph_positions(self.hb_buffer,
                                                              &mut length as *mut u32);
            std::slice::from_raw_parts_mut(glyph_pos, length as usize)
        }
    }

    fn get_glyph_infos(&self) -> &mut [GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.hb_buffer,
                                                            &mut length as *mut u32);
            std::slice::from_raw_parts_mut(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.hb_buffer) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe {
            hb::hb_buffer_reverse_range(self.hb_buffer, start as u32, end as u32)
        }
    }
}

impl Drop for BufferRaw {
    fn drop(&mut self) {
        unsafe {
            hb::hb_buffer_destroy(self.hb_buffer);
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding
pub struct UnicodeBuffer(BufferRaw);
#[allow(dead_code)]
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(BufferRaw::new())
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Adds the string slice to the `Buffer`'s array of codepoints.
    pub fn add_str(mut self, string: &str) -> UnicodeBuffer {
        self.0.add_str(string);
        self
    }

    fn get_string(&self) -> String {
        let mut result = String::with_capacity(self.len());
        for info in self.0.get_glyph_infos() {
            let chr = std::char::from_u32(info.codepoint).unwrap();
            result.push(chr)
        }
        result
    }

    /// Sets the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    pub fn get_language(&self) -> &'static str {
        self.0.get_language()
    }

    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("content", &self.get_string())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language().to_owned())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// A `GlyphBuffer` is obtained through the `shape` function of a `UnicodeBuffer`. It contains
/// the resulting output information of the shaping process.
pub struct GlyphBuffer(BufferRaw);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn get_glyph_positions(&self) -> &mut [GlyphPosition] {
        self.0.get_glyph_positions()
    }

    pub fn get_glyph_infos(&self) -> &mut [GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}
<commit_msg>Add more hb_buffer_t functions.<commit_after>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, Tag};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

fn language_to_string(tag: hb::hb_language_t) -> &'static str {
    let lang_string_ptr = unsafe { hb::hb_language_to_string(tag) };
    let cstring = unsafe { std::ffi::CStr::from_ptr(lang_string_ptr) };
    cstring.to_str().expect("harfbuzz error: language string is not valid utf-8!")
}

struct BufferRaw {
    hb_buffer: *mut hb::hb_buffer_t,
}
impl BufferRaw {
    fn new() -> BufferRaw {
        let buffer = unsafe { hb::hb_buffer_create() };

        BufferRaw { hb_buffer: buffer }
    }

    fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.hb_buffer
    }

    fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.hb_buffer) as usize }
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(self.hb_buffer,
                                   utf8_ptr,
                                   string.len() as i32,
                                   0,
                                   string.len() as i32);
        }
    }

    fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.hb_buffer, direction) };
    }

    /// Returns the `Buffer`'s text direction.
    fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.hb_buffer) }
    }

    fn set_language(&mut self, lang: hb::hb_language_t) {
        unsafe { hb::hb_buffer_set_language(self.hb_buffer, lang) }
    }

    fn get_language(&self) -> &'static str {
        let lang = unsafe { hb::hb_buffer_get_language(self.hb_buffer) };
        language_to_string(lang)
    }

    fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.hb_buffer, script) }
    }

    fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.hb_buffer) }
    }

    fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.hb_buffer) };
    }

    fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.hb_buffer, &mut segment_props as *mut _);
            segment_props
        }
    }

    fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(font.as_raw(),
                         self.hb_buffer,
                         features.as_ptr(),
                         features.len() as u32)
        };
    }

    fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.hb_buffer) };
    }

    fn get_glyph_positions(&self) -> &mut [GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos = hb::hb_buffer_get_glyph_positions(self.hb_buffer,
                                                              &mut length as *mut u32);
            std::slice::from_raw_parts_mut(glyph_pos, length as usize)
        }
    }

    fn get_glyph_infos(&self) -> &mut [GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.hb_buffer,
                                                            &mut length as *mut u32);
            std::slice::from_raw_parts_mut(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.hb_buffer) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe {
            hb::hb_buffer_reverse_range(self.hb_buffer, start as u32, end as u32)
        }
    }
}

impl Drop for BufferRaw {
    fn drop(&mut self) {
        unsafe {
            hb::hb_buffer_destroy(self.hb_buffer);
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding
pub struct UnicodeBuffer(BufferRaw);
#[allow(dead_code)]
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(BufferRaw::new())
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Adds the string slice to the `Buffer`'s array of codepoints.
    pub fn add_str(mut self, string: &str) -> UnicodeBuffer {
        self.0.add_str(string);
        self
    }

    fn get_string(&self) -> String {
        let mut result = String::with_capacity(self.len());
        for info in self.0.get_glyph_infos() {
            let chr = std::char::from_u32(info.codepoint).unwrap();
            result.push(chr)
        }
        result
    }

    /// Sets the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0.set_script(script.0);
        self
    }

    pub fn get_script(&self) -> Tag {
        Tag(self.0.get_script())
    }

    pub fn get_language(&self) -> &'static str {
        self.0.get_language()
    }

    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("content", &self.get_string())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language().to_owned())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// A `GlyphBuffer` is obtained through the `shape` function of a `UnicodeBuffer`. It contains
/// the resulting output information of the shaping process.
pub struct GlyphBuffer(BufferRaw);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn get_glyph_positions(&self) -> &mut [GlyphPosition] {
        self.0.get_glyph_positions()
    }

    pub fn get_glyph_infos(&self) -> &mut [GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}
<|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/.

extern crate cc3200_sys;

use core;
use core::result::Result;

use self::cc3200_sys::{board_init, GPIO_IF_LedConfigure, GPIO_IF_LedOn, GPIO_IF_LedOff,
                       MAP_UtilsDelay, I2C_IF_Open, I2C_IF_Close, I2C_IF_Write, I2C_IF_Read,
                       I2C_IF_ReadFrom};
use logger::SimpleLogger;
use rtc::RTC;

#[allow(non_camel_case_types, dead_code)]
pub enum LedName {
    NO_LED_IND = 0,
    MCU_SENDING_DATA_IND,
    MCU_ASSOCIATED_IND, // Device associated to an AP
    MCU_IP_ALLOC_IND, // Device acquired an IP
    MCU_SERVER_INIT_IND, // Device connected to remote server
    MCU_CLIENT_CONNECTED_IND, // Any client connects to device
    MCU_ON_IND, // Device SLHost invoked successfully
    MCU_EXECUTE_SUCCESS_IND, // Task executed sucessfully
    MCU_EXECUTE_FAIL_IND, // Task execution failed
    MCU_RED_LED_GPIO, // GP09 for LED RED as per LP 3.0
    MCU_ORANGE_LED_GPIO, // GP10 for LED ORANGE as per LP 3.0
    MCU_GREEN_LED_GPIO, // GP11 for LED GREEN as per LP 3.0
    MCU_ALL_LED_IND,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub enum LedEnum {
    NO_LED = 0x0,
    LED1 = 0x1, // RED LED D7/GP9/Pin64
    LED2 = 0x2, // ORANGE LED D6/GP10/Pin1
    LED3 = 0x4, // GREEN LED D5/GP11/Pin2
}

pub struct Board { }

impl Board {
    pub fn init() {
        unsafe {
            board_init();
        }
        SimpleLogger::init().unwrap();
        RTC::init();
    }

    pub fn test() {
        unsafe {
            cc3200_sys::board_test();
        }
    }

    pub fn led_configure(leds: &[LedEnum]) {
        let mut val = LedEnum::NO_LED as u8;
        for led in leds {
            val |= *led as u8;
        }
        unsafe {
            GPIO_IF_LedConfigure(val);
        }
    }

    pub fn led_off(led: LedName) {
        unsafe {
            GPIO_IF_LedOff(led as i8);
        }
    }

    pub fn led_on(led: LedName) {
        unsafe {
            GPIO_IF_LedOn(led as i8);
        }
    }

    pub fn start_scheduler() {
        unsafe {
            cc3200_sys::vTaskStartScheduler();
        }
    }

    pub fn disable_irq() {
        unsafe {
            asm!("cpsid i");
        }
    }

    pub fn reset() {
        unsafe {
            cc3200_sys::reset();
        }
    }
}

pub struct Console { }

impl Console {
    pub fn clear_term() {
        unsafe {
            cc3200_sys::ClearTerm();
        }
    }

    pub fn init_term() {
        unsafe {
            cc3200_sys::InitTerm();
        }
    }

    pub fn message(msg: &str) {
        for char in msg.chars() {
            // Lossy converstion from unicode to ASCII
            let ascii_char = {
                if char > '\x7f' { '?' } else { char }
            };
            unsafe {
                cc3200_sys::console_putchar(ascii_char as i8);
            }
        }
    }
}

impl core::fmt::Write for Console {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        Console::message(s);
        Ok(())
    }
}

pub enum I2COpenMode {
    MasterModeStd = 0,
    MasterModeFst = 1,
}

static mut I2C_IS_OPEN: bool = false;
static I2C_SUCCESS: i32 = 0;

#[derive(Clone, Copy)]
pub struct I2C { }

impl I2C {
    pub fn open(mode: I2COpenMode) -> Option<Self> {
        unsafe {
            // Only allow one instance to be created in a given open mode.
            if I2C_IS_OPEN || I2C_IF_Open(mode as u32) != I2C_SUCCESS {
                return None;
            }
            I2C_IS_OPEN = true;
        }
        return Some(I2C {});
    }

    pub fn close(&self) {
        unsafe {
            // TODO: decide what to do if we never called I2C_IF_Open
            I2C_IF_Close();
            I2C_IS_OPEN = false;
        }
    }

    pub fn write(&self, addr: u8, data: &[u8], stop: u8) -> Result<(), ()> {
        if data.len() > 255 {
            return Err(());
        }
        unsafe {
            if I2C_IF_Write(addr, data.as_ptr() as *mut u8, data.len() as u8, stop) == I2C_SUCCESS {
                return Ok(());
            }
        }
        return Err(());
    }

    pub fn read(&self, addr: u8, data: &mut [u8]) -> Result<(), ()> {
        if data.len() > 255 {
            return Err(());
        }
        unsafe {
            if I2C_IF_Read(addr, data.as_ptr() as *mut u8, data.len() as u8) == I2C_SUCCESS {
                return Ok(());
            }
        }
        return Err(());
    }

    pub fn read_from_with_length(&self,
                                 addr: u8,
                                 wr_data: &[u8],
                                 rd_data: &mut [u8],
                                 rd_len: u8)
                                 -> Result<(), ()> {
        if wr_data.len() > 255 || rd_data.len() > 255 {
            return Err(());
        }
        unsafe {
            if I2C_IF_ReadFrom(addr,
                               wr_data.as_ptr() as *mut u8,
                               wr_data.len() as u8,
                               rd_data.as_ptr() as *mut u8,
                               rd_len) == I2C_SUCCESS {
                return Ok(());
            }
        }
        return Err(());
    }

    pub fn read_from(&self, addr: u8, wr_data: &[u8], rd_data: &mut [u8]) -> Result<(), ()> {
        let len = rd_data.len() as u8;
        self.read_from_with_length(addr, wr_data, rd_data, len)
    }
}

pub struct Utils { }

impl Utils {
    pub fn delay(loops: u32) {
        unsafe {
            MAP_UtilsDelay(loops);
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn abort() {
    unimplemented!();
}
<commit_msg>Provide high-level interface to boot info<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/.

extern crate cc3200_sys;

use core;
use core::result::Result;

use self::cc3200_sys::{board_init, GPIO_IF_LedConfigure, GPIO_IF_LedOn, GPIO_IF_LedOff,
                       MAP_UtilsDelay, I2C_IF_Open, I2C_IF_Close, I2C_IF_Write, I2C_IF_Read,
                       I2C_IF_ReadFrom};
use self::cc3200_sys::simplelink::*;
use logger::SimpleLogger;
use rtc::RTC;

#[allow(non_camel_case_types, dead_code)]
pub enum LedName {
    NO_LED_IND = 0,
    MCU_SENDING_DATA_IND,
    MCU_ASSOCIATED_IND, // Device associated to an AP
    MCU_IP_ALLOC_IND, // Device acquired an IP
    MCU_SERVER_INIT_IND, // Device connected to remote server
    MCU_CLIENT_CONNECTED_IND, // Any client connects to device
    MCU_ON_IND, // Device SLHost invoked successfully
    MCU_EXECUTE_SUCCESS_IND, // Task executed sucessfully
    MCU_EXECUTE_FAIL_IND, // Task execution failed
    MCU_RED_LED_GPIO, // GP09 for LED RED as per LP 3.0
    MCU_ORANGE_LED_GPIO, // GP10 for LED ORANGE as per LP 3.0
    MCU_GREEN_LED_GPIO, // GP11 for LED GREEN as per LP 3.0
    MCU_ALL_LED_IND,
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub enum LedEnum {
    NO_LED = 0x0,
    LED1 = 0x1, // RED LED D7/GP9/Pin64
    LED2 = 0x2, // ORANGE LED D6/GP10/Pin1
    LED3 = 0x4, // GREEN LED D5/GP11/Pin2
}

pub struct Board { }

impl Board {
    pub fn init() {
        unsafe {
            board_init();
        }
        SimpleLogger::init().unwrap();
        RTC::init();
    }

    pub fn test() {
        unsafe {
            cc3200_sys::board_test();
        }
    }

    pub fn led_configure(leds: &[LedEnum]) {
        let mut val = LedEnum::NO_LED as u8;
        for led in leds {
            val |= *led as u8;
        }
        unsafe {
            GPIO_IF_LedConfigure(val);
        }
    }

    pub fn led_off(led: LedName) {
        unsafe {
            GPIO_IF_LedOff(led as i8);
        }
    }

    pub fn led_on(led: LedName) {
        unsafe {
            GPIO_IF_LedOn(led as i8);
        }
    }

    pub fn start_scheduler() {
        unsafe {
            cc3200_sys::vTaskStartScheduler();
        }
    }

    pub fn disable_irq() {
        unsafe {
            asm!("cpsid i");
        }
    }

    pub fn reset() {
        unsafe {
            cc3200_sys::reset();
        }
    }
}

pub struct Console { }

impl Console {
    pub fn clear_term() {
        unsafe {
            cc3200_sys::ClearTerm();
        }
    }

    pub fn init_term() {
        unsafe {
            cc3200_sys::InitTerm();
        }
    }

    pub fn message(msg: &str) {
        for char in msg.chars() {
            // Lossy converstion from unicode to ASCII
            let ascii_char = {
                if char > '\x7f' { '?' } else { char }
            };
            unsafe {
                cc3200_sys::console_putchar(ascii_char as i8);
            }
        }
    }
}

impl core::fmt::Write for Console {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        Console::message(s);
        Ok(())
    }
}

pub enum I2COpenMode {
    MasterModeStd = 0,
    MasterModeFst = 1,
}

static mut I2C_IS_OPEN: bool = false;
static I2C_SUCCESS: i32 = 0;

#[derive(Clone, Copy)]
pub struct I2C { }

impl I2C {
    pub fn open(mode: I2COpenMode) -> Option<Self> {
        unsafe {
            // Only allow one instance to be created in a given open mode.
            if I2C_IS_OPEN || I2C_IF_Open(mode as u32) != I2C_SUCCESS {
                return None;
            }
            I2C_IS_OPEN = true;
        }
        return Some(I2C {});
    }

    pub fn close(&self) {
        unsafe {
            // TODO: decide what to do if we never called I2C_IF_Open
            I2C_IF_Close();
            I2C_IS_OPEN = false;
        }
    }

    pub fn write(&self, addr: u8, data: &[u8], stop: u8) -> Result<(), ()> {
        if data.len() > 255 {
            return Err(());
        }
        unsafe {
            if I2C_IF_Write(addr, data.as_ptr() as *mut u8, data.len() as u8, stop) == I2C_SUCCESS {
                return Ok(());
            }
        }
        return Err(());
    }

    pub fn read(&self, addr: u8, data: &mut [u8]) -> Result<(), ()> {
        if data.len() > 255 {
            return Err(());
        }
        unsafe {
            if I2C_IF_Read(addr, data.as_ptr() as *mut u8, data.len() as u8) == I2C_SUCCESS {
                return Ok(());
            }
        }
        return Err(());
    }

    pub fn read_from_with_length(&self,
                                 addr: u8,
                                 wr_data: &[u8],
                                 rd_data: &mut [u8],
                                 rd_len: u8)
                                 -> Result<(), ()> {
        if wr_data.len() > 255 || rd_data.len() > 255 {
            return Err(());
        }
        unsafe {
            if I2C_IF_ReadFrom(addr,
                               wr_data.as_ptr() as *mut u8,
                               wr_data.len() as u8,
                               rd_data.as_ptr() as *mut u8,
                               rd_len) == I2C_SUCCESS {
                return Ok(());
            }
        }
        return Err(());
    }

    pub fn read_from(&self, addr: u8, wr_data: &[u8], rd_data: &mut [u8]) -> Result<(), ()> {
        let len = rd_data.len() as u8;
        self.read_from_with_length(addr, wr_data, rd_data, len)
    }
}

pub struct Update { }

impl Update {

    /// Sets the application to test mode
    pub fn test() -> bool {
        let res = unsafe {
            sl_extlib_FlcTest(FLC_TEST_RESET_MCU |
                              FLC_TEST_RESET_MCU_WITH_APP)
        };
        Update::reset_is_required(res)
    }

    /// Returns true if the application runs in testing mode, false otherwise
    pub fn is_testing() -> bool {
        let res = unsafe {
            sl_extlib_FlcIsPendingCommit()
        };
        res != 0
    }

    /// Commits all changes, moving the application state from 'testing' to 'stable'
    pub fn commit() -> bool {
        let res = unsafe {
            sl_extlib_FlcCommit(FLC_COMMITED)
        };
        Update::reset_is_required(res)
    }

    /// Aborts the update
    pub fn abort() -> bool {
        let res = unsafe {
            sl_extlib_FlcCommit(FLC_NOT_COMMITED)
        };
        Update::reset_is_required(res)
    }

    fn reset_is_required(flags: i32) -> bool {
        (flags & (FLC_TEST_RESET_MCU | FLC_TEST_RESET_NWP)) != 0
    }
}

pub struct Utils { }

impl Utils {
    pub fn delay(loops: u32) {
        unsafe {
            MAP_UtilsDelay(loops);
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn abort() {
    unimplemented!();
}
<|endoftext|>


<commit_before>use std::net::{TcpStream, ToSocketAddrs};
use openssl::ssl::{SslContext, SslStream};
use std::io::{Error, ErrorKind, Read, Result, Write};
use regex::Regex;

static TAG_PREFIX: &'static str = "a";
const INITIAL_TAG: u32 = 1;

/// Stream to interface with the IMAP server. This interface is only for the command stream.
pub struct Client<T> {
	stream: T,
	tag: u32
}

pub struct IMAPMailbox {
	pub flags: String,
	pub exists: u32,
	pub recent: u32,
	pub unseen: Option<u32>,
	pub permanent_flags: Option<String>,
	pub uid_next: Option<u32>,
	pub uid_validity: Option<u32>
}

impl Client<TcpStream> {
	/// Creates a new client.
	pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Client<TcpStream>> {
		match TcpStream::connect(addr) {
			Ok(stream) => {
				let mut socket = Client { stream: stream, tag: INITIAL_TAG};

				try!(socket.read_greeting());
				Ok(socket)
			},
			Err(e) => Err(e)
		}
	}
}

impl Client<SslStream<TcpStream>> {
	/// Creates a client with an SSL wrapper.
	pub fn secure_connect<A: ToSocketAddrs>(addr: A, ssl_context: SslContext) -> Result<Client<SslStream<TcpStream>>> {
		match TcpStream::connect(addr) {
			Ok(stream) => {
				let mut socket = Client { stream: SslStream::connect(&ssl_context, stream).unwrap(), tag: INITIAL_TAG};

				try!(socket.read_greeting());
				Ok(socket)
			},
			Err(e) => Err(e)
		}
	}
}

impl<T: Read+Write> Client<T> {

	/// Log in to the IMAP server.
	pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
		self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
	}

	/// Selects a mailbox
	pub fn select(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("SELECT {}", mailbox_name).to_string()) {
			Ok(lines) => self.parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_select_or_examine(&mut self, lines: Vec<String>) -> Result<IMAPMailbox> {
		let exists_regex = Regex::new(r"^\* (\d+) EXISTS\r\n").unwrap();

		let recent_regex = Regex::new(r"^\* (\d+) RECENT\r\n").unwrap();

		let flags_regex = Regex::new(r"^\* FLAGS (.+)\r\n").unwrap();

		let unseen_regex = Regex::new(r"^OK \[UNSEEN (\d+)\](.*)\r\n").unwrap();

		let uid_validity_regex = Regex::new(r"^OK \[UIDVALIDITY (\d+)\](.*)\r\n").unwrap();

		let uid_next_regex = Regex::new(r"^OK \[UIDNEXT (\d+)\](.*)\r\n").unwrap();

		let permanent_flags_regex = Regex::new(r"^OK \[PERMANENTFLAGS (.+)\]\r\n").unwrap();

		//Check Ok
		match self.parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		let mut mailbox = IMAPMailbox{
			flags: "".to_string(),
			exists: 0,
			recent: 0,
			unseen: None,
			permanent_flags: None,
			uid_next: None,
			uid_validity: None
		};

		for line in lines.iter() {
			if exists_regex.is_match(line) {
				let cap = exists_regex.captures(line).unwrap();
				mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if recent_regex.is_match(line) {
				let cap = recent_regex.captures(line).unwrap();
				mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if flags_regex.is_match(line) {
				let cap = flags_regex.captures(line).unwrap();
				mailbox.flags = cap.at(1).unwrap().to_string();
			} else if unseen_regex.is_match(line) {
				let cap = unseen_regex.captures(line).unwrap();
				mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_validity_regex.is_match(line) {
				let cap = uid_validity_regex.captures(line).unwrap();
				mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_next_regex.is_match(line) {
				let cap = uid_next_regex.captures(line).unwrap();
				mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if permanent_flags_regex.is_match(line) {
				let cap = permanent_flags_regex.captures(line).unwrap();
				mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
			}
		}

		return Ok(mailbox);
	}

	/// Examine is identical to Select, but the selected mailbox is identified as read-only
	pub fn examine(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("EXAMINE {}", mailbox_name).to_string()) {
			Ok(lines) => self.parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	/// Fetch retreives data associated with a message in the mailbox.
	pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
		self.run_command(&format!("FETCH {} {}", sequence_set, query).to_string())
	}

	/// Noop always succeeds, and it does nothing.
	pub fn noop(&mut self) -> Result<()> {
		self.run_command_and_check_ok("NOOP")
	}

	/// Logout informs the server that the client is done with the connection.
	pub fn logout(&mut self) -> Result<()> {
		self.run_command_and_check_ok("LOGOUT")
	}

	/// Create creates a mailbox with the given name.
	pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("CREATE {}", mailbox_name).to_string())
	}

	/// Delete permanently removes the mailbox with the given name.
	pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("DELETE {}", mailbox_name).to_string())
	}

	/// Rename changes the name of a mailbox.
	pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
	}

	/// Subscribe adds the specified mailbox name to the server's set of "active" or "subscribed"
	/// mailboxes as returned by the LSUB command.
	pub fn subscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
	}

	/// Unsubscribe removes the specified mailbox name from the server's set of "active" or "subscribed"
	/// mailboxes as returned by the LSUB command.
	pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
	}

	/// Capability requests a listing of capabilities that the server supports.
	pub fn capability(&mut self) -> Result<Vec<String>> {
		match self.run_command(&format!("CAPABILITY").to_string()) {
			Ok(lines) => self.parse_capability(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_capability(&mut self, lines: Vec<String>) -> Result<Vec<String>> {
		let capability_regex = match Regex::new(r"^\* CAPABILITY (.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match self.parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		for line in lines.iter() {
			if capability_regex.is_match(line) {
				let cap = capability_regex.captures(line).unwrap();
				let capabilities_str = cap.at(1).unwrap();
				return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
			}
		}

		Err(Error::new(ErrorKind::Other, "Error parsing capabilities response"))
	}

	/// Expunge permanently removes all messages that have the \Deleted flag set from the currently
	/// selected mailbox.
	pub fn expunge(&mut self) -> Result<()> {
		self.run_command_and_check_ok("CHECK")
	}

	/// Check requests a checkpoint of the currently selected mailbox.
	pub fn check(&mut self) -> Result<()> {
		self.run_command_and_check_ok("CHECK")
	}

	/// Close permanently removes all messages that have the \Deleted flag set from the currently
	/// selected mailbox, and returns to the authenticated state from the selected state.
	pub fn close(&mut self) -> Result<()> {
		self.run_command_and_check_ok("CLOSE")
	}

	/// Copy copies the specified message to the end of the specified destination mailbox.
	pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
	}

	pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
		match self.run_command(command) {
			Ok(lines) => self.parse_response_ok(lines),
			Err(e) => Err(e)
		}
	}

	pub fn run_command(&mut self, untagged_command: &str) -> Result<Vec<String>> {
		let command = self.create_command(untagged_command.to_string());

		match self.stream.write_fmt(format_args!("{}", &*command)) {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to write")),
		};

		let ret = match self.read_response() {
			Ok(lines) => Ok(lines),
			Err(_) => Err(Error::new(ErrorKind::Other, "Failed to read")),
		};

		self.tag += 1;

		return ret;
	}

	fn parse_response_ok(&mut self, lines: Vec<String>) -> Result<()> {
		let ok_regex = match Regex::new(r"^([a-zA-Z0-9]+) ([a-zA-Z0-9]+)(.*)") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};
		let last_line = lines.last().unwrap();

		for cap in ok_regex.captures_iter(last_line) {
			let response_type = cap.at(2).unwrap_or("");
			if response_type == "OK" {
				return Ok(());
			}
		}

		return Err(Error::new(ErrorKind::Other, format!("Invalid Response: {}", last_line).to_string()));
	}

	fn read_response(&mut self) -> Result<Vec<String>> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut found_tag_line = false;
		let start_str = format!("{}{} ", TAG_PREFIX, self.tag);
		let mut lines: Vec<String> = Vec::new();

		while !found_tag_line {
			let mut line_buffer: Vec<u8> = Vec::new();
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
					let byte_buffer: &mut [u8] = &mut [0];
					match self.stream.read(byte_buffer) {
						Ok(_) => {},
						Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
					}
					line_buffer.push(byte_buffer[0]);
			}

			let line = String::from_utf8(line_buffer).unwrap();

			lines.push(line.clone());

			if (&*line).starts_with(&*start_str) {
				found_tag_line = true;
			}
		}

		Ok(lines)
	}

	fn read_greeting(&mut self) -> Result<()> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;

		let mut line_buffer: Vec<u8> = Vec::new();
		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.stream.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		Ok(())
	}

	fn create_command(&mut self, command: String) -> String {
		let command = format!("{}{} {}\r\n", TAG_PREFIX, self.tag, command);
		return command;
	}
}

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

	fn create_client_with_mock_stream(mock_stream: MockStream) -> Client<MockStream> {
		Client {
			stream: mock_stream,
			tag: 1
		}
	}

	#[test]
	fn close() {
		let response = b"a1 OK CLOSE completed\r\n".to_vec();
		let mock_stream = MockStream::new(response);
		let mut imap_stream = create_client_with_mock_stream(mock_stream);
		match imap_stream.close() {
			Err(err) => panic!("Error reading response: {}", err),
			_ => {},
		}
		assert!(imap_stream.stream.written_buf == b"a1 CLOSE\r\n".to_vec(), "Invalid close command");
	}
}
<commit_msg>Adding INITIAL_TAG to test code<commit_after>use std::net::{TcpStream, ToSocketAddrs};
use openssl::ssl::{SslContext, SslStream};
use std::io::{Error, ErrorKind, Read, Result, Write};
use regex::Regex;

static TAG_PREFIX: &'static str = "a";
const INITIAL_TAG: u32 = 1;

/// Stream to interface with the IMAP server. This interface is only for the command stream.
pub struct Client<T> {
	stream: T,
	tag: u32
}

pub struct IMAPMailbox {
	pub flags: String,
	pub exists: u32,
	pub recent: u32,
	pub unseen: Option<u32>,
	pub permanent_flags: Option<String>,
	pub uid_next: Option<u32>,
	pub uid_validity: Option<u32>
}

impl Client<TcpStream> {
	/// Creates a new client.
	pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Client<TcpStream>> {
		match TcpStream::connect(addr) {
			Ok(stream) => {
				let mut socket = Client { stream: stream, tag: INITIAL_TAG};

				try!(socket.read_greeting());
				Ok(socket)
			},
			Err(e) => Err(e)
		}
	}
}

impl Client<SslStream<TcpStream>> {
	/// Creates a client with an SSL wrapper.
	pub fn secure_connect<A: ToSocketAddrs>(addr: A, ssl_context: SslContext) -> Result<Client<SslStream<TcpStream>>> {
		match TcpStream::connect(addr) {
			Ok(stream) => {
				let mut socket = Client { stream: SslStream::connect(&ssl_context, stream).unwrap(), tag: INITIAL_TAG};

				try!(socket.read_greeting());
				Ok(socket)
			},
			Err(e) => Err(e)
		}
	}
}

impl<T: Read+Write> Client<T> {

	/// Log in to the IMAP server.
	pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
		self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
	}

	/// Selects a mailbox
	pub fn select(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("SELECT {}", mailbox_name).to_string()) {
			Ok(lines) => self.parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_select_or_examine(&mut self, lines: Vec<String>) -> Result<IMAPMailbox> {
		let exists_regex = Regex::new(r"^\* (\d+) EXISTS\r\n").unwrap();

		let recent_regex = Regex::new(r"^\* (\d+) RECENT\r\n").unwrap();

		let flags_regex = Regex::new(r"^\* FLAGS (.+)\r\n").unwrap();

		let unseen_regex = Regex::new(r"^OK \[UNSEEN (\d+)\](.*)\r\n").unwrap();

		let uid_validity_regex = Regex::new(r"^OK \[UIDVALIDITY (\d+)\](.*)\r\n").unwrap();

		let uid_next_regex = Regex::new(r"^OK \[UIDNEXT (\d+)\](.*)\r\n").unwrap();

		let permanent_flags_regex = Regex::new(r"^OK \[PERMANENTFLAGS (.+)\]\r\n").unwrap();

		//Check Ok
		match self.parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		let mut mailbox = IMAPMailbox{
			flags: "".to_string(),
			exists: 0,
			recent: 0,
			unseen: None,
			permanent_flags: None,
			uid_next: None,
			uid_validity: None
		};

		for line in lines.iter() {
			if exists_regex.is_match(line) {
				let cap = exists_regex.captures(line).unwrap();
				mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if recent_regex.is_match(line) {
				let cap = recent_regex.captures(line).unwrap();
				mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if flags_regex.is_match(line) {
				let cap = flags_regex.captures(line).unwrap();
				mailbox.flags = cap.at(1).unwrap().to_string();
			} else if unseen_regex.is_match(line) {
				let cap = unseen_regex.captures(line).unwrap();
				mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_validity_regex.is_match(line) {
				let cap = uid_validity_regex.captures(line).unwrap();
				mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_next_regex.is_match(line) {
				let cap = uid_next_regex.captures(line).unwrap();
				mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if permanent_flags_regex.is_match(line) {
				let cap = permanent_flags_regex.captures(line).unwrap();
				mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
			}
		}

		return Ok(mailbox);
	}

	/// Examine is identical to Select, but the selected mailbox is identified as read-only
	pub fn examine(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("EXAMINE {}", mailbox_name).to_string()) {
			Ok(lines) => self.parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	/// Fetch retreives data associated with a message in the mailbox.
	pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
		self.run_command(&format!("FETCH {} {}", sequence_set, query).to_string())
	}

	/// Noop always succeeds, and it does nothing.
	pub fn noop(&mut self) -> Result<()> {
		self.run_command_and_check_ok("NOOP")
	}

	/// Logout informs the server that the client is done with the connection.
	pub fn logout(&mut self) -> Result<()> {
		self.run_command_and_check_ok("LOGOUT")
	}

	/// Create creates a mailbox with the given name.
	pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("CREATE {}", mailbox_name).to_string())
	}

	/// Delete permanently removes the mailbox with the given name.
	pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("DELETE {}", mailbox_name).to_string())
	}

	/// Rename changes the name of a mailbox.
	pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
	}

	/// Subscribe adds the specified mailbox name to the server's set of "active" or "subscribed"
	/// mailboxes as returned by the LSUB command.
	pub fn subscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
	}

	/// Unsubscribe removes the specified mailbox name from the server's set of "active" or "subscribed"
	/// mailboxes as returned by the LSUB command.
	pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
	}

	/// Capability requests a listing of capabilities that the server supports.
	pub fn capability(&mut self) -> Result<Vec<String>> {
		match self.run_command(&format!("CAPABILITY").to_string()) {
			Ok(lines) => self.parse_capability(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_capability(&mut self, lines: Vec<String>) -> Result<Vec<String>> {
		let capability_regex = match Regex::new(r"^\* CAPABILITY (.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match self.parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		for line in lines.iter() {
			if capability_regex.is_match(line) {
				let cap = capability_regex.captures(line).unwrap();
				let capabilities_str = cap.at(1).unwrap();
				return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
			}
		}

		Err(Error::new(ErrorKind::Other, "Error parsing capabilities response"))
	}

	/// Expunge permanently removes all messages that have the \Deleted flag set from the currently
	/// selected mailbox.
	pub fn expunge(&mut self) -> Result<()> {
		self.run_command_and_check_ok("CHECK")
	}

	/// Check requests a checkpoint of the currently selected mailbox.
	pub fn check(&mut self) -> Result<()> {
		self.run_command_and_check_ok("CHECK")
	}

	/// Close permanently removes all messages that have the \Deleted flag set from the currently
	/// selected mailbox, and returns to the authenticated state from the selected state.
	pub fn close(&mut self) -> Result<()> {
		self.run_command_and_check_ok("CLOSE")
	}

	/// Copy copies the specified message to the end of the specified destination mailbox.
	pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
	}

	pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
		match self.run_command(command) {
			Ok(lines) => self.parse_response_ok(lines),
			Err(e) => Err(e)
		}
	}

	pub fn run_command(&mut self, untagged_command: &str) -> Result<Vec<String>> {
		let command = self.create_command(untagged_command.to_string());

		match self.stream.write_fmt(format_args!("{}", &*command)) {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to write")),
		};

		let ret = match self.read_response() {
			Ok(lines) => Ok(lines),
			Err(_) => Err(Error::new(ErrorKind::Other, "Failed to read")),
		};

		self.tag += 1;

		return ret;
	}

	fn parse_response_ok(&mut self, lines: Vec<String>) -> Result<()> {
		let ok_regex = match Regex::new(r"^([a-zA-Z0-9]+) ([a-zA-Z0-9]+)(.*)") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};
		let last_line = lines.last().unwrap();

		for cap in ok_regex.captures_iter(last_line) {
			let response_type = cap.at(2).unwrap_or("");
			if response_type == "OK" {
				return Ok(());
			}
		}

		return Err(Error::new(ErrorKind::Other, format!("Invalid Response: {}", last_line).to_string()));
	}

	fn read_response(&mut self) -> Result<Vec<String>> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut found_tag_line = false;
		let start_str = format!("{}{} ", TAG_PREFIX, self.tag);
		let mut lines: Vec<String> = Vec::new();

		while !found_tag_line {
			let mut line_buffer: Vec<u8> = Vec::new();
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
					let byte_buffer: &mut [u8] = &mut [0];
					match self.stream.read(byte_buffer) {
						Ok(_) => {},
						Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
					}
					line_buffer.push(byte_buffer[0]);
			}

			let line = String::from_utf8(line_buffer).unwrap();

			lines.push(line.clone());

			if (&*line).starts_with(&*start_str) {
				found_tag_line = true;
			}
		}

		Ok(lines)
	}

	fn read_greeting(&mut self) -> Result<()> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;

		let mut line_buffer: Vec<u8> = Vec::new();
		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.stream.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		Ok(())
	}

	fn create_command(&mut self, command: String) -> String {
		let command = format!("{}{} {}\r\n", TAG_PREFIX, self.tag, command);
		return command;
	}
}

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

	fn create_client_with_mock_stream(mock_stream: MockStream) -> Client<MockStream> {
		Client {
			stream: mock_stream,
			tag: INITIAL_TAG
		}
	}

	#[test]
	fn close() {
		let response = b"a1 OK CLOSE completed\r\n".to_vec();
		let mock_stream = MockStream::new(response);
		let mut imap_stream = create_client_with_mock_stream(mock_stream);
		match imap_stream.close() {
			Err(err) => panic!("Error reading response: {}", err),
			_ => {},
		}
		assert!(imap_stream.stream.written_buf == b"a1 CLOSE\r\n".to_vec(), "Invalid close command");
	}
}
<|endoftext|>