<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match self {
            &Value::Nil => false,
            &Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => u.interpret(),
            &Expr::Binary(ref b) => b.interpret(),
            &Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::RuntimeError),
                }
            }
        }
    }
}

impl Interpret for BinaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let left = try!(self.left.interpret());
        let right = try!(self.right.interpret());
        match (&self.operator, &left, &right) {
            (&BinaryOperator::Minus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l - r))
            }
            (&BinaryOperator::Slash, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l / r))
            }
            (&BinaryOperator::Star, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l * r))
            }
            (&BinaryOperator::Plus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l + r))
            }
            (&BinaryOperator::Minus, &Value::String(ref l), &Value::String(ref r)) => {
                let mut result : String = "".into();
                result.push_str(l);
                result.push_str(r);
                Ok(Value::String(result))
            }
            _ => unimplemented!(),
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!(Value::String("abc".into()), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

}
<commit_msg>Actually using the Plus operator<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug, PartialEq)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

impl Value {
    fn is_true(&self) -> bool {
        match self {
            &Value::Nil => false,
            &Value::Boolean(b) => b,
            _ => true,
        }
    }
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => u.interpret(),
            &Expr::Binary(ref b) => b.interpret(),
            &Expr::Grouping(ref g) => g.interpret(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}

impl Interpret for Grouping {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        self.expr.interpret()
    }
}

impl Interpret for UnaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let value = try!(self.right.interpret());
        match self.operator {
            UnaryOperator::Bang => Ok(Value::Boolean(!value.is_true())),
            UnaryOperator::Minus => {
                match value {
                    Value::Number(n) => Ok(Value::Number(-n)),
                    _ => Err(RuntimeError::RuntimeError),
                }
            }
        }
    }
}

impl Interpret for BinaryExpr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        let left = try!(self.left.interpret());
        let right = try!(self.right.interpret());
        match (&self.operator, &left, &right) {
            (&BinaryOperator::Minus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l - r))
            }
            (&BinaryOperator::Slash, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l / r))
            }
            (&BinaryOperator::Star, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l * r))
            }
            (&BinaryOperator::Plus, &Value::Number(l), &Value::Number(r)) => {
                Ok(Value::Number(l + r))
            }
            (&BinaryOperator::Plus, &Value::String(ref l), &Value::String(ref r)) => {
                let mut result : String = "".into();
                result.push_str(l);
                result.push_str(r);
                Ok(Value::String(result))
            }
            _ => unimplemented!(),
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use interpreter::{Interpret, Value};

    #[test]
    fn literal() {
        let expr = Expr::Literal(Literal::StringLiteral("abc".into()));
        assert_eq!(Value::String("abc".into()), expr.interpret().unwrap());
    }

    #[test]
    fn grouping() {
        let expr = Grouping { expr: Expr::Literal(Literal::NumberLiteral(45.67f64)) };
        assert_eq!(Value::Number(45.67f64), expr.interpret().unwrap());
    }

    #[test]
    fn unary() {
        let expr = UnaryExpr {
            operator: UnaryOperator::Bang,
            right: Expr::Literal(Literal::BoolLiteral(false)),
        };
        assert_eq!(Value::Boolean(true), expr.interpret().unwrap());
    }

}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module implements the `Any` trait, which enables dynamic typing
//! of any `'static` type through runtime reflection.
//!
//! `Any` itself can be used to get a `TypeId`, and has more features when used
//! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and
//! `as_ref` methods, to test if the contained value is of a given type, and to
//! get a reference to the inner value as a type. As `&mut Any`, there is also
//! the `as_mut` method, for getting a mutable reference to the inner value.
//! `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the
//! object.  See the extension traits (`*Ext`) for the full details.
//!
//! Note that &Any is limited to testing whether a value is of a specified
//! concrete type, and cannot be used to test whether a type implements a trait.
//!
//! # Examples
//!
//! Consider a situation where we want to log out a value passed to a function.
//! We know the value we're working on implements Debug, but we don't know its
//! concrete type.  We want to give special treatment to certain types: in this
//! case printing out the length of String values prior to their value.
//! We don't know the concrete type of our value at compile time, so we need to
//! use runtime reflection instead.
//!
//! ```rust
//! use std::fmt::Debug;
//! use std::any::Any;
//!
//! // Logger function for any type that implements Debug.
//! fn log<T: Any + Debug>(value: &T) {
//!     let value_any = value as &Any;
//!
//!     // try to convert our value to a String.  If successful, we want to
//!     // output the String's length as well as its value.  If not, it's a
//!     // different type: just print it out unadorned.
//!     match value_any.downcast_ref::<String>() {
//!         Some(as_string) => {
//!             println!("String ({}): {}", as_string.len(), as_string);
//!         }
//!         None => {
//!             println!("{:?}", value);
//!         }
//!     }
//! }
//!
//! // This function wants to log its parameter out prior to doing work with it.
//! fn do_work<T: Any + Debug>(value: &T) {
//!     log(value);
//!     // ...do some other work
//! }
//!
//! fn main() {
//!     let my_string = "Hello World".to_string();
//!     do_work(&my_string);
//!
//!     let my_i8: i8 = 100;
//!     do_work(&my_i8);
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

use fmt;
use marker::Send;
use mem::transmute;
use option::Option::{self, Some, None};
use raw::TraitObject;
use intrinsics;
use marker::{Reflect, Sized};

///////////////////////////////////////////////////////////////////////////////
// Any trait
///////////////////////////////////////////////////////////////////////////////

/// A type to emulate dynamic typing.
///
/// Every type with no non-`'static` references implements `Any`.
/// See the [module-level documentation][mod] for more details.
///
/// [mod]: index.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Any: Reflect + 'static {
    /// Gets the `TypeId` of `self`.
    #[unstable(feature = "get_type_id",
               reason = "this method will likely be replaced by an associated static",
               issue = "27745")]
    fn get_type_id(&self) -> TypeId;
}

impl<T: Reflect + 'static> Any for T {
    fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
///////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Any {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Any")
    }
}

// Ensure that the result of e.g. joining a thread can be printed and
// hence used with `unwrap`. May eventually no longer be needed if
// dispatch works with upcasting.
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Any + Send {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Any")
    }
}

impl Any {
    /// Returns true if the boxed type is the same as `T`
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute(self);

                // Extract the data pointer
                Some(&*(to.data as *const T))
            }
        } else {
            None
        }
    }

    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute(self);

                // Extract the data pointer
                Some(&mut *(to.data as *const T as *mut T))
            }
        } else {
            None
        }
    }
}

impl Any+Send {
    /// Forwards to the method defined on the type `Any`.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        Any::is::<T>(self)
    }

    /// Forwards to the method defined on the type `Any`.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        Any::downcast_ref::<T>(self)
    }

    /// Forwards to the method defined on the type `Any`.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        Any::downcast_mut::<T>(self)
    }
}

///////////////////////////////////////////////////////////////////////////////
// TypeID and its methods
///////////////////////////////////////////////////////////////////////////////

/// A `TypeId` represents a globally unique identifier for a type.
///
/// Each `TypeId` is an opaque object which does not allow inspection of what's
/// inside but does allow basic operations such as cloning, comparison,
/// printing, and showing.
///
/// A `TypeId` is currently only available for types which ascribe to `'static`,
/// but this limitation may be removed in the future.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct TypeId {
    t: u64,
}

impl TypeId {
    /// Returns the `TypeId` of the type this generic function has been
    /// instantiated with
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
        TypeId {
            t: unsafe { intrinsics::type_id::<T>() },
        }
    }
}
<commit_msg>Auto merge of #28021 - steveklabnik:gh27958, r=alexcrichton<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module implements the `Any` trait, which enables dynamic typing
//! of any `'static` type through runtime reflection.
//!
//! `Any` itself can be used to get a `TypeId`, and has more features when used
//! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and
//! `downcast_ref` methods, to test if the contained value is of a given type,
//! and to get a reference to the inner value as a type. As `&mut Any`, there
//! is also the `downcast_mut` method, for getting a mutable reference to the
//! inner value. `Box<Any>` adds the `move` method, which will unwrap a
//! `Box<T>` from the object. See the extension traits (`*Ext`) for the full
//! details.
//!
//! Note that &Any is limited to testing whether a value is of a specified
//! concrete type, and cannot be used to test whether a type implements a trait.
//!
//! # Examples
//!
//! Consider a situation where we want to log out a value passed to a function.
//! We know the value we're working on implements Debug, but we don't know its
//! concrete type.  We want to give special treatment to certain types: in this
//! case printing out the length of String values prior to their value.
//! We don't know the concrete type of our value at compile time, so we need to
//! use runtime reflection instead.
//!
//! ```rust
//! use std::fmt::Debug;
//! use std::any::Any;
//!
//! // Logger function for any type that implements Debug.
//! fn log<T: Any + Debug>(value: &T) {
//!     let value_any = value as &Any;
//!
//!     // try to convert our value to a String.  If successful, we want to
//!     // output the String's length as well as its value.  If not, it's a
//!     // different type: just print it out unadorned.
//!     match value_any.downcast_ref::<String>() {
//!         Some(as_string) => {
//!             println!("String ({}): {}", as_string.len(), as_string);
//!         }
//!         None => {
//!             println!("{:?}", value);
//!         }
//!     }
//! }
//!
//! // This function wants to log its parameter out prior to doing work with it.
//! fn do_work<T: Any + Debug>(value: &T) {
//!     log(value);
//!     // ...do some other work
//! }
//!
//! fn main() {
//!     let my_string = "Hello World".to_string();
//!     do_work(&my_string);
//!
//!     let my_i8: i8 = 100;
//!     do_work(&my_i8);
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]

use fmt;
use marker::Send;
use mem::transmute;
use option::Option::{self, Some, None};
use raw::TraitObject;
use intrinsics;
use marker::{Reflect, Sized};

///////////////////////////////////////////////////////////////////////////////
// Any trait
///////////////////////////////////////////////////////////////////////////////

/// A type to emulate dynamic typing.
///
/// Every type with no non-`'static` references implements `Any`.
/// See the [module-level documentation][mod] for more details.
///
/// [mod]: index.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Any: Reflect + 'static {
    /// Gets the `TypeId` of `self`.
    #[unstable(feature = "get_type_id",
               reason = "this method will likely be replaced by an associated static",
               issue = "27745")]
    fn get_type_id(&self) -> TypeId;
}

impl<T: Reflect + 'static> Any for T {
    fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
///////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Any {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Any")
    }
}

// Ensure that the result of e.g. joining a thread can be printed and
// hence used with `unwrap`. May eventually no longer be needed if
// dispatch works with upcasting.
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Any + Send {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Any")
    }
}

impl Any {
    /// Returns true if the boxed type is the same as `T`
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute(self);

                // Extract the data pointer
                Some(&*(to.data as *const T))
            }
        } else {
            None
        }
    }

    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute(self);

                // Extract the data pointer
                Some(&mut *(to.data as *const T as *mut T))
            }
        } else {
            None
        }
    }
}

impl Any+Send {
    /// Forwards to the method defined on the type `Any`.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        Any::is::<T>(self)
    }

    /// Forwards to the method defined on the type `Any`.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        Any::downcast_ref::<T>(self)
    }

    /// Forwards to the method defined on the type `Any`.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        Any::downcast_mut::<T>(self)
    }
}

///////////////////////////////////////////////////////////////////////////////
// TypeID and its methods
///////////////////////////////////////////////////////////////////////////////

/// A `TypeId` represents a globally unique identifier for a type.
///
/// Each `TypeId` is an opaque object which does not allow inspection of what's
/// inside but does allow basic operations such as cloning, comparison,
/// printing, and showing.
///
/// A `TypeId` is currently only available for types which ascribe to `'static`,
/// but this limitation may be removed in the future.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct TypeId {
    t: u64,
}

impl TypeId {
    /// Returns the `TypeId` of the type this generic function has been
    /// instantiated with
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
        TypeId {
            t: unsafe { intrinsics::type_id::<T>() },
        }
    }
}
<|endoftext|>


<commit_before>extern crate nix;

use std::error::Error;
use std::fmt;
use std::path::PathBuf;

use nix::sched::{unshare, setns};
use nix::fcntl::open;
use nix::unistd::{getpid, gettid};
use nix::sys::stat::Mode;
use nix::Error as NError;

pub struct NetNS {
    fd: i32,
    path: PathBuf,
}

#[derive(Debug)]
pub enum NetNSError {
    CreateNetNSError,
}

impl Error for NetNSError {
    fn description(&self) -> &str {
        "Cannot create"
    }
}

impl fmt::Debug for NetNS {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NetNS {{ fd: {}, path: {} }}", self.fd, self.path.display())
    }
}

impl NetNS {
    pub fn new() -> Result<NetNS, NetNSError> {
        unshare(nix::sched::CLONE_NEWNET).expect("failed");
        NetNS::get()
    }

    pub fn get() -> Result<NetNS, NetNSError> {
        return NetNS::get_from_thread(getpid(), gettid());
    }

    pub fn set(ns: NetNS) -> Result<(), NError> {
        setns(ns.fd, nix::sched::CLONE_NEWNET)
    }

    fn get_from_thread(pid: i32, tid: i32) -> Result<NetNS, NetNSError> {
        return NetNS::get_from_path(PathBuf::from(format!("/proc/{}/task/{}/ns/net", pid, tid)
            .as_str()));
    }

    fn get_from_path(path: PathBuf) -> Result<NetNS, NetNSError> {
        let fd = open(&path, nix::fcntl::O_RDONLY, Mode::empty()).expect("Could not open");
        return Ok(NetNS {
            fd: fd,
            path: path,
        });
    }
}

impl fmt::Display for NetNSError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "oops")
    }
}
<commit_msg>make more methods public<commit_after>extern crate nix;

use std::error::Error;
use std::fmt;
use std::path::PathBuf;

use nix::sched::{unshare, setns};
use nix::fcntl::open;
use nix::unistd::{getpid, gettid};
use nix::sys::stat::Mode;
use nix::Error as NError;

pub struct NetNS {
    fd: i32,
    path: PathBuf,
}

#[derive(Debug)]
pub enum NetNSError {
    CreateNetNSError,
}

impl Error for NetNSError {
    fn description(&self) -> &str {
        "Cannot create"
    }
}

impl fmt::Debug for NetNS {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NetNS {{ fd: {}, path: {} }}", self.fd, self.path.display())
    }
}

impl NetNS {
    pub fn new() -> Result<NetNS, NetNSError> {
        unshare(nix::sched::CLONE_NEWNET).expect("failed");
        NetNS::get()
    }

    pub fn get() -> Result<NetNS, NetNSError> {
        return NetNS::get_from_thread(getpid(), gettid());
    }

    pub fn set(ns: NetNS) -> Result<(), NError> {
        setns(ns.fd, nix::sched::CLONE_NEWNET)
    }

    pub fn get_from_thread(pid: i32, tid: i32) -> Result<NetNS, NetNSError> {
        return NetNS::get_from_path(PathBuf::from(format!("/proc/{}/task/{}/ns/net", pid, tid)
            .as_str()));
    }

    pub fn get_from_process(pid: i32) -> Result<NetNS, NetNSError> {
        return NetNS::get_from_path(PathBuf::from(format!("/proc/{}/ns/net", pid)
            .as_str()));
    }

    pub fn get_from_path(path: PathBuf) -> Result<NetNS, NetNSError> {
        let fd = open(&path, nix::fcntl::O_RDONLY, Mode::empty()).expect("Could not open");
        return Ok(NetNS {
            fd: fd,
            path: path,
        });
    }
}

impl fmt::Display for NetNSError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "oops")
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

use client::PluginRegister;
use events::MessageEvent;

fn log_message(event: &MessageEvent) {
    let nick = event.mask.nick().unwrap_or_else(|| event.mask.mask().unwrap_or("*unknown*"));
    let message = match event.command.to_ascii_uppercase().as_slice() {
        "PRIVMSG" => match event.ctcp() {
            Some((ctcp_command, ctcp_message)) => match ctcp_command {
                "ACTION" => format!("[{}] * {} {}", event.args[0], nick, ctcp_message),
                _ => if ctcp_message.len() == 0 {
                    format!("[{}] CTCP {} from {}", event.args[0], ctcp_command, nick)
                } else {
                    format!("[{}] CTCP {} from {}: {}", event.args[0], ctcp_command, nick,
                        ctcp_message)
                },
            },
            None => format!("[{}] <{}> {}", event.args[0], nick, event.args.slice_from(1)
                .connect(" ").slice_from(1)),
        },
        "NOTICE" => format!("[{}] -{}- {}", event.args[0], nick, event.args.slice_from(1)
            .connect(" ").slice_from(1)),
        "JOIN" => format!("[{}] *** {} joined", event.args[0], nick),
        "PART" => format!("[{}] *** {} left ({})", event.args[0], nick, event.args[1]),
        "KICK" => {
            if event.args.len() > 2 {
                format!("[{}] *** {} kicked {} ({})", event.args[0], nick, event.args[1],
                    event.args.slice_from(2).connect(" ").slice_from(1))
            } else {
                format!("[{}] *** {} kicked {}", event.args[0], nick, event.args[1])
            }
        },
        "TOPIC" => format!("[{}] *** {} changed the topic to \"{}\"", event.args[0], nick,
            event.args.slice_from(1).connect(" ").slice_from(1)),
        "PING" => return, // don't log pings
        _ => match event.mask.mask() {
            Some(mask) => format!("{} {} {}", mask, event.command, event.args.connect(" ")),
            None => format!("{} {}", event.command, event.args.connect(" ")),
        }
    };
    info!("{}", message);
}

pub fn register(register: &mut PluginRegister) {
    register.register_catch_all(log_message);
}
<commit_msg>Update log to work with PART messages without any message argument<commit_after>use std::ascii::AsciiExt;

use client::PluginRegister;
use events::MessageEvent;

fn log_message(event: &MessageEvent) {
    let nick = event.mask.nick().unwrap_or_else(|| event.mask.mask().unwrap_or("*unknown*"));
    let message = match event.command.to_ascii_uppercase().as_slice() {
        "PRIVMSG" => match event.ctcp() {
            Some((ctcp_command, ctcp_message)) => match ctcp_command {
                "ACTION" => format!("[{}] * {} {}", event.args[0], nick, ctcp_message),
                _ => if ctcp_message.len() == 0 {
                    format!("[{}] CTCP {} from {}", event.args[0], ctcp_command, nick)
                } else {
                    format!("[{}] CTCP {} from {}: {}", event.args[0], ctcp_command, nick,
                        ctcp_message)
                },
            },
            None => format!("[{}] <{}> {}", event.args[0], nick, event.args.slice_from(1)
                .connect(" ").slice_from(1)),
        },
        "NOTICE" => format!("[{}] -{}- {}", event.args[0], nick, event.args.slice_from(1)
            .connect(" ").slice_from(1)),
        "JOIN" => format!("[{}] *** {} joined", event.args[0], nick),
        "PART" => {
            if event.args.len() > 1 {
                format!("[{}] *** {} left ({})", event.args[0], nick, event.args[1])
            } else {
                format!("[{}] *** {} left", event.args[0], nick)
            }

        },
        "KICK" => {
            if event.args.len() > 2 {
                format!("[{}] *** {} kicked {} ({})", event.args[0], nick, event.args[1],
                    event.args.slice_from(2).connect(" ").slice_from(1))
            } else {
                format!("[{}] *** {} kicked {}", event.args[0], nick, event.args[1])
            }
        },
        "TOPIC" => format!("[{}] *** {} changed the topic to \"{}\"", event.args[0], nick,
            event.args.slice_from(1).connect(" ").slice_from(1)),
        "PING" => return, // don't log pings
        _ => match event.mask.mask() {
            Some(mask) => format!("{} {} {}", mask, event.command, event.args.connect(" ")),
            None => format!("{} {}", event.command, event.args.connect(" ")),
        }
    };
    info!("{}", message);
}

pub fn register(register: &mut PluginRegister) {
    register.register_catch_all(log_message);
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{lldb_pid_t, sys, SBFileSpec};
use std::ffi::CStr;

#[allow(missing_docs)]
#[derive(Debug)]
pub struct SBProcessInfo {
    /// The underlying raw `SBProcessInfoRef`.
    pub raw: sys::SBProcessInfoRef,
}

impl SBProcessInfo {
    /// Construct a new `SBProcessInfo`.
    pub(crate) fn wrap(raw: sys::SBProcessInfoRef) -> SBProcessInfo {
        SBProcessInfo { raw }
    }

    #[allow(missing_docs)]
    pub fn name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBProcessInfoGetName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn executable_file(&self) -> SBFileSpec {
        SBFileSpec::wrap(unsafe { sys::SBProcessInfoGetExecutableFile(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn process_id(&self) -> lldb_pid_t {
        unsafe { sys::SBProcessInfoGetProcessID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn user_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoUserIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetUserID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn group_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoGroupIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetGroupID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn effective_user_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoEffectiveUserIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetEffectiveUserID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn effective_group_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoEffectiveGroupIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetEffectiveGroupID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn parent_process_id(&self) -> lldb_pid_t {
        unsafe { sys::SBProcessInfoGetParentProcessID(self.raw) }
    }
}

impl Clone for SBProcessInfo {
    fn clone(&self) -> SBProcessInfo {
        SBProcessInfo {
            raw: unsafe { sys::CloneSBProcessInfo(self.raw) },
        }
    }
}

impl Drop for SBProcessInfo {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBProcessInfo(self.raw) };
    }
}

unsafe impl Send for SBProcessInfo {}
unsafe impl Sync for SBProcessInfo {}

#[cfg(feature = "graphql")]
#[graphql_object]
impl SBProcessInfo {
    fn name() -> &str {
        self.name()
    }

    fn executable_file() -> SBFileSpec {
        self.executable_file()
    }

    // TODO(bm) This should be lldb_pid_t
    fn process_id() -> i32 {
        self.process_id() as i32
    }

    // TODO(bm) This should be u32
    fn user_id() -> Option<i32> {
        self.user_id().map(|i| i as i32)
    }

    // TODO(bm) This should be u32
    fn group_id() -> Option<i32> {
        self.group_id().map(|i| i as i32)
    }

    // TODO(bm) This should be u32
    fn effective_user_id() -> Option<i32> {
        self.effective_user_id().map(|i| i as i32)
    }

    // TODO(bm) This should be u32
    fn effective_group_id() -> Option<i32> {
        self.effective_group_id().map(|i| i as i32)
    }

    // TODO(bm) This should be lldb_pid_t
    fn parent_process_id() -> i32 {
        self.parent_process_id() as i32
    }
}
<commit_msg>SBProcessInfo: Add triple.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{lldb_pid_t, sys, SBFileSpec};
use std::ffi::CStr;

/// Describes an existing process and any discoverable information that
/// pertains to that process.
#[derive(Debug)]
pub struct SBProcessInfo {
    /// The underlying raw `SBProcessInfoRef`.
    pub raw: sys::SBProcessInfoRef,
}

impl SBProcessInfo {
    /// Construct a new `SBProcessInfo`.
    pub(crate) fn wrap(raw: sys::SBProcessInfoRef) -> SBProcessInfo {
        SBProcessInfo { raw }
    }

    #[allow(missing_docs)]
    pub fn name(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBProcessInfoGetName(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn executable_file(&self) -> SBFileSpec {
        SBFileSpec::wrap(unsafe { sys::SBProcessInfoGetExecutableFile(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn process_id(&self) -> lldb_pid_t {
        unsafe { sys::SBProcessInfoGetProcessID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn user_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoUserIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetUserID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn group_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoGroupIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetGroupID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn effective_user_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoEffectiveUserIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetEffectiveUserID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn effective_group_id(&self) -> Option<u32> {
        if unsafe { sys::SBProcessInfoEffectiveGroupIDIsValid(self.raw) } {
            Some(unsafe { sys::SBProcessInfoGetEffectiveGroupID(self.raw) })
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn parent_process_id(&self) -> lldb_pid_t {
        unsafe { sys::SBProcessInfoGetParentProcessID(self.raw) }
    }

    /// Return the target triple (arch-vendor-os) for the described process.
    pub fn triple(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBProcessInfoGetTriple(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }
}

impl Clone for SBProcessInfo {
    fn clone(&self) -> SBProcessInfo {
        SBProcessInfo {
            raw: unsafe { sys::CloneSBProcessInfo(self.raw) },
        }
    }
}

impl Drop for SBProcessInfo {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBProcessInfo(self.raw) };
    }
}

unsafe impl Send for SBProcessInfo {}
unsafe impl Sync for SBProcessInfo {}

#[cfg(feature = "graphql")]
#[graphql_object]
impl SBProcessInfo {
    fn name() -> &str {
        self.name()
    }

    fn executable_file() -> SBFileSpec {
        self.executable_file()
    }

    // TODO(bm) This should be lldb_pid_t
    fn process_id() -> i32 {
        self.process_id() as i32
    }

    // TODO(bm) This should be u32
    fn user_id() -> Option<i32> {
        self.user_id().map(|i| i as i32)
    }

    // TODO(bm) This should be u32
    fn group_id() -> Option<i32> {
        self.group_id().map(|i| i as i32)
    }

    // TODO(bm) This should be u32
    fn effective_user_id() -> Option<i32> {
        self.effective_user_id().map(|i| i as i32)
    }

    // TODO(bm) This should be u32
    fn effective_group_id() -> Option<i32> {
        self.effective_group_id().map(|i| i as i32)
    }

    // TODO(bm) This should be lldb_pid_t
    fn parent_process_id() -> i32 {
        self.parent_process_id() as i32
    }

    fn triple() -> &str {
        self.triple()
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::path::Path;

use gltf;
use gltf_importer;

use collision::{Aabb, Union};

use controls::CameraParams;
use render::math::*;
use render::mesh::Mesh;
use render::Root;
use render::camera::Camera;

pub struct Node {
    pub index: usize, // glTF index
    pub children: Vec<usize>,
    pub matrix: Matrix4,
    pub mesh: Option<Rc<Mesh>>,
    pub rotation: Quaternion,
    pub scale: Vector3,
    pub translation: Vector3,
    // TODO: weights
    // weights_id: usize,
    pub camera: Option<Camera>,
    pub name: Option<String>,

    pub final_transform: Matrix4, // including parent transforms
    pub bounds: Aabb3,
}

impl Node {
    // TODO!: refactor transformations using mint and non-deprecated functions
    #[allow(deprecated)]
    pub fn from_gltf(
        g_node: &gltf::Node,
        root: &mut Root,
        buffers: &gltf_importer::Buffers,
        base_path: &Path
    ) -> Node {
        // convert matrix in 3 steps due to type system weirdness
        let matrix = &g_node.matrix();
        let matrix: &Matrix4 = matrix.into();
        let matrix = *matrix;

        let r = &g_node.rotation();
        let rotation = Quaternion::new(r[3], r[0], r[1], r[2]); // NOTE: different element order!

        let mut mesh = None;
        if let Some(g_mesh) = g_node.mesh() {
            if let Some(existing_mesh) = root.meshes.iter().find(|mesh| (***mesh).index == g_mesh.index()) {
                mesh = Some(Rc::clone(existing_mesh));
            }

            if mesh.is_none() { // not using else due to borrow-checking madness
                mesh = Some(Rc::new(Mesh::from_gltf(&g_mesh, root, buffers, base_path)));
                root.meshes.push(mesh.clone().unwrap());
            }
        }
        let children: Vec<_> = g_node.children()
                .map(|g_node| g_node.index())
                .collect();

        Node {
            index: g_node.index(),
            children,
            matrix,
            mesh,
            rotation,
            scale: g_node.scale().into(),
            translation: g_node.translation().into(),
            camera: g_node.camera().as_ref().map(Camera::from_gltf),
            name: g_node.name().map(|s| s.into()),

            final_transform: Matrix4::identity(),

            bounds: Aabb3::zero(),
        }
    }

    pub fn update_transform(&mut self, root: &mut Root, parent_transform: &Matrix4) {
        self.final_transform = *parent_transform;

        if !self.matrix.is_identity() {
            self.final_transform = self.final_transform * self.matrix;
        }
        else {
            // TODO?: detect if all default and set None? does NOT happen for any sample model
            self.final_transform = self.final_transform *
                Matrix4::from_translation(self.translation) *
                Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z) *
                Matrix4::from(self.rotation);
        }

        for node_id in &self.children {
            let node = root.unsafe_get_node_mut(*node_id);
            node.update_transform(root, &self.final_transform);
        }
    }

    /// Should be called after update_transforms
    pub fn update_bounds(&mut self, root: &mut Root) {
        self.bounds = Aabb3::zero();
        if let Some(ref mesh) = self.mesh {
            self.bounds = mesh.bounds
                .transform(&self.final_transform);
        }
        else if self.children.is_empty() {
            // Cameras (others?) have neither mesh nor children. Their position is the origin
            // TODO!: are there other cases? Do bounds matter for cameras?
            self.bounds = Aabb3::zero();
            self.bounds = self.bounds.transform(&self.final_transform);
        }
        else {
            for node_id in &self.children {
                let node = root.unsafe_get_node_mut(*node_id);
                node.update_bounds(root);
                self.bounds = self.bounds.union(&node.bounds);
            }
        }
    }

    pub fn draw(&mut self, root: &mut Root, cam_params: &CameraParams) {
        if let Some(ref mesh) = self.mesh {
            let mvp_matrix = cam_params.projection_matrix * cam_params.view_matrix * self.final_transform;

            (*mesh).draw(&self.final_transform, &mvp_matrix, &cam_params.position);
        }
        for node_id in &self.children {
            let node = root.unsafe_get_node_mut(*node_id);
            node.draw(root, cam_params);
        }
    }
}
<commit_msg>exclude camera node bounds in scene bounds<commit_after>use std::rc::Rc;
use std::path::Path;

use gltf;
use gltf_importer;

use collision::{Aabb, Union};

use controls::CameraParams;
use render::math::*;
use render::mesh::Mesh;
use render::Root;
use render::camera::Camera;

pub struct Node {
    pub index: usize, // glTF index
    pub children: Vec<usize>,
    pub matrix: Matrix4,
    pub mesh: Option<Rc<Mesh>>,
    pub rotation: Quaternion,
    pub scale: Vector3,
    pub translation: Vector3,
    // TODO: weights
    // weights_id: usize,
    pub camera: Option<Camera>,
    pub name: Option<String>,

    pub final_transform: Matrix4, // including parent transforms
    pub bounds: Aabb3,
}

impl Node {
    // TODO!: refactor transformations using mint and non-deprecated functions
    #[allow(deprecated)]
    pub fn from_gltf(
        g_node: &gltf::Node,
        root: &mut Root,
        buffers: &gltf_importer::Buffers,
        base_path: &Path
    ) -> Node {
        // convert matrix in 3 steps due to type system weirdness
        let matrix = &g_node.matrix();
        let matrix: &Matrix4 = matrix.into();
        let matrix = *matrix;

        let r = &g_node.rotation();
        let rotation = Quaternion::new(r[3], r[0], r[1], r[2]); // NOTE: different element order!

        let mut mesh = None;
        if let Some(g_mesh) = g_node.mesh() {
            if let Some(existing_mesh) = root.meshes.iter().find(|mesh| (***mesh).index == g_mesh.index()) {
                mesh = Some(Rc::clone(existing_mesh));
            }

            if mesh.is_none() { // not using else due to borrow-checking madness
                mesh = Some(Rc::new(Mesh::from_gltf(&g_mesh, root, buffers, base_path)));
                root.meshes.push(mesh.clone().unwrap());
            }
        }
        let children: Vec<_> = g_node.children()
                .map(|g_node| g_node.index())
                .collect();

        Node {
            index: g_node.index(),
            children,
            matrix,
            mesh,
            rotation,
            scale: g_node.scale().into(),
            translation: g_node.translation().into(),
            camera: g_node.camera().as_ref().map(Camera::from_gltf),
            name: g_node.name().map(|s| s.into()),

            final_transform: Matrix4::identity(),

            bounds: Aabb3::zero(),
        }
    }

    pub fn update_transform(&mut self, root: &mut Root, parent_transform: &Matrix4) {
        self.final_transform = *parent_transform;

        if !self.matrix.is_identity() {
            self.final_transform = self.final_transform * self.matrix;
        }
        else {
            // TODO?: detect if all default and set None? does NOT happen for any sample model
            self.final_transform = self.final_transform *
                Matrix4::from_translation(self.translation) *
                Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z) *
                Matrix4::from(self.rotation);
        }

        for node_id in &self.children {
            let node = root.unsafe_get_node_mut(*node_id);
            node.update_transform(root, &self.final_transform);
        }
    }

    /// Should be called after update_transforms
    pub fn update_bounds(&mut self, root: &mut Root) {
        self.bounds = Aabb3::zero();
        if let Some(ref mesh) = self.mesh {
            self.bounds = mesh.bounds
                .transform(&self.final_transform);
        }
        else if self.camera.is_some() {
            // Skip updating bounds for Cameras, since they don't have bounds.
        }
        else if self.children.is_empty() {
            // Cameras (others?) have neither mesh nor children. Their position is the origin
            // TODO!: are there other cases? Do bounds matter for cameras?
            self.bounds = Aabb3::zero();
            self.bounds = self.bounds.transform(&self.final_transform);
        }
        else {
            for node_id in &self.children {
                let node = root.unsafe_get_node_mut(*node_id);
                node.update_bounds(root);
                self.bounds = self.bounds.union(&node.bounds);
            }
        }
    }

    pub fn draw(&mut self, root: &mut Root, cam_params: &CameraParams) {
        if let Some(ref mesh) = self.mesh {
            let mvp_matrix = cam_params.projection_matrix * cam_params.view_matrix * self.final_transform;

            (*mesh).draw(&self.final_transform, &mvp_matrix, &cam_params.position);
        }
        for node_id in &self.children {
            let node = root.unsafe_get_node_mut(*node_id);
            node.draw(root, cam_params);
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        self.print_header(&format!("{} - {} [{}/{}]",
                             item.title,
                             title,
                             item.page,
                             item.max_page));
        self.print_body(2, &item);
    }

    fn print_header(&mut self, text: &str) {
        let title_len = jks_len(text);
        let padding = (if self.rustbox.width() >= title_len {
            self.rustbox.width() - title_len
        } else {
            0
        }) / 2;

        let header_bottom = seq_str_gen(0, self.rustbox.width(), "─", "");

        clearline(&self.rustbox, self.rustbox.width(), 0, 0);
        self.rustbox.print(padding,
                      0,
                      rustbox::RB_BOLD,
                      Color::White,
                      Color::Black,
                      text);
        self.rustbox.print(0,
                      1,
                      rustbox::RB_BOLD,
                      Color::Yellow,
                      Color::Black,
                      &header_bottom);
    }

    pub fn print_body(&mut self,offset_y: usize, item: &ShowItem) {
        let width = self.body_width();
        let rows = self.body_height();
        let rustbox = self.rustbox;
        let scrollY = self.scrollY;

        let mut y = offset_y;
        let replier_max_width = 14;
        let time_max_width = 5;
        let now = Local::now();

        let separator_width = if rustbox.width() >= 2 {
            rustbox.width() - 2
        } else {
            0
        };
        let separator_padding_width = if rustbox.width() > separator_width {
            rustbox.width() - separator_width
        } else {
            0
        } / 2;

        let separator_padding = seq_str_gen(0, separator_padding_width, " ", "");

        let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

        for (i, reply) in item.replies.iter().take(rows).enumerate() {

            let mut m = print_reply(&reply.body, 0, scrollY, y, &rustbox);

            if scrollY + 1 < y + m {

                let replier_name = reply.username.clone();

                let published_at = reply.published_at.clone();

                let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
                    Ok(v) => v,
                    Err(e) => now,
                };
                let time = published_at_format(&(now - published_at_dt));

                let separator_top = make_separator_top(separator_width,
                                                       &separator_padding,
                                                       replier_max_width,
                                                       &replier_name,
                                                       time_max_width,
                                                       &time);

                rustbox.print(0,
                              m + y - scrollY,
                              rustbox::RB_NORMAL,
                              Color::Green,
                              Color::Black,
                              &separator_top);
            }
            m += 1;

            if scrollY + 1 < y + m {
                rustbox.print(0,
                              m + y - scrollY,
                              rustbox::RB_NORMAL,
                              Color::Green,
                              Color::Black,
                              &separator_bottom);
            }
            m += 1;
            y += m;
        }
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
    fn print_default(&self, x: usize, y: usize, text: &str){
        self.rustbox.print(x,
                      y,
                      rustbox::RB_BOLD,
                      Color::White,
                      Color::Black,
                      text);
    }
}

fn print_default(rustbox: &rustbox::RustBox, x: usize, y: usize, s: String) {
    rustbox.print(0, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn print_reply(vec: &Vec<NodeType>,
               depth: usize,
               scrollY: usize,
               y: usize,
               rustbox: &rustbox::RustBox)
               -> usize {
    let padding = seq_str_gen(0, depth, "├─", "");
    let mut m = 0;
    let mut recursive_offset = 0;
    let mut total_y = 0;
    let mut line = String::new();

    // clean up lines (end)
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    // clean up lines (start)
    let vec3 = {
        let vec2_cloned = vec2.clone();
        let mut result: Vec<NodeType> = Vec::new();
        for (j, node) in vec2_cloned.enumerate() {
            let node2 = node.clone();
            let node3 = node.clone();
            match node2 {
                NodeType::Br(n) => {
                    if !result.is_empty() {
                        result.push(node3);
                    }
                }
                _ => { result.push(node3) }
            }
        }
        result.clone()
    };

    let mut is_first = true;
    for (j, node) in vec3.iter().enumerate() {
        total_y = y + m + recursive_offset;
        if scrollY + 1 < total_y {
            let node2 = node.clone();
            match node2 {
                NodeType::Text(n) => {
                    if n.data != "" {
                        line = format!("{}{}", line, n.data);
                    }
                }
                NodeType::Image(n) => {
                    if n.data != "" {
                        line = format!("{}[img {}]", line, n.data);
                    }
                }
                NodeType::BlockQuote(n) => {
                    recursive_offset += print_reply(&n.data, depth + 1, scrollY, total_y, &rustbox);
                    is_first = false;
                }
                NodeType::Br(n) => {
                    if !line.is_empty() {
                        print_default(rustbox,
                                      0,
                                      total_y - scrollY,
                                      format!(" {}{}", padding, line));
                        line = String::new();
                        is_first = false;
                    }

                    // prevent first line empty
                    if !is_first {
                        m += 1;
                    }

                }
            }
        }
    }

    if !line.is_empty() {
        total_y = y + m + recursive_offset;
        print_default(rustbox,
                      0,
                      total_y - scrollY,
                      format!(" {}{}  ", padding, line));
        line = String::new();
        m += 1;
    }

    m + recursive_offset
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = seq_str_gen(0, replier_name_left_spacing_width, "─", "");
    let replier_name_right_spacing = seq_str_gen(0, replier_name_right_spacing_width, "─", "");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = seq_str_gen(0, time_left_spacing_width, "─", "");
    let time_right_spacing = seq_str_gen(0, time_right_spacing_width, "─", "");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = seq_str_gen(0, separator_top_middle_width, " ", "");
    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = seq_str_gen(0, separator_bottom_middle_width, "─", "");

    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}

fn seq_str_gen(start: usize, end: usize, sym: &str, join_sym: &str) -> String {
    (start..end).map(|_|sym.clone()).collect::<Vec<_>>().join(&join_sym)
}
<commit_msg>show - reformated<commit_after>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        self.print_header(&format!("{} - {} [{}/{}]",
                                   item.title,
                                   title,
                                   item.page,
                                   item.max_page));
        self.print_body(2, &item);
    }

    fn print_header(&mut self, text: &str) {
        let title_len = jks_len(text);
        let padding = (if self.rustbox.width() >= title_len {
            self.rustbox.width() - title_len
        } else {
            0
        }) / 2;

        let header_bottom = seq_str_gen(0, self.rustbox.width(), "─", "");

        clearline(&self.rustbox, self.rustbox.width(), 0, 0);
        self.rustbox.print(padding,
                           0,
                           rustbox::RB_BOLD,
                           Color::White,
                           Color::Black,
                           text);
        self.rustbox.print(0,
                           1,
                           rustbox::RB_BOLD,
                           Color::Yellow,
                           Color::Black,
                           &header_bottom);
    }

    pub fn print_body(&mut self, offset_y: usize, item: &ShowItem) {
        let width = self.body_width();
        let rows = self.body_height();
        let rustbox = self.rustbox;
        let scrollY = self.scrollY;

        let mut y = offset_y;
        let replier_max_width = 14;
        let time_max_width = 5;
        let now = Local::now();

        let separator_width = if rustbox.width() >= 2 {
            rustbox.width() - 2
        } else {
            0
        };
        let separator_padding_width = if rustbox.width() > separator_width {
            rustbox.width() - separator_width
        } else {
            0
        } / 2;

        let separator_padding = seq_str_gen(0, separator_padding_width, " ", "");

        let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

        for (i, reply) in item.replies.iter().take(rows).enumerate() {

            let mut m = print_reply(&reply.body, 0, scrollY, y, &rustbox);

            if scrollY + 1 < y + m {

                let replier_name = reply.username.clone();

                let published_at = reply.published_at.clone();

                let published_at_dt = match Local.datetime_from_str(&published_at,
                                                                    "%d/%m/%Y %H:%M") {
                    Ok(v) => v,
                    Err(e) => now,
                };
                let time = published_at_format(&(now - published_at_dt));

                let separator_top = make_separator_top(separator_width,
                                                       &separator_padding,
                                                       replier_max_width,
                                                       &replier_name,
                                                       time_max_width,
                                                       &time);

                rustbox.print(0,
                              m + y - scrollY,
                              rustbox::RB_NORMAL,
                              Color::Green,
                              Color::Black,
                              &separator_top);
            }
            m += 1;

            if scrollY + 1 < y + m {
                rustbox.print(0,
                              m + y - scrollY,
                              rustbox::RB_NORMAL,
                              Color::Green,
                              Color::Black,
                              &separator_bottom);
            }
            m += 1;
            y += m;
        }
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
    fn print_default(&self, x: usize, y: usize, text: &str) {
        self.rustbox.print(x, y, rustbox::RB_BOLD, Color::White, Color::Black, text);
    }
}

fn print_default(rustbox: &rustbox::RustBox, x: usize, y: usize, s: String) {
    rustbox.print(0, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn print_reply(vec: &Vec<NodeType>,
               depth: usize,
               scrollY: usize,
               y: usize,
               rustbox: &rustbox::RustBox)
               -> usize {
    let padding = seq_str_gen(0, depth, "├─", "");
    let mut m = 0;
    let mut recursive_offset = 0;
    let mut total_y = 0;
    let mut line = String::new();

    // clean up lines (end)
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    // clean up lines (start)
    let vec3 = {
        let vec2_cloned = vec2.clone();
        let mut result: Vec<NodeType> = Vec::new();
        for (j, node) in vec2_cloned.enumerate() {
            let node2 = node.clone();
            let node3 = node.clone();
            match node2 {
                NodeType::Br(n) => {
                    if !result.is_empty() {
                        result.push(node3);
                    }
                }
                _ => result.push(node3),
            }
        }
        result.clone()
    };

    let mut is_first = true;
    for (j, node) in vec3.iter().enumerate() {
        total_y = y + m + recursive_offset;
        if scrollY + 1 < total_y {
            let node2 = node.clone();
            match node2 {
                NodeType::Text(n) => {
                    if n.data != "" {
                        line = format!("{}{}", line, n.data);
                    }
                }
                NodeType::Image(n) => {
                    if n.data != "" {
                        line = format!("{}[img {}]", line, n.data);
                    }
                }
                NodeType::BlockQuote(n) => {
                    recursive_offset += print_reply(&n.data, depth + 1, scrollY, total_y, &rustbox);
                    is_first = false;
                }
                NodeType::Br(n) => {
                    if !line.is_empty() {
                        print_default(rustbox,
                                      0,
                                      total_y - scrollY,
                                      format!(" {}{}", padding, line));
                        line = String::new();
                        is_first = false;
                    }

                    // prevent first line empty
                    if !is_first {
                        m += 1;
                    }

                }
            }
        }
    }

    if !line.is_empty() {
        total_y = y + m + recursive_offset;
        print_default(rustbox,
                      0,
                      total_y - scrollY,
                      format!(" {}{}  ", padding, line));
        line = String::new();
        m += 1;
    }

    m + recursive_offset
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = seq_str_gen(0, replier_name_left_spacing_width, "─", "");
    let replier_name_right_spacing = seq_str_gen(0, replier_name_right_spacing_width, "─", "");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = seq_str_gen(0, time_left_spacing_width, "─", "");
    let time_right_spacing = seq_str_gen(0, time_right_spacing_width, "─", "");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = seq_str_gen(0, separator_top_middle_width, " ", "");
    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = seq_str_gen(0, separator_bottom_middle_width, "─", "");

    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}

fn seq_str_gen(start: usize, end: usize, sym: &str, join_sym: &str) -> String {
    (start..end).map(|_| sym.clone()).collect::<Vec<_>>().join(&join_sym)
}
<|endoftext|>


<commit_before>//! SCCS-style delta weave stores.

use crate::{
    node,
    store::{Store, StoreTags, StoreVersion, StoreWriter, TempCleaner, TempFile, TempLoader, Version},
    Result, SureNode, SureTree,
};
use failure::format_err;
use log::warn;
use std::{
    env,
    fs::{self, File},
    io::{self, BufRead, BufReader, Read, BufWriter, Write},
    path::{Path, PathBuf},
    sync::mpsc::{self, Receiver, SyncSender},
    thread::{self, JoinHandle},
};
use weave::{self, DeltaWriter, NamingConvention, NewWeave, NullSink, Parser, SimpleNaming, Sink};

pub struct WeaveStore {
    naming: SimpleNaming,
}

impl WeaveStore {
    pub fn new<P: AsRef<Path>>(path: P, base: &str, compressed: bool) -> WeaveStore {
        WeaveStore {
            naming: SimpleNaming::new(path, base, "dat", compressed),
        }
    }
}

impl Store for WeaveStore {
    fn write_new(&self, tree: &SureTree, tags: &StoreTags) -> Result<()> {
        let itags = tags.iter().map(|(k, v)| (k.as_ref(), v.as_ref()));
        match weave::get_last_delta(&self.naming) {
            Ok(base) => {
                let mut wv = DeltaWriter::new(&self.naming, itags, base)?;
                tree.save_to(&mut wv)?;
                wv.close()?;
                Ok(())
            }
            Err(_) => {
                // Create a new weave file.
                let mut wv = NewWeave::new(&self.naming, itags)?;

                tree.save_to(&mut wv)?;

                wv.close()?;
                Ok(())
            }
        }
    }

    fn load(&self, version: Version) -> Result<SureTree> {
        let last = weave::get_last_delta(&self.naming)?;
        let last = match version {
            Version::Latest => last,
            Version::Prior => last - 1,
            Version::Tagged(vers) => vers.parse()?,
        };

        let child_naming = self.naming.clone();
        let (sender, receiver) = mpsc::sync_channel(32);
        let child = thread::spawn(move || {
            if let Err(err) = read_parse(&child_naming, last, sender.clone()) {
                // Attempt to send the last error over.
                if let Err(inner) = sender.send(Some(Err(err))) {
                    warn!("Error sending error on channel {:?}", inner);
                }
            }
        });
        let rd = ReadReceiver(receiver);
        let tree = SureTree::load_from(rd);
        match child.join() {
            Ok(()) => (),
            Err(e) => warn!("Problem joining child thread: {:?}", e),
        }
        tree
    }

    fn get_versions(&self) -> Result<Vec<StoreVersion>> {
        let header = Parser::new(&self.naming, NullSink, 1)?.into_header();
        let mut versions: Vec<_> = header
            .deltas
            .iter()
            .map(|v| StoreVersion {
                name: v.name.clone(),
                time: v.time,
                version: Version::Tagged(v.number.to_string()),
            }).collect();
        versions.reverse();
        Ok(versions)
    }

    fn load_iter(&self, version: Version) -> Result<Box<dyn Iterator<Item = Result<SureNode>>>> {
        let last = weave::get_last_delta(&self.naming)?;
        let last = match version {
            Version::Latest => last,
            Version::Prior => last - 1,
            Version::Tagged(vers) => vers.parse()?,
        };

        let child_naming = self.naming.clone();
        let (sender, receiver) = mpsc::sync_channel(32);
        let child = thread::spawn(move || {
            if let Err(err) = read_parse(&child_naming, last, sender.clone()) {
                // Attempt to send the last error over.
                if let Err(inner) = sender.send(Some(Err(err))) {
                    warn!("Error sending error on channel {:?}", inner);
                }
            }
        });

        fixed(&receiver, b"asure-2.0")?;
        fixed(&receiver, b"-----")?;

        Ok(Box::new(WeaveIter {
            _child: child,
            receiver: receiver,
        }))
    }

    fn make_temp(&self) -> Result<Box<dyn TempFile + '_>> {
        // TODO: Fixup naming to allow uncompressed writes.
        let (path, file) = self.naming.temp_file()?;
        let cpath = path.clone();
        Ok(Box::new(WeaveTemp {
            parent: self,
            path: path,
            file: BufWriter::new(file),
            cleaner: FileClean(cpath),
        }))
    }

    fn make_new(&self, tags: &StoreTags) -> Result<Box<dyn StoreWriter + '_>> {
        let itags = tags.iter().map(|(k, v)| (k.as_ref(), v.as_ref()));
        match weave::get_last_delta(&self.naming) {
            Ok(base) => {
                let wv = DeltaWriter::new(&self.naming, itags, base)?;
                Ok(Box::new(NewWeaveDelta { weave: wv }))
            }
            Err(_) => {
                // Create a new weave file.
                let wv = NewWeave::new(&self.naming, itags)?;
                Ok(Box::new(NewWeaveWriter { weave: wv }))
            }
        }
    }
}

struct WeaveTemp<'a> {
    parent: &'a WeaveStore,
    path: PathBuf,
    file: BufWriter<File>,
    cleaner: FileClean,
}

impl<'a> TempFile<'a> for WeaveTemp<'a> {
    fn into_loader(self: Box<Self>) -> Result<Box<dyn TempLoader + 'a>> {
        drop(self.file);
        Ok(Box::new(WeaveTempLoader {
            _parent: self.parent,
            path: self.path,
            cleaner: self.cleaner,
        }))
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

impl<'a> Write for WeaveTemp<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

pub struct WeaveTempLoader<'a> {
    _parent: &'a WeaveStore,
    path: PathBuf,
    cleaner: FileClean,
}

impl<'a> TempLoader for WeaveTempLoader<'a> {
    fn new_loader(&self) -> Result<Box<dyn BufRead>> {
        let read = BufReader::new(File::open(&self.path)?);
        Ok(Box::new(read))
    }

    fn path_ref(&self) -> &Path {
        &self.path
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

pub struct NewWeaveWriter<'a> {
    weave: NewWeave<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveWriter<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct NewWeaveDelta<'a> {
    weave: DeltaWriter<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveDelta<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveDelta<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct WeaveIter {
    // This field doesn't need to be referenced, just held onto, the Drop
    // implementation for it is sufficient cleanup.
    _child: JoinHandle<()>,
    receiver: Receiver<Option<Result<String>>>,
}

impl Iterator for WeaveIter {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        let line = match self.receiver.recv() {
            Ok(None) => return None,
            Ok(Some(Err(e))) => return Some(Err(e)),
            Ok(Some(Ok(line))) => line,
            Err(e) => return Some(Err(e.into())),
        };
        let line = line.as_bytes();

        match line[0] {
            b'd' => {
                let (dname, datts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::Enter{name: dname, atts: datts}))
            }
            b'f' => {
                let (fname, fatts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::File{name: fname, atts: fatts}))
            }
            b'-' => Some(Ok(SureNode::Sep)),
            b'u' => Some(Ok(SureNode::Leave)),
            ch => Some(Err(format_err!("Invalid surefile line start: {:?}", ch)))
        }
    }
}

// Parse a given delta, emitting the lines to the given channel.  Finishes with Ok(()), or an error
// if something goes wrong.
fn read_parse(
    naming: &dyn NamingConvention,
    delta: usize,
    chan: SyncSender<Option<Result<String>>>,
) -> Result<()> {
    let mut parser = Parser::new(naming, ReadSync { chan: chan }, delta)?;
    parser.parse_to(0)?;
    let sink = parser.get_sink();
    match sink.borrow().chan.send(None) {
        Ok(()) => (),
        Err(e) => return Err(format_err!("chan send error: {:?}", e)),
    }
    Ok(())
}

/// Try reading a specific line from the given channel.  Returns Err if the
/// line didn't match, or something went wrong with the read.
fn fixed(recv: &Receiver<Option<Result<String>>>, expect: &[u8]) -> Result<()> {
    match recv.recv() {
        Ok(Some(Ok(line))) => {
            if line.as_bytes() == expect {
                Ok(())
            } else {
                Err(format_err!("Unexpect line from channel: {:?} expect {:?}", line, expect))
            }
        }
        Ok(Some(Err(e))) => Err(format_err!("Error reading suredata: {:?}", e)),
        Ok(None) => Err(format_err!("Unexpected eof reading suredata")),
        Err(e) => Err(e.into()),
    }
}

struct ReadSync {
    chan: SyncSender<Option<Result<String>>>,
}

impl Sink for ReadSync {
    fn plain(&mut self, text: &str, keep: bool) -> weave::Result<()> {
        if keep {
            match self.chan.send(Some(Ok(text.to_string()))) {
                Ok(()) => Ok(()),
                Err(e) => Err(format_err!("chan send error: {:?}", e)),
            }
        } else {
            Ok(())
        }
    }
}

struct ReadReceiver(Receiver<Option<Result<String>>>);

impl Read for ReadReceiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let line = match self.0.recv() {
            Ok(line) => line,
            Err(e) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("channel error: {:?}", e),
                ))
            }
        };
        let line = match line {
            None => return Ok(0),
            Some(Ok(line)) => line,
            Some(Err(e)) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("channel error: {:?}", e),
                ))
            }
        };
        let chars = line.as_bytes();
        if chars.len() + 1 > buf.len() {
            panic!("TODO: Handle line longer than buffer");
        }
        buf[..chars.len()].copy_from_slice(chars);
        buf[chars.len()] = b'\n';
        Ok(chars.len() + 1)
    }
}

/// Own a PathBuf, and delete this file on drop.  This is in its own type
/// for two reason. 1. I makes it easy to have cleaning in multiple types,
/// passing ownership between them, and 2.  It prevents the need for those
/// types to implement drop, which prevents moves out of the fields.
struct FileClean(PathBuf);

impl Drop for FileClean {
    fn drop(&mut self) {
        if env::var_os("RSURE_KEEP").is_none() {
            let _ = fs::remove_file(&self.0);
        }
    }
}

impl TempCleaner for FileClean{}
<commit_msg>Change to crossbeam for weave read channel<commit_after>//! SCCS-style delta weave stores.

use crate::{
    node,
    store::{Store, StoreTags, StoreVersion, StoreWriter, TempCleaner, TempFile, TempLoader, Version},
    Result, SureNode, SureTree,
};
use crossbeam::{
    channel::{bounded, Receiver, Sender},
};
use failure::format_err;
use log::warn;
use std::{
    env,
    fs::{self, File},
    io::{self, BufRead, BufReader, Read, BufWriter, Write},
    path::{Path, PathBuf},
    thread::{self, JoinHandle},
};
use weave::{self, DeltaWriter, NamingConvention, NewWeave, NullSink, Parser, SimpleNaming, Sink};

pub struct WeaveStore {
    naming: SimpleNaming,
}

impl WeaveStore {
    pub fn new<P: AsRef<Path>>(path: P, base: &str, compressed: bool) -> WeaveStore {
        WeaveStore {
            naming: SimpleNaming::new(path, base, "dat", compressed),
        }
    }
}

impl Store for WeaveStore {
    fn write_new(&self, tree: &SureTree, tags: &StoreTags) -> Result<()> {
        let itags = tags.iter().map(|(k, v)| (k.as_ref(), v.as_ref()));
        match weave::get_last_delta(&self.naming) {
            Ok(base) => {
                let mut wv = DeltaWriter::new(&self.naming, itags, base)?;
                tree.save_to(&mut wv)?;
                wv.close()?;
                Ok(())
            }
            Err(_) => {
                // Create a new weave file.
                let mut wv = NewWeave::new(&self.naming, itags)?;

                tree.save_to(&mut wv)?;

                wv.close()?;
                Ok(())
            }
        }
    }

    fn load(&self, version: Version) -> Result<SureTree> {
        let last = weave::get_last_delta(&self.naming)?;
        let last = match version {
            Version::Latest => last,
            Version::Prior => last - 1,
            Version::Tagged(vers) => vers.parse()?,
        };

        let child_naming = self.naming.clone();
        let (sender, receiver) = bounded(32);
        let child = thread::spawn(move || {
            if let Err(err) = read_parse(&child_naming, last, sender.clone()) {
                // Attempt to send the last error over.
                if let Err(inner) = sender.send(Some(Err(err))) {
                    warn!("Error sending error on channel {:?}", inner);
                }
            }
        });
        let rd = ReadReceiver(receiver);
        let tree = SureTree::load_from(rd);
        match child.join() {
            Ok(()) => (),
            Err(e) => warn!("Problem joining child thread: {:?}", e),
        }
        tree
    }

    fn get_versions(&self) -> Result<Vec<StoreVersion>> {
        let header = Parser::new(&self.naming, NullSink, 1)?.into_header();
        let mut versions: Vec<_> = header
            .deltas
            .iter()
            .map(|v| StoreVersion {
                name: v.name.clone(),
                time: v.time,
                version: Version::Tagged(v.number.to_string()),
            }).collect();
        versions.reverse();
        Ok(versions)
    }

    fn load_iter(&self, version: Version) -> Result<Box<dyn Iterator<Item = Result<SureNode>>>> {
        let last = weave::get_last_delta(&self.naming)?;
        let last = match version {
            Version::Latest => last,
            Version::Prior => last - 1,
            Version::Tagged(vers) => vers.parse()?,
        };

        let child_naming = self.naming.clone();
        let (sender, receiver) = bounded(32);
        let child = thread::spawn(move || {
            if let Err(err) = read_parse(&child_naming, last, sender.clone()) {
                // Attempt to send the last error over.
                if let Err(inner) = sender.send(Some(Err(err))) {
                    warn!("Error sending error on channel {:?}", inner);
                }
            }
        });

        fixed(&receiver, b"asure-2.0")?;
        fixed(&receiver, b"-----")?;

        Ok(Box::new(WeaveIter {
            _child: child,
            receiver: receiver,
        }))
    }

    fn make_temp(&self) -> Result<Box<dyn TempFile + '_>> {
        // TODO: Fixup naming to allow uncompressed writes.
        let (path, file) = self.naming.temp_file()?;
        let cpath = path.clone();
        Ok(Box::new(WeaveTemp {
            parent: self,
            path: path,
            file: BufWriter::new(file),
            cleaner: FileClean(cpath),
        }))
    }

    fn make_new(&self, tags: &StoreTags) -> Result<Box<dyn StoreWriter + '_>> {
        let itags = tags.iter().map(|(k, v)| (k.as_ref(), v.as_ref()));
        match weave::get_last_delta(&self.naming) {
            Ok(base) => {
                let wv = DeltaWriter::new(&self.naming, itags, base)?;
                Ok(Box::new(NewWeaveDelta { weave: wv }))
            }
            Err(_) => {
                // Create a new weave file.
                let wv = NewWeave::new(&self.naming, itags)?;
                Ok(Box::new(NewWeaveWriter { weave: wv }))
            }
        }
    }
}

struct WeaveTemp<'a> {
    parent: &'a WeaveStore,
    path: PathBuf,
    file: BufWriter<File>,
    cleaner: FileClean,
}

impl<'a> TempFile<'a> for WeaveTemp<'a> {
    fn into_loader(self: Box<Self>) -> Result<Box<dyn TempLoader + 'a>> {
        drop(self.file);
        Ok(Box::new(WeaveTempLoader {
            _parent: self.parent,
            path: self.path,
            cleaner: self.cleaner,
        }))
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

impl<'a> Write for WeaveTemp<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file.write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

pub struct WeaveTempLoader<'a> {
    _parent: &'a WeaveStore,
    path: PathBuf,
    cleaner: FileClean,
}

impl<'a> TempLoader for WeaveTempLoader<'a> {
    fn new_loader(&self) -> Result<Box<dyn BufRead>> {
        let read = BufReader::new(File::open(&self.path)?);
        Ok(Box::new(read))
    }

    fn path_ref(&self) -> &Path {
        &self.path
    }

    fn into_cleaner(self: Box<Self>) -> Result<Box<dyn TempCleaner>> {
        Ok(Box::new(self.cleaner))
    }
}

pub struct NewWeaveWriter<'a> {
    weave: NewWeave<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveWriter<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct NewWeaveDelta<'a> {
    weave: DeltaWriter<'a>,
}

impl<'a> StoreWriter<'a> for NewWeaveDelta<'a> {
    fn commit(self: Box<Self>) -> Result<()> {
        self.weave.close()
    }
}

impl<'a> Write for NewWeaveDelta<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.weave.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.weave.flush()
    }
}

pub struct WeaveIter {
    // This field doesn't need to be referenced, just held onto, the Drop
    // implementation for it is sufficient cleanup.
    _child: JoinHandle<()>,
    receiver: Receiver<Option<Result<String>>>,
}

impl Iterator for WeaveIter {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        let line = match self.receiver.recv() {
            Ok(None) => return None,
            Ok(Some(Err(e))) => return Some(Err(e)),
            Ok(Some(Ok(line))) => line,
            Err(e) => return Some(Err(e.into())),
        };
        let line = line.as_bytes();

        match line[0] {
            b'd' => {
                let (dname, datts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::Enter{name: dname, atts: datts}))
            }
            b'f' => {
                let (fname, fatts) = node::decode_entity(&line[1..]);
                Some(Ok(SureNode::File{name: fname, atts: fatts}))
            }
            b'-' => Some(Ok(SureNode::Sep)),
            b'u' => Some(Ok(SureNode::Leave)),
            ch => Some(Err(format_err!("Invalid surefile line start: {:?}", ch)))
        }
    }
}

// Parse a given delta, emitting the lines to the given channel.  Finishes with Ok(()), or an error
// if something goes wrong.
fn read_parse(
    naming: &dyn NamingConvention,
    delta: usize,
    chan: Sender<Option<Result<String>>>,
) -> Result<()> {
    let mut parser = Parser::new(naming, ReadSync { chan: chan }, delta)?;
    parser.parse_to(0)?;
    let sink = parser.get_sink();
    match sink.borrow().chan.send(None) {
        Ok(()) => (),
        Err(e) => return Err(format_err!("chan send error: {:?}", e)),
    }
    Ok(())
}

/// Try reading a specific line from the given channel.  Returns Err if the
/// line didn't match, or something went wrong with the read.
fn fixed(recv: &Receiver<Option<Result<String>>>, expect: &[u8]) -> Result<()> {
    match recv.recv() {
        Ok(Some(Ok(line))) => {
            if line.as_bytes() == expect {
                Ok(())
            } else {
                Err(format_err!("Unexpect line from channel: {:?} expect {:?}", line, expect))
            }
        }
        Ok(Some(Err(e))) => Err(format_err!("Error reading suredata: {:?}", e)),
        Ok(None) => Err(format_err!("Unexpected eof reading suredata")),
        Err(e) => Err(e.into()),
    }
}

struct ReadSync {
    chan: Sender<Option<Result<String>>>,
}

impl Sink for ReadSync {
    fn plain(&mut self, text: &str, keep: bool) -> weave::Result<()> {
        if keep {
            match self.chan.send(Some(Ok(text.to_string()))) {
                Ok(()) => Ok(()),
                Err(e) => Err(format_err!("chan send error: {:?}", e)),
            }
        } else {
            Ok(())
        }
    }
}

struct ReadReceiver(Receiver<Option<Result<String>>>);

impl Read for ReadReceiver {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let line = match self.0.recv() {
            Ok(line) => line,
            Err(e) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("channel error: {:?}", e),
                ))
            }
        };
        let line = match line {
            None => return Ok(0),
            Some(Ok(line)) => line,
            Some(Err(e)) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("channel error: {:?}", e),
                ))
            }
        };
        let chars = line.as_bytes();
        if chars.len() + 1 > buf.len() {
            panic!("TODO: Handle line longer than buffer");
        }
        buf[..chars.len()].copy_from_slice(chars);
        buf[chars.len()] = b'\n';
        Ok(chars.len() + 1)
    }
}

/// Own a PathBuf, and delete this file on drop.  This is in its own type
/// for two reason. 1. I makes it easy to have cleaning in multiple types,
/// passing ownership between them, and 2.  It prevents the need for those
/// types to implement drop, which prevents moves out of the fields.
struct FileClean(PathBuf);

impl Drop for FileClean {
    fn drop(&mut self) {
        if env::var_os("RSURE_KEEP").is_none() {
            let _ = fs::remove_file(&self.0);
        }
    }
}

impl TempCleaner for FileClean{}
<|endoftext|>