<commit_before>// Non-conventional component-wise operators.

use num::{Signed, Zero};
use std::ops::{Add, Mul};

use simba::scalar::{ClosedDiv, ClosedMul};

use crate::base::allocator::{Allocator, SameShapeAllocator};
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::Dim;
use crate::base::storage::{Storage, StorageMut};
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar};

/// The type of the result of a matrix component-wise operation.
pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>;

impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
    /// Computes the component-wise absolute value.
    ///
    /// # Example
    ///
    /// ```
    /// # use nalgebra::Matrix2;
    /// let a = Matrix2::new(0.0, 1.0,
    ///                      -2.0, -3.0);
    /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0))
    /// ```
    #[inline]
    pub fn abs(&self) -> MatrixMN<N, R, C>
    where
        N: Signed,
        DefaultAllocator: Allocator<N, R, C>,
    {
        let mut res = self.clone_owned();

        for e in res.iter_mut() {
            *e = e.abs();
        }

        res
    }

    // FIXME: add other operators like component_ln, component_pow, etc. ?
}

macro_rules! component_binop_impl(
    ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$(
        impl<N: Scalar, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA> {
            #[doc = $desc]
            #[inline]
            pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R1, C1, R2, C2>
                where N: $Trait,
                      R2: Dim, C2: Dim,
                      SB: Storage<N, R2, C2>,
                      DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
                      ShapeConstraint:  SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                let mut res = self.clone_owned_sum();

                for j in 0 .. res.ncols() {
                    for i in 0 .. res.nrows() {
                        unsafe {
                            res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone());
                        }
                    }
                }

                res
            }
        }

        impl<N: Scalar, R1: Dim, C1: Dim, SA: StorageMut<N, R1, C1>> Matrix<N, R1, C1, SA> {
            // componentwise binop plus Y.
            #[doc = $desc_cmpy]
            #[inline]
            pub fn $cmpy<R2, C2, SB, R3, C3, SC>(&mut self, alpha: N, a: &Matrix<N, R2, C2, SB>, b: &Matrix<N, R3, C3, SC>, beta: N)
                where N: $Trait + Zero + Mul<N, Output = N> + Add<N, Output = N>,
                      R2: Dim, C2: Dim,
                      R3: Dim, C3: Dim,
                      SB: Storage<N, R2, C2>,
                      SC: Storage<N, R3, C3>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
                                       SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
                assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                if beta.is_zero() {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone());
                                *self.get_unchecked_mut((i, j)) = res;
                            }
                        }
                    }
                }
                else {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone());
                                *self.get_unchecked_mut((i, j)) = beta.inlined_clone() * self.get_unchecked((i, j)).inlined_clone() + res;
                            }
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                for j in 0 .. self.ncols() {
                    for i in 0 .. self.nrows() {
                        unsafe {
                            self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone());
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")]
            pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
                self.$binop_assign(rhs)
            }
        }
    )*}
);

component_binop_impl!(
    component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign,
    r"
    Componentwise matrix or vector multiplication.

    # Example

    ```
    # use nalgebra::Matrix2;
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);

    assert_eq!(a.component_mul(&b), expected);
    ```
    ",
    r"
    Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = (a.component_mul(&b) * 5.0) + m * 10.0;

    m.cmpy(5.0, &a, &b, 10.0);
    assert_eq!(m, expected);
    ```
    ",
    r"
    Inplace componentwise matrix or vector multiplication.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);

    a.component_mul_assign(&b);

    assert_eq!(a, expected);
    ```
    ";
    component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign,
    r"
    Componentwise matrix or vector division.

    # Example

    ```
    # use nalgebra::Matrix2;
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);

    assert_eq!(a.component_div(&b), expected);
    ```
    ",
    r"
    Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let a = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = (a.component_div(&b) * 5.0) + m * 10.0;

    m.cdpy(5.0, &a, &b, 10.0);
    assert_eq!(m, expected);
    ```
    ",
    r"
    Inplace componentwise matrix or vector division.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);

    a.component_div_assign(&b);

    assert_eq!(a, expected);
    ```
    ";
    // FIXME: add other operators like bitshift, etc. ?
);
<commit_msg>Re-add inf/sup.<commit_after>// Non-conventional component-wise operators.

use num::{Signed, Zero};
use std::ops::{Add, Mul};

use simba::scalar::{ClosedDiv, ClosedMul};
use simba::simd::SimdPartialOrd;

use crate::base::allocator::{Allocator, SameShapeAllocator};
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::Dim;
use crate::base::storage::{Storage, StorageMut};
use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar};

/// The type of the result of a matrix component-wise operation.
pub type MatrixComponentOp<N, R1, C1, R2, C2> = MatrixSum<N, R1, C1, R2, C2>;

impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
    /// Computes the component-wise absolute value.
    ///
    /// # Example
    ///
    /// ```
    /// # use nalgebra::Matrix2;
    /// let a = Matrix2::new(0.0, 1.0,
    ///                      -2.0, -3.0);
    /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0))
    /// ```
    #[inline]
    pub fn abs(&self) -> MatrixMN<N, R, C>
    where
        N: Signed,
        DefaultAllocator: Allocator<N, R, C>,
    {
        let mut res = self.clone_owned();

        for e in res.iter_mut() {
            *e = e.abs();
        }

        res
    }

    // FIXME: add other operators like component_ln, component_pow, etc. ?
}

macro_rules! component_binop_impl(
    ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$(
        impl<N: Scalar, R1: Dim, C1: Dim, SA: Storage<N, R1, C1>> Matrix<N, R1, C1, SA> {
            #[doc = $desc]
            #[inline]
            pub fn $binop<R2, C2, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> MatrixComponentOp<N, R1, C1, R2, C2>
                where N: $Trait,
                      R2: Dim, C2: Dim,
                      SB: Storage<N, R2, C2>,
                      DefaultAllocator: SameShapeAllocator<N, R1, C1, R2, C2>,
                      ShapeConstraint:  SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                let mut res = self.clone_owned_sum();

                for j in 0 .. res.ncols() {
                    for i in 0 .. res.nrows() {
                        unsafe {
                            res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone());
                        }
                    }
                }

                res
            }
        }

        impl<N: Scalar, R1: Dim, C1: Dim, SA: StorageMut<N, R1, C1>> Matrix<N, R1, C1, SA> {
            // componentwise binop plus Y.
            #[doc = $desc_cmpy]
            #[inline]
            pub fn $cmpy<R2, C2, SB, R3, C3, SC>(&mut self, alpha: N, a: &Matrix<N, R2, C2, SB>, b: &Matrix<N, R3, C3, SC>, beta: N)
                where N: $Trait + Zero + Mul<N, Output = N> + Add<N, Output = N>,
                      R2: Dim, C2: Dim,
                      R3: Dim, C3: Dim,
                      SB: Storage<N, R2, C2>,
                      SC: Storage<N, R3, C3>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
                                       SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
                assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions.");
                assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                if beta.is_zero() {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone());
                                *self.get_unchecked_mut((i, j)) = res;
                            }
                        }
                    }
                }
                else {
                    for j in 0 .. self.ncols() {
                        for i in 0 .. self.nrows() {
                            unsafe {
                                let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone());
                                *self.get_unchecked_mut((i, j)) = beta.inlined_clone() * self.get_unchecked((i, j)).inlined_clone() + res;
                            }
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            pub fn $binop_assign<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {

                assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions.");

                for j in 0 .. self.ncols() {
                    for i in 0 .. self.nrows() {
                        unsafe {
                            self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone());
                        }
                    }
                }
            }

            #[doc = $desc_mut]
            #[inline]
            #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")]
            pub fn $binop_mut<R2, C2, SB>(&mut self, rhs: &Matrix<N, R2, C2, SB>)
                where N: $Trait,
                      R2: Dim,
                      C2: Dim,
                      SB: Storage<N, R2, C2>,
                      ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
                self.$binop_assign(rhs)
            }
        }
    )*}
);

component_binop_impl!(
    component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMul.mul.mul_assign,
    r"
    Componentwise matrix or vector multiplication.

    # Example

    ```
    # use nalgebra::Matrix2;
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);

    assert_eq!(a.component_mul(&b), expected);
    ```
    ",
    r"
    Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = (a.component_mul(&b) * 5.0) + m * 10.0;

    m.cmpy(5.0, &a, &b, 10.0);
    assert_eq!(m, expected);
    ```
    ",
    r"
    Inplace componentwise matrix or vector multiplication.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0);

    a.component_mul_assign(&b);

    assert_eq!(a, expected);
    ```
    ";
    component_div, component_div_mut, component_div_assign, cdpy, ClosedDiv.div.div_assign,
    r"
    Componentwise matrix or vector division.

    # Example

    ```
    # use nalgebra::Matrix2;
    let a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);

    assert_eq!(a.component_div(&b), expected);
    ```
    ",
    r"
    Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let a = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = (a.component_div(&b) * 5.0) + m * 10.0;

    m.cdpy(5.0, &a, &b, 10.0);
    assert_eq!(m, expected);
    ```
    ",
    r"
    Inplace componentwise matrix or vector division.

    # Example
    ```
    # use nalgebra::Matrix2;
    let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0);
    let b = Matrix2::new(4.0, 5.0, 6.0, 7.0);
    let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0);

    a.component_div_assign(&b);

    assert_eq!(a, expected);
    ```
    ";
    // FIXME: add other operators like bitshift, etc. ?
);

/*
 * inf/sup
 */
impl<N, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
where
    N: Scalar + SimdPartialOrd,
    DefaultAllocator: Allocator<N, R, C>,
{
    /// Computes the infimum (aka. componentwise min) of two matrices/vectors.
    #[inline]
    pub fn inf(&self, other: &Self) -> MatrixMN<N, R, C> {
        self.zip_map(other, |a, b| a.simd_min(b))
    }

    /// Computes the supremum (aka. componentwise max) of two matrices/vectors.
    #[inline]
    pub fn sup(&self, other: &Self) -> MatrixMN<N, R, C> {
        self.zip_map(other, |a, b| a.simd_max(b))
    }

    /// Computes the (infimum, supremum) of two matrices/vectors.
    #[inline]
    pub fn inf_sup(&self, other: &Self) -> (MatrixMN<N, R, C>, MatrixMN<N, R, C>) {
        // FIXME: can this be optimized?
        (self.inf(other), self.sup(other))
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, All Contributors (see CONTRIBUTORS file)
//
// 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 pumpkindb;

extern crate config;
extern crate nom;
extern crate rustyline;
extern crate ansi_term;
extern crate uuid;
#[macro_use]
extern crate clap;

use pumpkindb::script;
use pumpkindb::script::compose::*;
use pumpkindb::script::compose::Item::*;

extern crate byteorder;

use std::io::prelude::*;
use std::net::TcpStream;

use byteorder::{ByteOrder, BigEndian};

use rustyline::error::ReadlineError;
use rustyline::Editor;
use rustyline::history::History;

use std::fmt::Write;
use std::io::Write as IoWrite;

use ansi_term::Colour::Red;

use std::str;

use uuid::Uuid;

use clap::{Arg, App};

fn main() {

    let args = App::new("PumpkinDB Terminal")
        .version(crate_version!())
        .about("Command-line access to PumpkinDB")
        .setting(clap::AppSettings::ColoredHelp)
        .arg(Arg::with_name("address")
            .help("Address to connect to")
            .required(true)
            .default_value("0.0.0.0:9981")
            .index(1))
        .get_matches();

    let _ = config::merge(config::Environment::new("pumpkindb"));
    let _ = config::set_default("prompt", "PumpkinDB> ");
    let formatted_prompt = format!("{}", config::get_str("prompt").unwrap());
    let mut current_prompt = formatted_prompt.as_str();

    let address = args.value_of("address").unwrap();
    let mut stream = match TcpStream::connect(address) {
        Ok(s) => s,
        Err(err) => {
            println!("Can't connect to {}, error: {}", address, err);
            return;
        }
    };

    let mut rl = Editor::<()>::new();
    let mut r = Vec::new();

    let mut multine = History::new();
    println!("Connected to PumpkinDB at {}", address);
    println!("To send an expression, end it with `.`");
    println!("Type \\h for help.");
    loop {
        match rl.readline(current_prompt) {
            Ok(text) => {
                let mut program = String::new();
                let text_str = text.as_str();
                let text_bytes = text_str.as_bytes();
                if text_bytes.len() >= 2 && text_bytes[0] == 92u8 {
                    if text_bytes[1] == 104u8 {
                        println!("\nTo send an expression, end it with `.`");
                        println!("To quit, hit ^D");
                        println!("Further help online at http://pumpkindb.org/doc/");
                        println!("Missing a feature? Let us know at https://github.com/PumpkinDB/PumpkinDB/issues/\n");
                    }
                } else if text_str.len() > 0 && text_bytes[text_str.len() - 1] == 46u8 {
                    let rest = str::from_utf8(&text.as_bytes()[..text_str.len() - 1]).unwrap();
                    multine.add(&rest);
                    for i in 0..multine.len() {
                        program.push_str(multine.get(i).unwrap().as_str());
                    }
                    multine.clear();
                    current_prompt = formatted_prompt.as_str();
                } else {
                    multine.add(&text);
                    multine.add(&" ");
                    current_prompt = "..> ";
                }
                if program.len() > 0 {
                    rl.add_history_entry(&program);
                    match script::parse(&program) {
                        Ok(compiled) => {
                            let uuid = Uuid::new_v4();
                            let msg : Vec<u8> = Program(vec![
                                Data(&compiled), Word("TRY"),
                                Data(uuid.as_bytes()), WordRef("topic"), Word("SET"),
                                Word("topic"),
                                Word("SUBSCRIBE"), Word("STACK"), Word("topic"), Word("SEND"),
                                Word("topic"), Word("UNSUBSCRIBE")
                            ]).into();
                            let mut buf = [0u8; 4];

                            BigEndian::write_u32(&mut buf, msg.len() as u32);
                            stream.write_all(buf.as_ref()).unwrap();
                            stream.write_all(msg.as_ref()).unwrap();

                            stream.read(&mut buf).unwrap();

                            let msg_len = BigEndian::read_u32(&mut buf);

                            let s_ref = <TcpStream as Read>::by_ref(&mut stream);

                            r.clear();

                            match s_ref.take(msg_len as u64).read_to_end(&mut r) {
                                Ok(0) => {
                                },
                                Ok(_) => {
                                    let mut input = r.clone();
                                    let mut top_level = true;
                                    let mut s = String::new();
                                    while input.len()> 0 {
                                        match script::binparser::data(input.clone().as_slice()) {
                                            nom::IResult::Done(rest, data) => {
                                                let (_, size) = script::binparser::data_size(data).unwrap();
                                                let data = &data[script::offset_by_size(size)..];

                                                input = Vec::from(rest);

                                                if rest.len() == 0 && top_level {
                                                    top_level = false;
                                                    if data.len() > 0 {
                                                        let _ = write!(&mut s, "{}", Red.paint("Error: "));
                                                        input = Vec::from(data);
                                                    }
                                                } else {
                                                    if data.iter().all(|c| *c >= 0x20 && *c <= 0x7e) {
                                                        let _ = write!(&mut s, "{:?} ", str::from_utf8(data).unwrap());
                                                    } else {
                                                        let _ = write!(&mut s, "0x");
                                                        for b in Vec::from(data) {
                                                            let _ = write!(&mut s, "{:02x}", b);
                                                        }
                                                        let _ = write!(&mut s, " ");
                                                    }
                                                }
                                            },
                                            e => {
                                                panic!("{:?}", e);
                                            }
                                        }
                                    }
                                    println!("{}", s);
                                },
                                Err(e) => {
                                    panic!("{}", e);
                                }
                            }
                        },
                        Err(err) => {
                            println!("Script error: {:?}", err);
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                println!("Aborted");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("Exiting");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }

    }
}<commit_msg>Problem: reusing term history requires re-typing period<commit_after>// Copyright (c) 2017, All Contributors (see CONTRIBUTORS file)
//
// 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 pumpkindb;

extern crate config;
extern crate nom;
extern crate rustyline;
extern crate ansi_term;
extern crate uuid;
#[macro_use]
extern crate clap;

use pumpkindb::script;
use pumpkindb::script::compose::*;
use pumpkindb::script::compose::Item::*;

extern crate byteorder;

use std::io::prelude::*;
use std::net::TcpStream;

use byteorder::{ByteOrder, BigEndian};

use rustyline::error::ReadlineError;
use rustyline::Editor;
use rustyline::history::History;

use std::fmt::Write;
use std::io::Write as IoWrite;

use ansi_term::Colour::Red;

use std::str;

use uuid::Uuid;

use clap::{Arg, App};

fn main() {

    let args = App::new("PumpkinDB Terminal")
        .version(crate_version!())
        .about("Command-line access to PumpkinDB")
        .setting(clap::AppSettings::ColoredHelp)
        .arg(Arg::with_name("address")
            .help("Address to connect to")
            .required(true)
            .default_value("0.0.0.0:9981")
            .index(1))
        .get_matches();

    let _ = config::merge(config::Environment::new("pumpkindb"));
    let _ = config::set_default("prompt", "PumpkinDB> ");
    let formatted_prompt = format!("{}", config::get_str("prompt").unwrap());
    let mut current_prompt = formatted_prompt.as_str();

    let address = args.value_of("address").unwrap();
    let mut stream = match TcpStream::connect(address) {
        Ok(s) => s,
        Err(err) => {
            println!("Can't connect to {}, error: {}", address, err);
            return;
        }
    };

    let mut rl = Editor::<()>::new();
    let mut r = Vec::new();

    let mut multine = History::new();
    println!("Connected to PumpkinDB at {}", address);
    println!("To send an expression, end it with `.`");
    println!("Type \\h for help.");
    loop {
        match rl.readline(current_prompt) {
            Ok(text) => {
                let mut program = String::new();
                let text_str = text.as_str();
                let text_bytes = text_str.as_bytes();
                if text_bytes.len() >= 2 && text_bytes[0] == 92u8 {
                    if text_bytes[1] == 104u8 {
                        println!("\nTo send an expression, end it with `.`");
                        println!("To quit, hit ^D");
                        println!("Further help online at http://pumpkindb.org/doc/");
                        println!("Missing a feature? Let us know at https://github.com/PumpkinDB/PumpkinDB/issues/\n");
                    }
                } else if text_str.len() > 0 && text_bytes[text_str.len() - 1] == 46u8 {
                    let rest = str::from_utf8(&text.as_bytes()[..text_str.len() - 1]).unwrap();
                    multine.add(&rest);
                    for i in 0..multine.len() {
                        program.push_str(multine.get(i).unwrap().as_str());
                    }
                    multine.clear();
                    current_prompt = formatted_prompt.as_str();
                } else {
                    multine.add(&text);
                    multine.add(&" ");
                    current_prompt = "..> ";
                }
                if program.len() > 0 {
                    rl.add_history_entry(format!("{}.", &program).as_str());
                    match script::parse(&program) {
                        Ok(compiled) => {
                            let uuid = Uuid::new_v4();
                            let msg : Vec<u8> = Program(vec![
                                Data(&compiled), Word("TRY"),
                                Data(uuid.as_bytes()), WordRef("topic"), Word("SET"),
                                Word("topic"),
                                Word("SUBSCRIBE"), Word("STACK"), Word("topic"), Word("SEND"),
                                Word("topic"), Word("UNSUBSCRIBE")
                            ]).into();
                            let mut buf = [0u8; 4];

                            BigEndian::write_u32(&mut buf, msg.len() as u32);
                            stream.write_all(buf.as_ref()).unwrap();
                            stream.write_all(msg.as_ref()).unwrap();

                            stream.read(&mut buf).unwrap();

                            let msg_len = BigEndian::read_u32(&mut buf);

                            let s_ref = <TcpStream as Read>::by_ref(&mut stream);

                            r.clear();

                            match s_ref.take(msg_len as u64).read_to_end(&mut r) {
                                Ok(0) => {
                                },
                                Ok(_) => {
                                    let mut input = r.clone();
                                    let mut top_level = true;
                                    let mut s = String::new();
                                    while input.len()> 0 {
                                        match script::binparser::data(input.clone().as_slice()) {
                                            nom::IResult::Done(rest, data) => {
                                                let (_, size) = script::binparser::data_size(data).unwrap();
                                                let data = &data[script::offset_by_size(size)..];

                                                input = Vec::from(rest);

                                                if rest.len() == 0 && top_level {
                                                    top_level = false;
                                                    if data.len() > 0 {
                                                        let _ = write!(&mut s, "{}", Red.paint("Error: "));
                                                        input = Vec::from(data);
                                                    }
                                                } else {
                                                    if data.iter().all(|c| *c >= 0x20 && *c <= 0x7e) {
                                                        let _ = write!(&mut s, "{:?} ", str::from_utf8(data).unwrap());
                                                    } else {
                                                        let _ = write!(&mut s, "0x");
                                                        for b in Vec::from(data) {
                                                            let _ = write!(&mut s, "{:02x}", b);
                                                        }
                                                        let _ = write!(&mut s, " ");
                                                    }
                                                }
                                            },
                                            e => {
                                                panic!("{:?}", e);
                                            }
                                        }
                                    }
                                    println!("{}", s);
                                },
                                Err(e) => {
                                    panic!("{}", e);
                                }
                            }
                        },
                        Err(err) => {
                            println!("Script error: {:?}", err);
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                println!("Aborted");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("Exiting");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }

    }
}<|endoftext|>


<commit_before>use crate::output::display_width;
use crate::output::textwrap;

/// Terminal-styling container
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct StyledStr {
    pieces: Vec<(Option<Style>, String)>,
}

impl StyledStr {
    /// Create an empty buffer
    pub const fn new() -> Self {
        Self { pieces: Vec::new() }
    }

    pub(crate) fn header(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Header), msg.into());
    }

    pub(crate) fn literal(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Literal), msg.into());
    }

    pub(crate) fn placeholder(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Placeholder), msg.into());
    }

    pub(crate) fn good(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Good), msg.into());
    }

    #[cfg_attr(not(feature = "error-context"), allow(dead_code))]
    pub(crate) fn warning(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Warning), msg.into());
    }

    pub(crate) fn error(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Error), msg.into());
    }

    #[allow(dead_code)]
    pub(crate) fn hint(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Hint), msg.into());
    }

    pub(crate) fn none(&mut self, msg: impl Into<String>) {
        self.stylize_(None, msg.into());
    }

    pub(crate) fn stylize(&mut self, style: impl Into<Option<Style>>, msg: impl Into<String>) {
        self.stylize_(style.into(), msg.into());
    }

    pub(crate) fn trim(&mut self) {
        self.trim_start();
        self.trim_end();
    }

    pub(crate) fn trim_start(&mut self) {
        if let Some((_, item)) = self.pieces.first_mut() {
            *item = item.trim_start().to_owned();
        }
    }

    pub(crate) fn trim_end(&mut self) {
        if let Some((_, item)) = self.pieces.last_mut() {
            *item = item.trim_end().to_owned();
        }
    }

    pub(crate) fn replace_newline(&mut self) {
        for (_, content) in &mut self.pieces {
            *content = content.replace("{n}", "\n");
        }
    }

    pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
        if let Some((_, first)) = self.pieces.first_mut() {
            first.insert_str(0, initial);
        }
        let mut line_sep = "\n".to_owned();
        line_sep.push_str(trailing);
        for (_, content) in &mut self.pieces {
            *content = content.replace('\n', &line_sep);
        }
    }

    pub(crate) fn wrap(&mut self, hard_width: usize) {
        let mut wrapper = textwrap::wrap_algorithms::LineWrapper::new(hard_width);
        for (_, content) in &mut self.pieces {
            let mut total = Vec::new();
            for (i, line) in content.split_inclusive('\n').enumerate() {
                if 0 < i {
                    // start of a section does not imply newline
                    wrapper.reset();
                }
                let line =
                    textwrap::word_separators::find_words_ascii_space(line).collect::<Vec<_>>();
                total.extend(wrapper.wrap(line));
            }
            let total = total.join("");
            *content = total;
        }
        if let Some((_, last)) = self.pieces.last_mut() {
            *last = last.trim_end().to_owned();
        }
    }

    fn stylize_(&mut self, style: Option<Style>, msg: String) {
        if !msg.is_empty() {
            self.pieces.push((style, msg));
        }
    }

    #[inline(never)]
    pub(crate) fn display_width(&self) -> usize {
        let mut width = 0;
        for (_, c) in &self.pieces {
            width += display_width(c);
        }
        width
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.pieces.is_empty()
    }

    pub(crate) fn iter(&self) -> impl Iterator<Item = (Option<Style>, &str)> {
        self.pieces.iter().map(|(s, c)| (*s, c.as_str()))
    }

    pub(crate) fn into_iter(self) -> impl Iterator<Item = (Option<Style>, String)> {
        self.pieces.into_iter()
    }

    pub(crate) fn extend(
        &mut self,
        other: impl IntoIterator<Item = (impl Into<Option<Style>>, impl Into<String>)>,
    ) {
        for (style, content) in other {
            self.stylize(style.into(), content.into());
        }
    }

    #[cfg(feature = "color")]
    pub(crate) fn write_colored(&self, buffer: &mut termcolor::Buffer) -> std::io::Result<()> {
        use std::io::Write;
        use termcolor::WriteColor;

        for (style, content) in &self.pieces {
            let mut color = termcolor::ColorSpec::new();
            match style {
                Some(Style::Header) => {
                    color.set_bold(true);
                    color.set_underline(true);
                }
                Some(Style::Literal) => {
                    color.set_bold(true);
                }
                Some(Style::Placeholder) => {}
                Some(Style::Good) => {
                    color.set_fg(Some(termcolor::Color::Green));
                }
                Some(Style::Warning) => {
                    color.set_fg(Some(termcolor::Color::Yellow));
                }
                Some(Style::Error) => {
                    color.set_fg(Some(termcolor::Color::Red));
                    color.set_bold(true);
                }
                Some(Style::Hint) => {
                    color.set_dimmed(true);
                }
                None => {}
            }

            buffer.set_color(&color)?;
            buffer.write_all(content.as_bytes())?;
            buffer.reset()?;
        }

        Ok(())
    }
}

impl Default for &'_ StyledStr {
    fn default() -> Self {
        static DEFAULT: StyledStr = StyledStr::new();
        &DEFAULT
    }
}

impl From<std::string::String> for StyledStr {
    fn from(name: std::string::String) -> Self {
        let mut styled = StyledStr::new();
        styled.none(name);
        styled
    }
}

impl From<&'_ std::string::String> for StyledStr {
    fn from(name: &'_ std::string::String) -> Self {
        let mut styled = StyledStr::new();
        styled.none(name);
        styled
    }
}

impl From<&'static str> for StyledStr {
    fn from(name: &'static str) -> Self {
        let mut styled = StyledStr::new();
        styled.none(name);
        styled
    }
}

impl From<&'_ &'static str> for StyledStr {
    fn from(name: &'_ &'static str) -> Self {
        StyledStr::from(*name)
    }
}

impl PartialOrd for StyledStr {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for StyledStr {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.iter().map(cmp_key).cmp(other.iter().map(cmp_key))
    }
}

fn cmp_key(c: (Option<Style>, &str)) -> (Option<usize>, &str) {
    let style = c.0.map(|s| s.as_usize());
    let content = c.1;
    (style, content)
}

/// Color-unaware printing. Never uses coloring.
impl std::fmt::Display for StyledStr {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        for (_, content) in &self.pieces {
            std::fmt::Display::fmt(content, f)?;
        }

        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Style {
    Header,
    Literal,
    Placeholder,
    Good,
    Warning,
    Error,
    Hint,
}

impl Style {
    fn as_usize(&self) -> usize {
        match self {
            Self::Header => 0,
            Self::Literal => 1,
            Self::Placeholder => 2,
            Self::Good => 3,
            Self::Warning => 4,
            Self::Error => 5,
            Self::Hint => 6,
        }
    }
}
<commit_msg>perf(help): Reduce colorless code size<commit_after>use crate::output::display_width;
use crate::output::textwrap;

/// Terminal-styling container
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct StyledStr {
    #[cfg(feature = "color")]
    pieces: Vec<(Option<Style>, String)>,
    #[cfg(not(feature = "color"))]
    pieces: String,
}

impl StyledStr {
    /// Create an empty buffer
    #[cfg(feature = "color")]
    pub const fn new() -> Self {
        Self { pieces: Vec::new() }
    }

    /// Create an empty buffer
    #[cfg(not(feature = "color"))]
    pub const fn new() -> Self {
        Self {
            pieces: String::new(),
        }
    }

    pub(crate) fn header(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Header), msg.into());
    }

    pub(crate) fn literal(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Literal), msg.into());
    }

    pub(crate) fn placeholder(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Placeholder), msg.into());
    }

    pub(crate) fn good(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Good), msg.into());
    }

    #[cfg_attr(not(feature = "error-context"), allow(dead_code))]
    pub(crate) fn warning(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Warning), msg.into());
    }

    pub(crate) fn error(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Error), msg.into());
    }

    #[allow(dead_code)]
    pub(crate) fn hint(&mut self, msg: impl Into<String>) {
        self.stylize_(Some(Style::Hint), msg.into());
    }

    pub(crate) fn none(&mut self, msg: impl Into<String>) {
        self.stylize_(None, msg.into());
    }

    pub(crate) fn stylize(&mut self, style: impl Into<Option<Style>>, msg: impl Into<String>) {
        self.stylize_(style.into(), msg.into());
    }

    pub(crate) fn trim(&mut self) {
        self.trim_start();
        self.trim_end();
    }

    pub(crate) fn trim_start(&mut self) {
        if let Some((_, item)) = self.iter_mut().next() {
            *item = item.trim_start().to_owned();
        }
    }

    #[cfg(feature = "color")]
    pub(crate) fn trim_end(&mut self) {
        if let Some((_, item)) = self.pieces.last_mut() {
            *item = item.trim_end().to_owned();
        }
    }

    #[cfg(not(feature = "color"))]
    pub(crate) fn trim_end(&mut self) {
        self.pieces = self.pieces.trim_end().to_owned();
    }

    pub(crate) fn replace_newline(&mut self) {
        for (_, content) in self.iter_mut() {
            *content = content.replace("{n}", "\n");
        }
    }

    pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
        if let Some((_, first)) = self.iter_mut().next() {
            first.insert_str(0, initial);
        }
        let mut line_sep = "\n".to_owned();
        line_sep.push_str(trailing);
        for (_, content) in self.iter_mut() {
            *content = content.replace('\n', &line_sep);
        }
    }

    pub(crate) fn wrap(&mut self, hard_width: usize) {
        let mut wrapper = textwrap::wrap_algorithms::LineWrapper::new(hard_width);
        for (_, content) in self.iter_mut() {
            let mut total = Vec::new();
            for (i, line) in content.split_inclusive('\n').enumerate() {
                if 0 < i {
                    // start of a section does not imply newline
                    wrapper.reset();
                }
                let line =
                    textwrap::word_separators::find_words_ascii_space(line).collect::<Vec<_>>();
                total.extend(wrapper.wrap(line));
            }
            let total = total.join("");
            *content = total;
        }

        self.trim_end();
    }

    #[cfg(feature = "color")]
    fn stylize_(&mut self, style: Option<Style>, msg: String) {
        if !msg.is_empty() {
            self.pieces.push((style, msg));
        }
    }

    #[cfg(not(feature = "color"))]
    fn stylize_(&mut self, _style: Option<Style>, msg: String) {
        self.pieces.push_str(&msg);
    }

    #[inline(never)]
    pub(crate) fn display_width(&self) -> usize {
        let mut width = 0;
        for (_, c) in self.iter() {
            width += display_width(c);
        }
        width
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.pieces.is_empty()
    }

    #[cfg(feature = "color")]
    pub(crate) fn iter(&self) -> impl Iterator<Item = (Option<Style>, &str)> {
        self.pieces.iter().map(|(s, c)| (*s, c.as_str()))
    }

    #[cfg(not(feature = "color"))]
    pub(crate) fn iter(&self) -> impl Iterator<Item = (Option<Style>, &str)> {
        [(None, self.pieces.as_str())].into_iter()
    }

    #[cfg(feature = "color")]
    pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = (Option<Style>, &mut String)> {
        self.pieces.iter_mut().map(|(s, c)| (*s, c))
    }

    #[cfg(not(feature = "color"))]
    pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = (Option<Style>, &mut String)> {
        [(None, &mut self.pieces)].into_iter()
    }

    #[cfg(feature = "color")]
    pub(crate) fn into_iter(self) -> impl Iterator<Item = (Option<Style>, String)> {
        self.pieces.into_iter()
    }

    #[cfg(not(feature = "color"))]
    pub(crate) fn into_iter(self) -> impl Iterator<Item = (Option<Style>, String)> {
        [(None, self.pieces)].into_iter()
    }

    pub(crate) fn extend(
        &mut self,
        other: impl IntoIterator<Item = (impl Into<Option<Style>>, impl Into<String>)>,
    ) {
        for (style, content) in other {
            self.stylize(style.into(), content.into());
        }
    }

    #[cfg(feature = "color")]
    pub(crate) fn write_colored(&self, buffer: &mut termcolor::Buffer) -> std::io::Result<()> {
        use std::io::Write;
        use termcolor::WriteColor;

        for (style, content) in &self.pieces {
            let mut color = termcolor::ColorSpec::new();
            match style {
                Some(Style::Header) => {
                    color.set_bold(true);
                    color.set_underline(true);
                }
                Some(Style::Literal) => {
                    color.set_bold(true);
                }
                Some(Style::Placeholder) => {}
                Some(Style::Good) => {
                    color.set_fg(Some(termcolor::Color::Green));
                }
                Some(Style::Warning) => {
                    color.set_fg(Some(termcolor::Color::Yellow));
                }
                Some(Style::Error) => {
                    color.set_fg(Some(termcolor::Color::Red));
                    color.set_bold(true);
                }
                Some(Style::Hint) => {
                    color.set_dimmed(true);
                }
                None => {}
            }

            buffer.set_color(&color)?;
            buffer.write_all(content.as_bytes())?;
            buffer.reset()?;
        }

        Ok(())
    }
}

impl Default for &'_ StyledStr {
    fn default() -> Self {
        static DEFAULT: StyledStr = StyledStr::new();
        &DEFAULT
    }
}

impl From<std::string::String> for StyledStr {
    fn from(name: std::string::String) -> Self {
        let mut styled = StyledStr::new();
        styled.none(name);
        styled
    }
}

impl From<&'_ std::string::String> for StyledStr {
    fn from(name: &'_ std::string::String) -> Self {
        let mut styled = StyledStr::new();
        styled.none(name);
        styled
    }
}

impl From<&'static str> for StyledStr {
    fn from(name: &'static str) -> Self {
        let mut styled = StyledStr::new();
        styled.none(name);
        styled
    }
}

impl From<&'_ &'static str> for StyledStr {
    fn from(name: &'_ &'static str) -> Self {
        StyledStr::from(*name)
    }
}

impl PartialOrd for StyledStr {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for StyledStr {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.iter().map(cmp_key).cmp(other.iter().map(cmp_key))
    }
}

fn cmp_key(c: (Option<Style>, &str)) -> (Option<usize>, &str) {
    let style = c.0.map(|s| s.as_usize());
    let content = c.1;
    (style, content)
}

/// Color-unaware printing. Never uses coloring.
impl std::fmt::Display for StyledStr {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        for (_, content) in self.iter() {
            std::fmt::Display::fmt(content, f)?;
        }

        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Style {
    Header,
    Literal,
    Placeholder,
    Good,
    Warning,
    Error,
    Hint,
}

impl Style {
    fn as_usize(&self) -> usize {
        match self {
            Self::Header => 0,
            Self::Literal => 1,
            Self::Placeholder => 2,
            Self::Good => 3,
            Self::Warning => 4,
            Self::Error => 5,
            Self::Hint => 6,
        }
    }
}
<|endoftext|>


<commit_before>use resources::*;
use resources::common::*;
use caches::common::*;

use rustc_serialize::base64::{self, ToBase64};

use std::io::Read;

use ::hyper::Client;
use ::hyper::net::HttpsConnector;
use ::hyper_native_tls::NativeTlsClient;
use ::hyper::header::{Headers, UserAgent};

pub struct ImageResource<'a, T: 'a + Cache> {
    cache: &'a mut Box<T>,
    client: Client
}

impl<'a, T: 'a + Cache> ImageResource<'a, T> {
    pub fn new(cache: &'a mut Box<T>) -> Self {
        let ssl = NativeTlsClient::new().unwrap();
        let connector = HttpsConnector::new(ssl);
        ImageResource {
            cache: cache,
            client: Client::with_connector(connector)
        }
    }
}

impl<'a, T: 'a + Cache> Resource for ImageResource<'a, T> {
    fn fetch(&mut self, item: &ChannelItem) -> ChannelItem {
        match item.extra.clone() {
            Some(o) => {
                match o {
                    ChannelItemType::Image(extra) => {
                        let url = extra.url;
                        let url2 = url.clone();
                        let img_path = "data/cache/img/";
                        let img_file_name = url.into_bytes().as_slice().to_base64(base64::URL_SAFE);

                        info!("image resource - before find in cache. url: {}", url2.clone());
                        let (from_cache, result, reason) = match self.cache.read(&img_path, &img_file_name) {
                            Ok(result) => {
                                info!("image resource - find in cache success. url:  {}", url2.clone());
                                (true, result, "".to_string())
                            }
                            Err(_) => {
                                info!("image resource - find in cache fail. url:  {}", url2.clone());

                                let mut headers = Headers::new();
                                headers.set(UserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36".to_owned()));

                                match self.client.get(&url2).headers(headers).send() {
                                    Ok(mut resp) => {
                                            info!("image resource - http request success url:  {}", url2.clone());
                                            let mut buffer = Vec::new();
                                            resp.read_to_end(&mut buffer).expect("fail to read buffer from the http response");
                                            self.cache.write(&img_path, &img_file_name, buffer.clone()).expect("fail to write cache");
                                            (false, buffer, "".to_string())
                                        }
                                    Err(e) => {
                                        info!("image resource - http request fail url:  {}", url2.clone());
                                        (false, Vec::new(), e.to_string())
                                    }
                                }
                            }
                        };

                        let url3 = url2.clone();
                        info!("image url: {} reason: {}", url3, reason);
                        let result_item = ChannelItem {
                            extra: Some(ChannelItemType::Image(ChannelImageItem { url: url2, bytes: result })),
                            result: reason,
                        };
                        result_item
                    },
                    _ => {
                        ChannelItem {
                            extra: Some(ChannelItemType::Image(Default::default())),
                            result: Default::default(),
                        }
                    }
                }
            }
            None => {
                ChannelItem {
                    extra: Some(ChannelItemType::Image(Default::default())),
                    result: Default::default(),
                }
            }
        }
    }
}
<commit_msg>[FIX] prevent client blocking in image resource<commit_after>use resources::*;
use resources::common::*;
use caches::common::*;

use rustc_serialize::base64::{self, ToBase64};

use std::io::Read;

use ::hyper::Client;
use ::hyper::net::HttpsConnector;
use ::hyper_native_tls::NativeTlsClient;
use ::hyper::header::{Headers, UserAgent};

pub struct ImageResource<'a, T: 'a + Cache> {
    cache: &'a mut Box<T>,
    client: Client
}

impl<'a, T: 'a + Cache> ImageResource<'a, T> {
    pub fn new(cache: &'a mut Box<T>) -> Self {
        let ssl = NativeTlsClient::new().unwrap();
        let connector = HttpsConnector::new(ssl);
        ImageResource {
            cache: cache,
            client: Client::with_connector(connector)
        }
    }
}

impl<'a, T: 'a + Cache> Resource for ImageResource<'a, T> {
    fn fetch(&mut self, item: &ChannelItem) -> ChannelItem {
        match item.extra.clone() {
            Some(o) => {
                match o {
                    ChannelItemType::Image(extra) => {
                        let url = extra.url;
                        let url2 = url.clone();
                        let img_path = "data/cache/img/";
                        let img_file_name = url.into_bytes().as_slice().to_base64(base64::URL_SAFE);

                        info!("image resource - before find in cache. url: {}", url2.clone());
                        let (from_cache, result, reason) = match self.cache.read(&img_path, &img_file_name) {
                            Ok(result) => {
                                info!("image resource - find in cache success. url:  {}", url2.clone());
                                (true, result, "".to_string())
                            }
                            Err(_) => {
                                info!("image resource - find in cache fail. url:  {}", url2.clone());

                                let mut headers = Headers::new();
                                headers.set(UserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36".to_owned()));

                                let ssl = NativeTlsClient::new().unwrap();
                                let connector = HttpsConnector::new(ssl);

                                let client = Client::with_connector(connector);
                                match client.get(&url2).headers(headers).send() {
                                    Ok(mut resp) => {
                                            info!("image resource - http request success url:  {}", url2.clone());
                                            let mut buffer = Vec::new();
                                            resp.read_to_end(&mut buffer).expect("fail to read buffer from the http response");
                                            self.cache.write(&img_path, &img_file_name, buffer.clone()).expect("fail to write cache");
                                            (false, buffer, "".to_string())
                                        }
                                    Err(e) => {
                                        info!("image resource - http request fail url:  {}", url2.clone());
                                        (false, Vec::new(), e.to_string())
                                    }
                                }
                            }
                        };

                        let url3 = url2.clone();
                        info!("image url: {} reason: {}", url3, reason);
                        let result_item = ChannelItem {
                            extra: Some(ChannelItemType::Image(ChannelImageItem { url: url2, bytes: result })),
                            result: reason,
                        };
                        result_item
                    },
                    _ => {
                        ChannelItem {
                            extra: Some(ChannelItemType::Image(Default::default())),
                            result: Default::default(),
                        }
                    }
                }
            }
            None => {
                ChannelItem {
                    extra: Some(ChannelItemType::Image(Default::default())),
                    result: Default::default(),
                }
            }
        }
    }
}
<|endoftext|>


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

use collections::hashmap::HashMap;
use geom::size::Size2D;
use layers::platform::surface::NativePaintingGraphicsContext;
use servo_msg::compositor_msg::Tile;
use std::hash::Hash;
use std::hash::sip::SipState;
use std::mem;

/// This is a struct used to store buffers when they are not in use.
/// The render task can quickly query for a particular size of buffer when it
/// needs it.
pub struct BufferMap<T> {
    /// A HashMap that stores the Buffers.
    map: HashMap<BufferKey, BufferValue<T>>,
    /// The current amount of memory stored by the BufferMap's buffers.
    mem: uint,
    /// The maximum allowed memory. Unused buffers will be deleted
    /// when this threshold is exceeded.
    max_mem: uint,
    /// A monotonically increasing counter to track how recently tile sizes were used.
    counter: uint,
}

/// A key with which to store buffers. It is based on the size of the buffer.
struct BufferKey([uint, ..2]);

impl Hash for BufferKey {
    fn hash(&self, state: &mut SipState) {
        let BufferKey(ref bytes) = *self;
        bytes.as_slice().hash(state);
    }
}

impl Eq for BufferKey {
    fn eq(&self, other: &BufferKey) -> bool {
        let BufferKey(s) = *self;
        let BufferKey(o) = *other;
        s[0] == o[0] && s[1] == o[1]
    }
}

impl TotalEq for BufferKey {
    fn equals(&self, other: &BufferKey) -> bool {
        self.eq(other)
    }
}

/// Create a key from a given size
impl BufferKey {
    fn get(input: Size2D<uint>) -> BufferKey {
        BufferKey([input.width, input.height])
    }
}

/// A helper struct to keep track of buffers in the HashMap
struct BufferValue<T> {
    /// An array of buffers, all the same size
    buffers: ~[T],
    /// The counter when this size was last requested
    last_action: uint,
}

impl<T: Tile> BufferMap<T> {
    // Creates a new BufferMap with a given buffer limit.
    pub fn new(max_mem: uint) -> BufferMap<T> {
        BufferMap {
            map: HashMap::new(),
            mem: 0u,
            max_mem: max_mem,
            counter: 0u,
        }
    }

    /// Insert a new buffer into the map.
    pub fn insert(&mut self, graphics_context: &NativePaintingGraphicsContext, new_buffer: T) {
        let new_key = BufferKey::get(new_buffer.get_size_2d());

        // If all our buffers are the same size and we're already at our
        // memory limit, no need to store this new buffer; just let it drop.
        if self.mem + new_buffer.get_mem() > self.max_mem && self.map.len() == 1 &&
            self.map.contains_key(&new_key) {
            return;
        }

        self.mem += new_buffer.get_mem();
        // use lazy insertion function to prevent unnecessary allocation
        let counter = &self.counter;
        self.map.find_or_insert_with(new_key, |_| BufferValue {
            buffers: ~[],
            last_action: *counter
        }).buffers.push(new_buffer);

        let mut opt_key: Option<BufferKey> = None;
        while self.mem > self.max_mem {
            let old_key = match opt_key {
                Some(key) => key,
                None => {
                    match self.map.iter().min_by(|&(_, x)| x.last_action) {
                        Some((k, _)) => *k,
                        None => fail!("BufferMap: tried to delete with no elements in map"),
                    }
                }
            };
            if {
                let list = &mut self.map.get_mut(&old_key).buffers;
                let condemned_buffer = list.pop().take_unwrap();
                self.mem -= condemned_buffer.get_mem();
                condemned_buffer.destroy(graphics_context);
                list.is_empty()
            }
            { // then
                self.map.pop(&old_key); // Don't store empty vectors!
                opt_key = None;
            } else {
                opt_key = Some(old_key);
            }
        }
    }

    // Try to find a buffer for the given size.
    pub fn find(&mut self, size: Size2D<uint>) -> Option<T> {
        let mut flag = false; // True if key needs to be popped after retrieval.
        let key = BufferKey::get(size);
        let ret = match self.map.find_mut(&key) {
            Some(ref mut buffer_val) => {
                buffer_val.last_action = self.counter;
                self.counter += 1;

                let buffer = buffer_val.buffers.pop().take_unwrap();
                self.mem -= buffer.get_mem();
                if buffer_val.buffers.is_empty() {
                    flag = true;
                }
                Some(buffer)
            }
            None => None,
        };

        if flag {
            self.map.pop(&key); // Don't store empty vectors!
        }

        ret
    }

    /// Destroys all buffers.
    pub fn clear(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        let map = mem::replace(&mut self.map, HashMap::new());
        for (_, value) in map.move_iter() {
            for tile in value.buffers.move_iter() {
                tile.destroy(graphics_context)
            }
        }
        self.mem = 0
    }
}
<commit_msg>Destroy LayerBuffers before dropping them<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use collections::hashmap::HashMap;
use geom::size::Size2D;
use layers::platform::surface::NativePaintingGraphicsContext;
use servo_msg::compositor_msg::Tile;
use std::hash::Hash;
use std::hash::sip::SipState;
use std::mem;

/// This is a struct used to store buffers when they are not in use.
/// The render task can quickly query for a particular size of buffer when it
/// needs it.
pub struct BufferMap<T> {
    /// A HashMap that stores the Buffers.
    map: HashMap<BufferKey, BufferValue<T>>,
    /// The current amount of memory stored by the BufferMap's buffers.
    mem: uint,
    /// The maximum allowed memory. Unused buffers will be deleted
    /// when this threshold is exceeded.
    max_mem: uint,
    /// A monotonically increasing counter to track how recently tile sizes were used.
    counter: uint,
}

/// A key with which to store buffers. It is based on the size of the buffer.
struct BufferKey([uint, ..2]);

impl Hash for BufferKey {
    fn hash(&self, state: &mut SipState) {
        let BufferKey(ref bytes) = *self;
        bytes.as_slice().hash(state);
    }
}

impl Eq for BufferKey {
    fn eq(&self, other: &BufferKey) -> bool {
        let BufferKey(s) = *self;
        let BufferKey(o) = *other;
        s[0] == o[0] && s[1] == o[1]
    }
}

impl TotalEq for BufferKey {
    fn equals(&self, other: &BufferKey) -> bool {
        self.eq(other)
    }
}

/// Create a key from a given size
impl BufferKey {
    fn get(input: Size2D<uint>) -> BufferKey {
        BufferKey([input.width, input.height])
    }
}

/// A helper struct to keep track of buffers in the HashMap
struct BufferValue<T> {
    /// An array of buffers, all the same size
    buffers: ~[T],
    /// The counter when this size was last requested
    last_action: uint,
}

impl<T: Tile> BufferMap<T> {
    // Creates a new BufferMap with a given buffer limit.
    pub fn new(max_mem: uint) -> BufferMap<T> {
        BufferMap {
            map: HashMap::new(),
            mem: 0u,
            max_mem: max_mem,
            counter: 0u,
        }
    }

    /// Insert a new buffer into the map.
    pub fn insert(&mut self, graphics_context: &NativePaintingGraphicsContext, new_buffer: T) {
        let new_key = BufferKey::get(new_buffer.get_size_2d());

        // If all our buffers are the same size and we're already at our
        // memory limit, no need to store this new buffer; just let it drop.
        if self.mem + new_buffer.get_mem() > self.max_mem && self.map.len() == 1 &&
            self.map.contains_key(&new_key) {
            new_buffer.destroy(graphics_context);
            return;
        }

        self.mem += new_buffer.get_mem();
        // use lazy insertion function to prevent unnecessary allocation
        let counter = &self.counter;
        self.map.find_or_insert_with(new_key, |_| BufferValue {
            buffers: ~[],
            last_action: *counter
        }).buffers.push(new_buffer);

        let mut opt_key: Option<BufferKey> = None;
        while self.mem > self.max_mem {
            let old_key = match opt_key {
                Some(key) => key,
                None => {
                    match self.map.iter().min_by(|&(_, x)| x.last_action) {
                        Some((k, _)) => *k,
                        None => fail!("BufferMap: tried to delete with no elements in map"),
                    }
                }
            };
            if {
                let list = &mut self.map.get_mut(&old_key).buffers;
                let condemned_buffer = list.pop().take_unwrap();
                self.mem -= condemned_buffer.get_mem();
                condemned_buffer.destroy(graphics_context);
                list.is_empty()
            }
            { // then
                self.map.pop(&old_key); // Don't store empty vectors!
                opt_key = None;
            } else {
                opt_key = Some(old_key);
            }
        }
    }

    // Try to find a buffer for the given size.
    pub fn find(&mut self, size: Size2D<uint>) -> Option<T> {
        let mut flag = false; // True if key needs to be popped after retrieval.
        let key = BufferKey::get(size);
        let ret = match self.map.find_mut(&key) {
            Some(ref mut buffer_val) => {
                buffer_val.last_action = self.counter;
                self.counter += 1;

                let buffer = buffer_val.buffers.pop().take_unwrap();
                self.mem -= buffer.get_mem();
                if buffer_val.buffers.is_empty() {
                    flag = true;
                }
                Some(buffer)
            }
            None => None,
        };

        if flag {
            self.map.pop(&key); // Don't store empty vectors!
        }

        ret
    }

    /// Destroys all buffers.
    pub fn clear(&mut self, graphics_context: &NativePaintingGraphicsContext) {
        let map = mem::replace(&mut self.map, HashMap::new());
        for (_, value) in map.move_iter() {
            for tile in value.buffers.move_iter() {
                tile.destroy(graphics_context)
            }
        }
        self.mem = 0
    }
}
<|endoftext|>


<commit_before>use rlua::{self, Lua};
use wlroots::{key_events::KeyEvent,
              xkbcommon::xkb::{KEY_Escape, KEY_Super_L, KEY_Super_R}, CompositorHandle,
              KeyboardHandle, KeyboardHandler, WLR_KEY_PRESSED, KeyboardModifier};

use awesome::{self, emit_object_signal, Objectable, LUA, ROOT_KEYS_HANDLE};
use compositor::Server;

pub struct Keyboard;

fn key_is_meta(key: u32) -> bool {
    // TODO configure meta key
    key == KEY_Super_L || key == KEY_Super_R
}

impl KeyboardHandler for Keyboard {
    fn on_key(&mut self,
              compositor: CompositorHandle,
              keyboard: KeyboardHandle,
              event: &KeyEvent) {
        with_handles!([(compositor: {compositor})] => {
            if event.key_state() == WLR_KEY_PRESSED {
                for key in event.pressed_keys() {
                    if key == KEY_Escape {
                        compositor.terminate();
                        ::awesome::lua::terminate();
                        return
                    }
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = true;
                    }
                }
            } else {
                for key in event.pressed_keys() {
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = false;
                    }
                }
            }
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_key(event.time_msec(),
                                         event.keycode(),
                                         event.key_state() as u32);
                seat.keyboard_send_modifiers(&mut keyboard.get_modifier_masks());
                let modifiers = keyboard.get_modifiers();
                // TODO Move up so that compositor isn't borrowed
                LUA.with(|lua| {
                    let lua = lua.borrow_mut();
                    if let Err(err) = emit_awesome_keybindings(&*lua, event, modifiers) {
                        warn!("Could not emit binding for {}: {:?}", event.keycode(), err);
                    }
                });
            }).expect("Seat was destroyed");
        }).unwrap();
    }

    fn modifiers(&mut self, compositor: CompositorHandle, keyboard: KeyboardHandle) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_modifiers(&mut keyboard.get_modifier_masks());
            }).unwrap();
        }).unwrap();
    }
}

/// Emits the Awesome keybindinsg.
fn emit_awesome_keybindings(lua: &Lua,
                            event: &KeyEvent,
                            event_modifiers: KeyboardModifier)
                            -> rlua::Result<()> {
    let state_string = if event.key_state() == WLR_KEY_PRESSED {
        "press"
    } else {
        "release"
    };
    // TODO Should also emit by current focused client so we can
    // do client based rules.
    let keybindings = lua.named_registry_value::<Vec<rlua::AnyUserData>>(ROOT_KEYS_HANDLE)?;
    for event_keysym in event.pressed_keys() {
        for binding in &keybindings {
            let obj: awesome::Object = binding.clone().into();
            let key = awesome::Key::cast(obj.clone()).unwrap();
            let keycode = key.keycode()?;
            let keysym = key.keysym()?;
            let modifiers = key.modifiers()?;
            let binding_match = (keysym != 0 && keysym == event_keysym
                                 || keycode != 0 && keycode == event.keycode())
                                && modifiers == 0
                                || modifiers == event_modifiers.bits();
            if binding_match {
                emit_object_signal(&*lua, obj, state_string.into(), event_keysym)?;
            }
        }
    }
    Ok(())
}
<commit_msg>Drop compositor before calling user lua code<commit_after>use rlua::{self, Lua};
use wlroots::{key_events::KeyEvent,
              xkbcommon::xkb::{KEY_Escape, KEY_Super_L, KEY_Super_R}, CompositorHandle,
              KeyboardHandle, KeyboardHandler, WLR_KEY_PRESSED, KeyboardModifier};

use awesome::{self, emit_object_signal, Objectable, LUA, ROOT_KEYS_HANDLE};
use compositor::Server;

pub struct Keyboard;

fn key_is_meta(key: u32) -> bool {
    // TODO configure meta key
    key == KEY_Super_L || key == KEY_Super_R
}

impl KeyboardHandler for Keyboard {
    fn on_key(&mut self,
              compositor: CompositorHandle,
              keyboard: KeyboardHandle,
              event: &KeyEvent) {
        let modifiers = with_handles!([(compositor: {compositor})] => {
            if event.key_state() == WLR_KEY_PRESSED {
                for key in event.pressed_keys() {
                    if key == KEY_Escape {
                        compositor.terminate();
                        ::awesome::lua::terminate();
                    }
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = true;
                    }
                }
            } else {
                for key in event.pressed_keys() {
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = false;
                    }
                }
            }
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_key(event.time_msec(),
                                         event.keycode(),
                                         event.key_state() as u32);
                seat.keyboard_send_modifiers(&mut keyboard.get_modifier_masks());
                keyboard.get_modifiers()
                // TODO Move up so that compositor isn't borrowed
            }).expect("Seat was destroyed")
        }).unwrap();
        LUA.with(|lua| {
                     let lua = lua.borrow_mut();
                     if let Err(err) = emit_awesome_keybindings(&*lua, event, modifiers) {
                         warn!("Could not emit binding for {}: {:?}", event.keycode(), err);
                     }
                 });
    }

    fn modifiers(&mut self, compositor: CompositorHandle, keyboard: KeyboardHandle) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_modifiers(&mut keyboard.get_modifier_masks());
            }).unwrap();
        }).unwrap();
    }
}

/// Emits the Awesome keybindinsg.
fn emit_awesome_keybindings(lua: &Lua,
                            event: &KeyEvent,
                            event_modifiers: KeyboardModifier)
                            -> rlua::Result<()> {
    let state_string = if event.key_state() == WLR_KEY_PRESSED {
        "press"
    } else {
        "release"
    };
    // TODO Should also emit by current focused client so we can
    // do client based rules.
    let keybindings = lua.named_registry_value::<Vec<rlua::AnyUserData>>(ROOT_KEYS_HANDLE)?;
    for event_keysym in event.pressed_keys() {
        for binding in &keybindings {
            let obj: awesome::Object = binding.clone().into();
            let key = awesome::Key::cast(obj.clone()).unwrap();
            let keycode = key.keycode()?;
            let keysym = key.keysym()?;
            let modifiers = key.modifiers()?;
            let binding_match = (keysym != 0 && keysym == event_keysym
                                 || keycode != 0 && keycode == event.keycode())
                                && modifiers == 0
                                || modifiers == event_modifiers.bits();
            if binding_match {
                emit_object_signal(&*lua, obj, state_string.into(), event_keysym)?;
            }
        }
    }
    Ok(())
}
<|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/.

// Code to handle a single block device.

use std::collections::HashMap;
use std::io::ErrorKind;
use std::fs::{OpenOptions, read_dir};
use std::os::linux::fs::MetadataExt;
use std::path::PathBuf;

use nix::Errno;
use nix::sys::stat::{S_IFBLK, S_IFMT};
use serde_json;

use engine::{EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{BDA, StaticHeader};
use super::engine::DevOwnership;
use super::serde_structs::PoolSave;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a vector of devices for each pool.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, Vec<PathBuf>>> {

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let dir_e = try!(dir_e);
        let mode = try!(dir_e.metadata()).st_mode();

        // Device node can't belong to Stratis if it is not a block device
        if mode & S_IFMT.bits() != S_IFBLK.bits() {
            continue;
        }

        let devnode = dir_e.path();

        let f = OpenOptions::new().read(true).open(&devnode);

        // There are some reasons for OpenOptions::open() to return an error
        // which are not reasons for this method to return an error.
        // Try to distinguish. Non-error conditions are:
        // 1. The device does not exist anymore. This means that the device
        // was volatile for some reason; in that case it can not belong to
        // Stratis so it is safe to ignore it.
        //
        // Note that it is better to be conservative and return with an
        // error in any case where failure to read the device could result
        // in bad data for Stratis. Additional exceptions may be added,
        // but only with a complete justification.
        if f.is_err() {
            let err = f.unwrap_err();
            match err.kind() {
                ErrorKind::NotFound => {
                    continue;
                }
                _ => {
                    if let Some(errno) = err.raw_os_error() {
                        if Errno::from_i32(errno) == Errno::ENXIO {
                            continue;
                        } else {
                            return Err(EngineError::Io(err));
                        }
                    } else {
                        return Err(EngineError::Io(err));
                    }
                }
            }
        }

        let mut f = f.expect("unreachable if f is err");

        match try!(StaticHeader::determine_ownership(&mut f)) {
            DevOwnership::Ours(uuid) => {
                pool_map
                    .entry(uuid)
                    .or_insert_with(Vec::new)
                    .push(devnode)
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
pub fn get_metadata(pool_uuid: &PoolUuid, devnodes: &[PathBuf]) -> EngineResult<Option<PoolSave>> {

    // No device nodes means no metadata
    if devnodes.is_empty() {
        return Ok(None);
    }

    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes {
        let bda = try!(BDA::load(&mut try!(OpenOptions::new().read(true).open(devnode))));
        if bda.is_none() {
            continue;
        }
        let bda = bda.expect("unreachable if bda is None");

        if bda.pool_uuid() != pool_uuid {
            continue;
        }
        bdas.push((devnode, bda));
    }

    // We may have had no devices with BDAs for this pool, so return if no BDAs.
    if bdas.is_empty() {
        return Ok(None);
    }

    // Get a most recent BDA
    let &(_, ref most_recent_bda) = bdas.iter()
        .max_by_key(|p| p.1.last_update_time())
        .expect("bdas is not empty, must have a max");

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = most_recent_bda.last_update_time();
    if most_recent_time.is_none() {
        return Ok(None);
    }

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in
        bdas.iter()
            .filter(|p| p.1.last_update_time() == most_recent_time) {

        let f = OpenOptions::new().read(true).open(devnode);
        if f.is_err() {
            continue;
        }
        let mut f = f.expect("f is not err");

        if let Ok(Some(data)) = bda.load_state(&mut f) {
            let json: serde_json::Result<PoolSave> = serde_json::from_slice(&data);
            if let Ok(pool) = json {
                return Ok(Some(pool));
            } else {
                continue;
            }
        } else {
            continue;
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data succesfully read";
    Err(EngineError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get the most recent metadata for each pool.
/// Since the metadata is written immediately after a pool is created, it
/// is considered an error for a pool to be w/out metadata.
pub fn get_pool_metadata(pool_table: &HashMap<PoolUuid, Vec<PathBuf>>)
                         -> EngineResult<HashMap<PoolUuid, PoolSave>> {
    let mut metadata = HashMap::new();
    for (pool_uuid, devices) in pool_table.iter() {
        if let Ok(Some(pool)) = get_metadata(pool_uuid, &devices) {
            metadata.insert(pool_uuid.clone(), pool);
        } else {
            return Err(EngineError::Engine(ErrorEnum::NotFound,
                                           format!("no metadata for pool {}", pool_uuid)));
        }
    }
    Ok(metadata)
}
<commit_msg>Change a match expression to an if-let<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/.

// Code to handle a single block device.

use std::collections::HashMap;
use std::io::ErrorKind;
use std::fs::{OpenOptions, read_dir};
use std::os::linux::fs::MetadataExt;
use std::path::PathBuf;

use nix::Errno;
use nix::sys::stat::{S_IFBLK, S_IFMT};
use serde_json;

use engine::{EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{BDA, StaticHeader};
use super::engine::DevOwnership;
use super::serde_structs::PoolSave;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a vector of devices for each pool.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, Vec<PathBuf>>> {

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let dir_e = try!(dir_e);
        let mode = try!(dir_e.metadata()).st_mode();

        // Device node can't belong to Stratis if it is not a block device
        if mode & S_IFMT.bits() != S_IFBLK.bits() {
            continue;
        }

        let devnode = dir_e.path();

        let f = OpenOptions::new().read(true).open(&devnode);

        // There are some reasons for OpenOptions::open() to return an error
        // which are not reasons for this method to return an error.
        // Try to distinguish. Non-error conditions are:
        // 1. The device does not exist anymore. This means that the device
        // was volatile for some reason; in that case it can not belong to
        // Stratis so it is safe to ignore it.
        //
        // Note that it is better to be conservative and return with an
        // error in any case where failure to read the device could result
        // in bad data for Stratis. Additional exceptions may be added,
        // but only with a complete justification.
        if f.is_err() {
            let err = f.unwrap_err();
            match err.kind() {
                ErrorKind::NotFound => {
                    continue;
                }
                _ => {
                    if let Some(errno) = err.raw_os_error() {
                        if Errno::from_i32(errno) == Errno::ENXIO {
                            continue;
                        } else {
                            return Err(EngineError::Io(err));
                        }
                    } else {
                        return Err(EngineError::Io(err));
                    }
                }
            }
        }

        let mut f = f.expect("unreachable if f is err");
        if let DevOwnership::Ours(uuid) = try!(StaticHeader::determine_ownership(&mut f)) {
            pool_map
                .entry(uuid)
                .or_insert_with(Vec::new)
                .push(devnode)
        };
    }

    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
pub fn get_metadata(pool_uuid: &PoolUuid, devnodes: &[PathBuf]) -> EngineResult<Option<PoolSave>> {

    // No device nodes means no metadata
    if devnodes.is_empty() {
        return Ok(None);
    }

    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes {
        let bda = try!(BDA::load(&mut try!(OpenOptions::new().read(true).open(devnode))));
        if bda.is_none() {
            continue;
        }
        let bda = bda.expect("unreachable if bda is None");

        if bda.pool_uuid() != pool_uuid {
            continue;
        }
        bdas.push((devnode, bda));
    }

    // We may have had no devices with BDAs for this pool, so return if no BDAs.
    if bdas.is_empty() {
        return Ok(None);
    }

    // Get a most recent BDA
    let &(_, ref most_recent_bda) = bdas.iter()
        .max_by_key(|p| p.1.last_update_time())
        .expect("bdas is not empty, must have a max");

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = most_recent_bda.last_update_time();
    if most_recent_time.is_none() {
        return Ok(None);
    }

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in
        bdas.iter()
            .filter(|p| p.1.last_update_time() == most_recent_time) {

        let f = OpenOptions::new().read(true).open(devnode);
        if f.is_err() {
            continue;
        }
        let mut f = f.expect("f is not err");

        if let Ok(Some(data)) = bda.load_state(&mut f) {
            let json: serde_json::Result<PoolSave> = serde_json::from_slice(&data);
            if let Ok(pool) = json {
                return Ok(Some(pool));
            } else {
                continue;
            }
        } else {
            continue;
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data succesfully read";
    Err(EngineError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get the most recent metadata for each pool.
/// Since the metadata is written immediately after a pool is created, it
/// is considered an error for a pool to be w/out metadata.
pub fn get_pool_metadata(pool_table: &HashMap<PoolUuid, Vec<PathBuf>>)
                         -> EngineResult<HashMap<PoolUuid, PoolSave>> {
    let mut metadata = HashMap::new();
    for (pool_uuid, devices) in pool_table.iter() {
        if let Ok(Some(pool)) = get_metadata(pool_uuid, &devices) {
            metadata.insert(pool_uuid.clone(), pool);
        } else {
            return Err(EngineError::Engine(ErrorEnum::NotFound,
                                           format!("no metadata for pool {}", pool_uuid)));
        }
    }
    Ok(metadata)
}
<|endoftext|>