<commit_before>#![cfg_attr(feature = "unstable", feature(plugin))]
#![cfg_attr(feature = "unstable", plugin(clippy))]

/// POD (*plain old data*) type: scalar, fixed-size array or compound (struct).
/// May be arbitrarily nested.
#[derive(Clone, PartialEq, Debug)]
pub enum Type {
    /// 1-byte signed integer
    Int8,
    /// 2-byte signed integer
    Int16,
    /// 4-byte signed integer
    Int32,
    /// 8-byte signed integer
    Int64,
    /// pointer-sized signed integer
    ISize,
    /// 1-byte unsigned integer
    UInt8,
    /// 2-byte unsigned integer
    UInt16,
    /// 3-byte unsigned integer
    UInt32,
    /// 4-byte unsigned integer
    UInt64,
    /// pointer-sized unsigned integer
    USize,
    /// 4-byte floating-point number
    Float32,
    /// 8-byte floating-point number
    Float64,
    /// character type
    Char,
    /// 1-byte boolean type
    Bool,
    /// fixed-size array with POD elements
    Array(Box<Type>, usize),
    /// compound type whose fields are POD
    Compound(Vec<Field>, usize),
}

impl Type {
    /// Returns the total size of a type value in bytes.
    pub fn size(&self) -> usize {
        match *self {
            Type::Int8 | Type::UInt8 | Type::Bool => 1,
            Type::Int16 | Type::UInt16 => 2,
            Type::Int32 | Type::UInt32 | Type::Float32 | Type::Char => 4,
            Type::Int64 | Type::UInt64 | Type::Float64 => 8,
            Type::USize => ::std::mem::size_of::<usize>(),
            Type::ISize => ::std::mem::size_of::<isize>(),
            Type::Array(ref ty, num) => ty.size() * num,
            Type::Compound(_, size) => size,
        }
    }

    /// Returns true if the underlying type is a scalar.
    pub fn is_scalar(&self) -> bool {
        !self.is_array() && !self.is_compound()
    }

    /// Returns true if the underlying type is a fixed-size array.
    pub fn is_array(&self) -> bool {
        if let Type::Array(_, _) = *self { true } else { false }
    }

    /// Returns true if the underlying type is compound.
    pub fn is_compound(&self) -> bool {
        if let Type::Compound(_, _) = *self { true } else { false }
    }
}

/// Field of a compound type: type, name and offset from the beginning of the struct.
#[derive(Clone, PartialEq, Debug)]
pub struct Field {
    /// field value type
    pub ty: Type,
    /// field name
    pub name: String,
    /// offset to the beginning of the struct
    pub offset: usize,
}

impl Field {
    pub fn new<S, U>(ty: &Type, name: S, offset: U) -> Field
    where S: Into<String>, U: Into<usize> {
        Field {
            ty: ty.clone(),
            name: name.into(),
            offset: offset.into()
        }
    }
}

pub trait TypeInfo: Copy {
    /// Returns the runtime type information for the implementing type.
    fn type_info() -> Type;
}

macro_rules! impl_scalar {
    ($t:ty, $i:ident) => (
        impl $crate::TypeInfo for $t {
            #[inline(always)]
            fn type_info() -> $crate::Type {
                $crate::Type::$i
            }
        }
    )
}

// implement TypeInfo for built-in scalar types
impl_scalar!(i8, Int8);
impl_scalar!(i16, Int16);
impl_scalar!(i32, Int32);
impl_scalar!(i64, Int64);
impl_scalar!(isize, ISize);
impl_scalar!(u8, UInt8);
impl_scalar!(u16, UInt16);
impl_scalar!(u32, UInt32);
impl_scalar!(u64, UInt64);
impl_scalar!(usize, USize);
impl_scalar!(f32, Float32);
impl_scalar!(f64, Float64);
impl_scalar!(char, Char);
impl_scalar!(bool, Bool);

macro_rules! impl_array {
    ($($n:expr),*$(,)*) => {
        $(
            impl<T: $crate::TypeInfo> $crate::TypeInfo for [T; $n] {
                #[inline(always)]
                fn type_info() -> $crate::Type {
                    $crate::Type::Array(
                        Box::new(<T as $crate::TypeInfo>::type_info()),
                        $n
                    )
                }
            }
        )*
    };
}

// implement TypeInfo for fixed-size arrays of lengths 0..63
impl_array!(
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
);

#[macro_export]
macro_rules! def {
    // private struct, private fields
    ($($(#[$attr:meta])* struct $s:ident { $($i:ident: $t:ty),+$(,)* })*) => (
        $(
            #[allow(dead_code)]
            #[derive(Clone, Copy)]
            $(#[$attr])*
            struct $s { $($i: $t),* }
            def!(@impl $s { $($i: $t),+ } );
        )*
    );

    // public struct, private fields
    ($($(#[$attr:meta])* pub struct $s:ident { $($i:ident: $t:ty),+$(,)* })*) => (
        $(
            #[allow(dead_code)]
            #[derive(Clone, Copy)]
            $(#[$attr])*
            pub struct $s { $($i: $t),* }
            def!(@impl $s { $($i: $t),+ } );
        )*
    );

    // public struct, public fields
    ($($(#[$attr:meta])* pub struct $s:ident { $(pub $i:ident: $t:ty),+$(,)* })*) => (
        $(
            #[allow(dead_code)]
            #[derive(Clone, Copy)]
            $(#[$attr])*
            pub struct $s { pub $($i: $t),* }
            def!(@impl $s { $($i: $t),+ } );
        )*
    );

    // implement TypeInfo trait
    (@impl $s:ident { $($i:ident: $t:ty),+ }) => (
        impl $crate::TypeInfo for $s {
            fn type_info() -> $crate::Type {
                let base = 0usize as *const $s;
                $crate::Type::Compound(vec![$(
                    $crate::Field::new(
                        &<$t as $crate::TypeInfo>::type_info(),
                        stringify!($i),
                        unsafe { &((*base).$i) as *const $t as usize}
                    )
                ),*], ::std::mem::size_of::<$s>())
            }
        }
    );
}

<commit_msg>Use the same repetition qualifiers in def! for clarity<commit_after>#![cfg_attr(feature = "unstable", feature(plugin))]
#![cfg_attr(feature = "unstable", plugin(clippy))]

/// POD (*plain old data*) type: scalar, fixed-size array or compound (struct).
/// May be arbitrarily nested.
#[derive(Clone, PartialEq, Debug)]
pub enum Type {
    /// 1-byte signed integer
    Int8,
    /// 2-byte signed integer
    Int16,
    /// 4-byte signed integer
    Int32,
    /// 8-byte signed integer
    Int64,
    /// pointer-sized signed integer
    ISize,
    /// 1-byte unsigned integer
    UInt8,
    /// 2-byte unsigned integer
    UInt16,
    /// 3-byte unsigned integer
    UInt32,
    /// 4-byte unsigned integer
    UInt64,
    /// pointer-sized unsigned integer
    USize,
    /// 4-byte floating-point number
    Float32,
    /// 8-byte floating-point number
    Float64,
    /// character type
    Char,
    /// 1-byte boolean type
    Bool,
    /// fixed-size array with POD elements
    Array(Box<Type>, usize),
    /// compound type whose fields are POD
    Compound(Vec<Field>, usize),
}

impl Type {
    /// Returns the total size of a type value in bytes.
    pub fn size(&self) -> usize {
        match *self {
            Type::Int8 | Type::UInt8 | Type::Bool => 1,
            Type::Int16 | Type::UInt16 => 2,
            Type::Int32 | Type::UInt32 | Type::Float32 | Type::Char => 4,
            Type::Int64 | Type::UInt64 | Type::Float64 => 8,
            Type::USize => ::std::mem::size_of::<usize>(),
            Type::ISize => ::std::mem::size_of::<isize>(),
            Type::Array(ref ty, num) => ty.size() * num,
            Type::Compound(_, size) => size,
        }
    }

    /// Returns true if the underlying type is a scalar.
    pub fn is_scalar(&self) -> bool {
        !self.is_array() && !self.is_compound()
    }

    /// Returns true if the underlying type is a fixed-size array.
    pub fn is_array(&self) -> bool {
        if let Type::Array(_, _) = *self { true } else { false }
    }

    /// Returns true if the underlying type is compound.
    pub fn is_compound(&self) -> bool {
        if let Type::Compound(_, _) = *self { true } else { false }
    }
}

/// Field of a compound type: type, name and offset from the beginning of the struct.
#[derive(Clone, PartialEq, Debug)]
pub struct Field {
    /// field value type
    pub ty: Type,
    /// field name
    pub name: String,
    /// offset to the beginning of the struct
    pub offset: usize,
}

impl Field {
    pub fn new<S, U>(ty: &Type, name: S, offset: U) -> Field
    where S: Into<String>, U: Into<usize> {
        Field {
            ty: ty.clone(),
            name: name.into(),
            offset: offset.into()
        }
    }
}

pub trait TypeInfo: Copy {
    /// Returns the runtime type information for the implementing type.
    fn type_info() -> Type;
}

macro_rules! impl_scalar {
    ($t:ty, $i:ident) => (
        impl $crate::TypeInfo for $t {
            #[inline(always)]
            fn type_info() -> $crate::Type {
                $crate::Type::$i
            }
        }
    )
}

// implement TypeInfo for built-in scalar types
impl_scalar!(i8, Int8);
impl_scalar!(i16, Int16);
impl_scalar!(i32, Int32);
impl_scalar!(i64, Int64);
impl_scalar!(isize, ISize);
impl_scalar!(u8, UInt8);
impl_scalar!(u16, UInt16);
impl_scalar!(u32, UInt32);
impl_scalar!(u64, UInt64);
impl_scalar!(usize, USize);
impl_scalar!(f32, Float32);
impl_scalar!(f64, Float64);
impl_scalar!(char, Char);
impl_scalar!(bool, Bool);

macro_rules! impl_array {
    ($($n:expr),*$(,)*) => {
        $(
            impl<T: $crate::TypeInfo> $crate::TypeInfo for [T; $n] {
                #[inline(always)]
                fn type_info() -> $crate::Type {
                    $crate::Type::Array(
                        Box::new(<T as $crate::TypeInfo>::type_info()),
                        $n
                    )
                }
            }
        )*
    };
}

// implement TypeInfo for fixed-size arrays of lengths 0..63
impl_array!(
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
);

#[macro_export]
macro_rules! def {
    // private struct, private fields
    ($($(#[$attr:meta])* struct $s:ident { $($i:ident: $t:ty),+$(,)* })*) => (
        $(
            #[allow(dead_code)]
            #[derive(Clone, Copy)]
            $(#[$attr])*
            struct $s { $($i: $t),+ }
            def!(@impl $s { $($i: $t),+ } );
        )*
    );

    // public struct, private fields
    ($($(#[$attr:meta])* pub struct $s:ident { $($i:ident: $t:ty),+$(,)* })*) => (
        $(
            #[allow(dead_code)]
            #[derive(Clone, Copy)]
            $(#[$attr])*
            pub struct $s { $($i: $t),+ }
            def!(@impl $s { $($i: $t),+ } );
        )*
    );

    // public struct, public fields
    ($($(#[$attr:meta])* pub struct $s:ident { $(pub $i:ident: $t:ty),+$(,)* })*) => (
        $(
            #[allow(dead_code)]
            #[derive(Clone, Copy)]
            $(#[$attr])*
            pub struct $s { pub $($i: $t),+ }
            def!(@impl $s { $($i: $t),+ } );
        )*
    );

    // implement TypeInfo trait
    (@impl $s:ident { $($i:ident: $t:ty),+ }) => (
        impl $crate::TypeInfo for $s {
            fn type_info() -> $crate::Type {
                let base = 0usize as *const $s;
                $crate::Type::Compound(vec![$(
                    $crate::Field::new(
                        &<$t as $crate::TypeInfo>::type_info(),
                        stringify!($i),
                        unsafe { &((*base).$i) as *const $t as usize}
                    )
                ),+], ::std::mem::size_of::<$s>())
            }
        }
    );
}

<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! RPPAL is a Rust library that provides access to the Raspberry Pi's GPIO, I2C and SPI peripherals.
//! Support for additional peripherals will be added in future updates. The library is
//! compatible with the Raspberry Pi A, A+, B, B+, 2B, 3B, 3B+, Compute, Compute 3,
//! Zero and Zero W.

// Used by rustdoc to link other crates to rppal's docs
#![doc(html_root_url = "https://docs.rs/rppal/0.7.1")]
// Needed for the quick_error! macro
#![recursion_limit = "128"]
// Suppress warnings/errors in IDEs on other platforms
#![cfg(linux)]

extern crate libc;
#[macro_use]
extern crate quick_error;

mod user;

pub mod gpio;
pub mod i2c;
pub mod pwm;
pub mod spi;
pub mod system;
pub mod uart;
<commit_msg>Remove top level #![cfg(linux)]<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! RPPAL is a Rust library that provides access to the Raspberry Pi's GPIO, I2C and SPI peripherals.
//! Support for additional peripherals will be added in future updates. The library is
//! compatible with the Raspberry Pi A, A+, B, B+, 2B, 3B, 3B+, Compute, Compute 3,
//! Zero and Zero W.

// Used by rustdoc to link other crates to rppal's docs
#![doc(html_root_url = "https://docs.rs/rppal/0.7.1")]
// Needed for the quick_error! macro
#![recursion_limit = "128"]

extern crate libc;
#[macro_use]
extern crate quick_error;

mod user;

pub mod gpio;
pub mod i2c;
pub mod pwm;
pub mod spi;
pub mod system;
pub mod uart;
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://dtolnay.github.io/syn")]

#![cfg_attr(feature = "cargo-clippy", allow(large_enum_variant))]

extern crate proc_macro2;
extern crate unicode_xid;

#[cfg(feature = "printing")]
extern crate quote;

#[cfg_attr(feature = "parsing", macro_use)]
extern crate synom;

#[macro_use]
mod macros;

mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
               MetaNameValue};

mod constant;
pub use constant::{ConstExpr, ConstCall, ConstBinary, ConstUnary, ConstCast,
                   ConstIndex, ConstParen};

mod data;
pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
               VisPublic, VisInherited};

#[cfg(feature = "full")]
mod expr;
#[cfg(feature = "full")]
pub use expr::{Arm, BindingMode, Block, CaptureBy, Expr, ExprKind, FieldPat, FieldValue, Local,
               MacStmtStyle, Pat, RangeLimits, Stmt, ExprBox, ExprInPlace,
               ExprArray, ExprCall, ExprMethodCall, ExprTup, ExprBinary, ExprUnary,
               ExprCast, ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
               ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
               ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
               ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
               ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
               PatIdent, PatWild, PatStruct, PatTuple, PatTupleStruct, PatPath,
               PatBox, PatRef, PatLit, PatRange, PatSlice, InPlaceKind, ExprGroup};

mod generics;
pub use generics::{Generics, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
                   WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
                   WhereRegionPredicate, BoundLifetimes};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, Turbofish, TyGenerics};

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItemKind, ForeignItem, ItemForeignMod,
               ImplItem, ImplItemKind, ImplPolarity, Item, ItemKind, MethodSig, PathListItem,
               TraitItem, TraitItemKind, ViewPath, ItemExternCrate, ItemUse,
               ItemStatic, ItemConst, ItemFn, ItemMod, ItemTy, ItemEnum,
               ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
               PathSimple, PathGlob, PathList, ForeignItemFn, ForeignItemStatic,
               TraitItemConst, TraitItemMethod, TraitItemType,
               ImplItemConst, ImplItemMethod, ImplItemType, ArgSelfRef,
               ArgSelf, ArgCaptured};

#[cfg(feature = "full")]
mod krate;
#[cfg(feature = "full")]
pub use krate::Crate;

mod lifetime;
pub use lifetime::Lifetime;

mod lit;
pub use lit::{Lit, LitKind};

mod mac;
pub use mac::{Mac, TokenTree};

mod derive;
pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};
// Deprecated. Use `DeriveInput` instead.
#[doc(hidden)]
pub type MacroInput = DeriveInput;

mod op;
pub use op::{BinOp, UnOp};

mod ty;
pub use ty::{Abi, AngleBracketedParameterData, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
             Mutability, ParenthesizedParameterData, Path, PathParameters, PathSegment,
             PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety, TySlice, TyArray,
             TyPtr, TyRptr, TyBareFn, TyNever, TyTup, TyPath, TyTraitObject,
             TyImplTrait, TyParen, TyInfer, TyGroup};
#[cfg(feature = "printing")]
pub use ty::PathTokens;

pub use synom::span::Span;
pub use synom::tokens;
pub use synom::delimited;

#[cfg(feature = "visit")]
pub mod visit;

#[cfg(feature = "fold")]
pub mod fold;

#[cfg(feature = "parsing")]
mod parsing {
    use std::str::FromStr;

    use super::*;
    use synom::{Synom, ParseError};
    use proc_macro2::TokenStream;

    macro_rules! traits {
        ($($ty:ident,)*) => ($(
            impl From<TokenStream> for $ty {
                fn from(stream: TokenStream) -> $ty {
                    $ty::parse_all_unwrap(stream)
                }
            }

            impl FromStr for $ty {
                type Err = ParseError;

                fn from_str(s: &str) -> Result<Self, Self::Err> {
                    $ty::parse_str_all(s)
                }
            }
        )*)
    }

    traits! {
        DeriveInput,
        TyParamBound,
        Ident,
        WhereClause,
        Ty,
        Lit,
    }

    #[cfg(feature = "full")]
    traits! {
        Expr,
        Item,
        Crate,
    }
}
<commit_msg>Remove the MacroInput type alias<commit_after>#![doc(html_root_url = "https://dtolnay.github.io/syn")]

#![cfg_attr(feature = "cargo-clippy", allow(large_enum_variant))]

extern crate proc_macro2;
extern crate unicode_xid;

#[cfg(feature = "printing")]
extern crate quote;

#[cfg_attr(feature = "parsing", macro_use)]
extern crate synom;

#[macro_use]
mod macros;

mod attr;
pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
               MetaNameValue};

mod constant;
pub use constant::{ConstExpr, ConstCall, ConstBinary, ConstUnary, ConstCast,
                   ConstIndex, ConstParen};

mod data;
pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
               VisPublic, VisInherited};

#[cfg(feature = "full")]
mod expr;
#[cfg(feature = "full")]
pub use expr::{Arm, BindingMode, Block, CaptureBy, Expr, ExprKind, FieldPat, FieldValue, Local,
               MacStmtStyle, Pat, RangeLimits, Stmt, ExprBox, ExprInPlace,
               ExprArray, ExprCall, ExprMethodCall, ExprTup, ExprBinary, ExprUnary,
               ExprCast, ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
               ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
               ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
               ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
               ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
               PatIdent, PatWild, PatStruct, PatTuple, PatTupleStruct, PatPath,
               PatBox, PatRef, PatLit, PatRange, PatSlice, InPlaceKind, ExprGroup};

mod generics;
pub use generics::{Generics, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
                   WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
                   WhereRegionPredicate, BoundLifetimes};
#[cfg(feature = "printing")]
pub use generics::{ImplGenerics, Turbofish, TyGenerics};

mod ident;
pub use ident::Ident;

#[cfg(feature = "full")]
mod item;
#[cfg(feature = "full")]
pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItemKind, ForeignItem, ItemForeignMod,
               ImplItem, ImplItemKind, ImplPolarity, Item, ItemKind, MethodSig, PathListItem,
               TraitItem, TraitItemKind, ViewPath, ItemExternCrate, ItemUse,
               ItemStatic, ItemConst, ItemFn, ItemMod, ItemTy, ItemEnum,
               ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
               PathSimple, PathGlob, PathList, ForeignItemFn, ForeignItemStatic,
               TraitItemConst, TraitItemMethod, TraitItemType,
               ImplItemConst, ImplItemMethod, ImplItemType, ArgSelfRef,
               ArgSelf, ArgCaptured};

#[cfg(feature = "full")]
mod krate;
#[cfg(feature = "full")]
pub use krate::Crate;

mod lifetime;
pub use lifetime::Lifetime;

mod lit;
pub use lit::{Lit, LitKind};

mod mac;
pub use mac::{Mac, TokenTree};

mod derive;
pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};

mod op;
pub use op::{BinOp, UnOp};

mod ty;
pub use ty::{Abi, AngleBracketedParameterData, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
             Mutability, ParenthesizedParameterData, Path, PathParameters, PathSegment,
             PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety, TySlice, TyArray,
             TyPtr, TyRptr, TyBareFn, TyNever, TyTup, TyPath, TyTraitObject,
             TyImplTrait, TyParen, TyInfer, TyGroup};
#[cfg(feature = "printing")]
pub use ty::PathTokens;

pub use synom::span::Span;
pub use synom::tokens;
pub use synom::delimited;

#[cfg(feature = "visit")]
pub mod visit;

#[cfg(feature = "fold")]
pub mod fold;

#[cfg(feature = "parsing")]
mod parsing {
    use std::str::FromStr;

    use super::*;
    use synom::{Synom, ParseError};
    use proc_macro2::TokenStream;

    macro_rules! traits {
        ($($ty:ident,)*) => ($(
            impl From<TokenStream> for $ty {
                fn from(stream: TokenStream) -> $ty {
                    $ty::parse_all_unwrap(stream)
                }
            }

            impl FromStr for $ty {
                type Err = ParseError;

                fn from_str(s: &str) -> Result<Self, Self::Err> {
                    $ty::parse_str_all(s)
                }
            }
        )*)
    }

    traits! {
        DeriveInput,
        TyParamBound,
        Ident,
        WhereClause,
        Ty,
        Lit,
    }

    #[cfg(feature = "full")]
    traits! {
        Expr,
        Item,
        Crate,
    }
}
<|endoftext|>


<commit_before>extern crate image;
extern crate rand;
extern crate rayon;
extern crate pbr;

use image::{Rgba, RgbaImage, Pixel};

use rand::Rng;

use rayon::prelude::*;

use pbr::ProgressBar;

#[derive(Clone, Copy, Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn cross_product(&self, b: Point) -> i32 {
        self.x * b.y - self.y * b.x
    }
}

#[derive(Debug, Copy, Clone)]
struct BoundingBox {
    top_left: Point,
    bottom_right: Point,
}

#[derive(Debug, Copy, Clone)]
struct Triangle {
    a: Point,
    b: Point,
    c: Point,
    color: Option<Rgba<u8>>,
}

impl Triangle {
    fn new(a: Point, b: Point, c: Point) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            color: None,
        }
    }

    // fn set_color(&mut self, c: Color) {
    //     self.color = Some(c);
    // }

    // fn get_color(&)

    fn is_inside_primitive(&self, p: Point) -> bool {
        let spanA = Point { x: self.b.x - self.a.x, y: self.b.y - self.a.y };
        let spanB = Point { x: self.c.x - self.a.x, y: self.c.y - self.a.y };

        let q = Point { x: p.x - self.a.x, y: p.y - self.a.y };

        let s = q.cross_product(spanB) as f32 / spanA.cross_product(spanB) as f32;
        let t = spanA.cross_product(q) as f32 / spanA.cross_product(spanB) as f32;

        (s >= 0.0) && (t >= 0.0) && ((s + t) <= 1.0)
    }

    fn get_bounding_box(&self) -> BoundingBox {
        use std::cmp::{min, max};
        BoundingBox {
            top_left: Point {
                x: min(min(self.a.x, self.b.x), self.c.x),
                y: min(min(self.a.y, self.b.y), self.c.y),
            },
            bottom_right: Point {
                x: max(max(self.a.x, self.b.x), self.c.x),
                y: max(max(self.a.y, self.b.y), self.c.y),
            }
        }
    }
}

pub struct RandomPointGenerator {
    rng: Box<Rng>,
    width: i32,
    height: i32,
}

impl RandomPointGenerator {
    pub fn new(width: i32, height: i32) -> RandomPointGenerator {
        RandomPointGenerator {
            rng: Box::new(rand::thread_rng()),
            width: width,
            height: height,
        }
    }

    fn next_point(&mut self) -> Point {
        Point {
            x: self.rng.gen_range(0, self.width),
            y: self.rng.gen_range(0, self.height),
        }
    }
}

pub struct Geometrify {
    point_gen: RandomPointGenerator,
}

impl Geometrify {
    pub fn new(point_gen: RandomPointGenerator) -> Geometrify {
        Geometrify {
            point_gen: point_gen
        }
    }

    fn calculate_color(image: &RgbaImage, primitive: Triangle) -> Rgba<u8> {
        let bb = primitive.get_bounding_box();

        let mut count = 0u64;
        let mut cr = 0u64;
        let mut cg = 0u64;
        let mut cb = 0u64;
        let mut ca = 0u64;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let (r, g, b, a) = image.get_pixel(x as u32, y as u32).channels4();
                cr += r as u64;
                cg += g as u64;
                cb += b as u64;
                ca += a as u64;
                count += 1;
            }
        }

        if count == 0 {
            Rgba::from_channels(255, 255, 255, 255)
        } else {
            Rgba::from_channels((cr / count) as u8,
                                (cg / count) as u8,
                                (cb / count) as u8,
                                (ca / count) as u8)
        }
    }

    fn generate_primitive(&mut self) -> Triangle {
        Triangle::new(self.point_gen.next_point(),
                      self.point_gen.next_point(),
                      self.point_gen.next_point())
    }

    fn add_to_image(image: &mut RgbaImage, primitive: Triangle) {
        let bb = primitive.get_bounding_box();

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
        // for y in 0..image.height() {
        //     for x in 0..image.width() {
                let p = Point {x: x as i32, y: y as i32};
                if primitive.is_inside_primitive(p) {
                    *image.get_pixel_mut(x as u32, y as u32) = Geometrify::mixColor(primitive.color.expect("color of triangle not set"), *image.get_pixel(x as u32, y as u32));
                }
            }
        }
    }

    fn mixColor(first: Rgba<u8>, second: Rgba<u8>) -> Rgba<u8> {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();

        Rgba::from_channels(
            ((((r1 as u32 + r2 as u32)) / 2) as u8),
            ((((g1 as u32 + g2 as u32)) / 2) as u8),
            ((((b1 as u32 + b2 as u32)) / 2) as u8),
            ((((a1 as u32 + a2 as u32)) / 2) as u8),
        )
    }

    fn difference(first: Rgba<u8>, second: Rgba<u8>) -> i32 {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();
        let mut d = 0i32;

        d += i32::abs((r1 as i32 - r2 as i32));
        d += i32::abs((g1 as i32 - g2 as i32));
        d += i32::abs((b1 as i32 - b2 as i32));
        d += i32::abs((a1 as i32 - a2 as i32));

        d
    }

    fn calculate_difference(original: &RgbaImage, current: &RgbaImage, primitive: Triangle) -> i32 {
        let bb = primitive.get_bounding_box();

        let mut d = 0i32;

        for y in 0..original.height() {
            for x in 0..original.width() {
                let originalRgb = original.get_pixel(x, y);
                let resultRgb = if (bb.top_left.x as u32 <= x) && (x <= bb.bottom_right.x as u32)
                    && (bb.top_left.y as u32 <= y) && (y <= bb.bottom_right.y as u32)
                    && (primitive.is_inside_primitive(Point { x: x as i32, y: y as i32 })) {
                        Geometrify::mixColor(*current.get_pixel(x, y), primitive.color.expect("triangle color not "))
                    } else {
                        *current.get_pixel(x, y)
                    };

                d += Geometrify::difference(*originalRgb, resultRgb);
            }
        }

        d
    }

    pub fn apply(&mut self, image: RgbaImage, numberOfIterations: i32, numberOfSamples: i32) -> RgbaImage {
        let mut progress = ProgressBar::new(numberOfIterations as u64);
        progress.format("|#--|");

        let mut destination = RgbaImage::new(image.width(), image.height());

        for _ in 0..numberOfIterations {
            let minPrimitive = (0..numberOfSamples)
                .map(|_| {
                    self.generate_primitive()
                }).collect::<Vec<Triangle>>()
                .par_iter()
                .map(|primitive| {
                    let mut prim = *primitive;
                    prim.color = Some(Geometrify::calculate_color(&image, prim));
                    (prim, Geometrify::calculate_difference(&image, &destination, prim))
                })
                .min_by_key(|tup| tup.1);

            Geometrify::add_to_image(&mut destination, minPrimitive.expect("no fitting triangle found").0);
            progress.inc();
        }
        progress.finish_print("done");

        destination
    }

}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>More generics.<commit_after>extern crate image;
extern crate rand;
extern crate rayon;
extern crate pbr;

use image::{Rgba, RgbaImage, Pixel};

use rand::Rng;

use rayon::prelude::*;

use pbr::ProgressBar;

#[derive(Clone, Copy, Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn cross_product(&self, b: Point) -> i32 {
        self.x * b.y - self.y * b.x
    }
}

#[derive(Debug, Copy, Clone)]
struct BoundingBox {
    top_left: Point,
    bottom_right: Point,
}

trait Primitive {
    fn is_inside_primitive(&self, p: Point) -> bool;
    fn bounding_box(&self) -> BoundingBox;
    fn get_color(&self) -> Option<Rgba<u8>>;
    fn set_color(&mut self, color: Rgba<u8>);
}

#[derive(Debug, Copy, Clone)]
struct Triangle {
    a: Point,
    b: Point,
    c: Point,
    color: Option<Rgba<u8>>,
}

impl Triangle {
    fn new(a: Point, b: Point, c: Point) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            color: None,
        }
    }
}

impl Primitive for Triangle {
    fn is_inside_primitive(&self, p: Point) -> bool {
        let spanA = Point { x: self.b.x - self.a.x, y: self.b.y - self.a.y };
        let spanB = Point { x: self.c.x - self.a.x, y: self.c.y - self.a.y };

        let q = Point { x: p.x - self.a.x, y: p.y - self.a.y };

        let s = q.cross_product(spanB) as f32 / spanA.cross_product(spanB) as f32;
        let t = spanA.cross_product(q) as f32 / spanA.cross_product(spanB) as f32;

        (s >= 0.0) && (t >= 0.0) && ((s + t) <= 1.0)
    }

    fn bounding_box(&self) -> BoundingBox {
        use std::cmp::{min, max};
        BoundingBox {
            top_left: Point {
                x: min(min(self.a.x, self.b.x), self.c.x),
                y: min(min(self.a.y, self.b.y), self.c.y),
            },
            bottom_right: Point {
                x: max(max(self.a.x, self.b.x), self.c.x),
                y: max(max(self.a.y, self.b.y), self.c.y),
            }
        }
    }

    fn get_color(&self) -> Option<Rgba<u8>> {
        self.color
    }

    fn set_color(&mut self, color: Rgba<u8>) {
        self.color = Some(color);
    }
}

pub struct RandomPointGenerator {
    rng: Box<Rng>,
    width: i32,
    height: i32,
}

impl RandomPointGenerator {
    pub fn new(width: i32, height: i32) -> RandomPointGenerator {
        RandomPointGenerator {
            rng: Box::new(rand::thread_rng()),
            width: width,
            height: height,
        }
    }

    fn next_point(&mut self) -> Point {
        Point {
            x: self.rng.gen_range(0, self.width),
            y: self.rng.gen_range(0, self.height),
        }
    }
}

pub struct Geometrify {
    point_gen: RandomPointGenerator,
}

impl Geometrify {
    pub fn new(point_gen: RandomPointGenerator) -> Geometrify {
        Geometrify {
            point_gen: point_gen
        }
    }

    fn calculate_color(image: &RgbaImage, primitive: &Primitive) -> Rgba<u8> {
        let bb = primitive.bounding_box();

        let mut count = 0u64;
        let mut cr = 0u64;
        let mut cg = 0u64;
        let mut cb = 0u64;
        let mut ca = 0u64;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let (r, g, b, a) = image.get_pixel(x as u32, y as u32).channels4();
                cr += r as u64;
                cg += g as u64;
                cb += b as u64;
                ca += a as u64;
                count += 1;
            }
        }

        if count == 0 {
            Rgba::from_channels(255, 255, 255, 255)
        } else {
            Rgba::from_channels((cr / count) as u8,
                                (cg / count) as u8,
                                (cb / count) as u8,
                                (ca / count) as u8)
        }
    }

    fn generate_primitive(&mut self) -> Triangle {
        Triangle::new(self.point_gen.next_point(),
                      self.point_gen.next_point(),
                      self.point_gen.next_point())
    }

    fn add_to_image(image: &mut RgbaImage, primitive: &Primitive) {
        let bb = primitive.bounding_box();

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
        // for y in 0..image.height() {
        //     for x in 0..image.width() {
                let p = Point {x: x as i32, y: y as i32};
                if primitive.is_inside_primitive(p) {
                    *image.get_pixel_mut(x as u32, y as u32) = Geometrify::mixColor(primitive.get_color().expect("color of triangle not set"), *image.get_pixel(x as u32, y as u32));
                }
            }
        }
    }

    fn mixColor(first: Rgba<u8>, second: Rgba<u8>) -> Rgba<u8> {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();

        Rgba::from_channels(
            ((((r1 as u32 + r2 as u32)) / 2) as u8),
            ((((g1 as u32 + g2 as u32)) / 2) as u8),
            ((((b1 as u32 + b2 as u32)) / 2) as u8),
            ((((a1 as u32 + a2 as u32)) / 2) as u8),
        )
    }

    fn difference(first: Rgba<u8>, second: Rgba<u8>) -> i32 {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();
        let mut d = 0i32;

        d += i32::abs((r1 as i32 - r2 as i32));
        d += i32::abs((g1 as i32 - g2 as i32));
        d += i32::abs((b1 as i32 - b2 as i32));
        d += i32::abs((a1 as i32 - a2 as i32));

        d
    }

    fn calculate_difference(original: &RgbaImage, current: &RgbaImage, primitive: &Primitive) -> i32 {
        let bb = primitive.bounding_box();

        let mut d = 0i32;

        for y in 0..original.height() {
            for x in 0..original.width() {
                let originalRgb = original.get_pixel(x, y);
                let resultRgb = if (bb.top_left.x as u32 <= x) && (x <= bb.bottom_right.x as u32)
                    && (bb.top_left.y as u32 <= y) && (y <= bb.bottom_right.y as u32)
                    && (primitive.is_inside_primitive(Point { x: x as i32, y: y as i32 })) {
                        Geometrify::mixColor(*current.get_pixel(x, y), primitive.get_color().expect("triangle color not "))
                    } else {
                        *current.get_pixel(x, y)
                    };

                d += Geometrify::difference(*originalRgb, resultRgb);
            }
        }

        d
    }

    pub fn apply(&mut self, image: RgbaImage, numberOfIterations: i32, numberOfSamples: i32) -> RgbaImage {
        let mut progress = ProgressBar::new(numberOfIterations as u64);
        progress.format("|#--|");

        let mut destination = RgbaImage::new(image.width(), image.height());

        for _ in 0..numberOfIterations {
            let minPrimitive = (0..numberOfSamples)
                .map(|_| {
                    self.generate_primitive()
                }).collect::<Vec<Triangle>>()
                .par_iter()
                .map(|primitive| {
                    let mut prim = *primitive;
                    prim.color = Some(Geometrify::calculate_color(&image, &prim));
                    (prim, Geometrify::calculate_difference(&image, &destination, &prim))
                })
                .min_by_key(|tup| tup.1);

            Geometrify::add_to_image(&mut destination, &minPrimitive.expect("no fitting triangle found").0);
            progress.inc();
        }
        progress.finish_print("done");

        destination
    }

}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::io;
use std::fs::File;
use std::convert;

use serde_json;

use gerrit;
use spark;

#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    spark_person_id: spark::PersonId,
    email: spark::Email,
    enabled: bool,
}

impl User {
    fn new(person_id: spark::PersonId, email: spark::Email) -> User {
        User {
            spark_person_id: person_id,
            email: email,
            enabled: true,
        }
    }
}

/// Describes a state of the bot
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bot {
    gerrit_username: Option<String>, // TODO: this should not be part of the state
    users: Vec<User>,
}

#[derive(Debug)]
pub enum BotError {
    Io(io::Error),
    Serialization(serde_json::Error),
}

impl convert::From<io::Error> for BotError {
    fn from(err: io::Error) -> BotError {
        BotError::Io(err)
    }
}

impl convert::From<serde_json::Error> for BotError {
    fn from(err: serde_json::Error) -> BotError {
        BotError::Serialization(err)
    }
}

fn format_approval_value(value: &str) -> String {
    let value: i8 = value.parse().unwrap_or(0);
    // TODO: when Spark will be allow to format text with different colors,
    // set green resp. red color here.
    if value > 0 {
        format!("+{}", value)
    } else {
        format!("{}", value)
    }
}

impl Bot {
    pub fn new(gerrit_username: gerrit::Username) -> Bot {
        Bot {
            gerrit_username: Some(gerrit_username),
            users: Vec::new(),
        }
    }

    pub fn default() -> Bot {
        Bot {
            gerrit_username: None,
            users: Vec::new(),
        }
    }

    fn enable<'a>(&'a mut self, person_id: &str, email: &str, enabled: bool) -> &'a User {
        // FIXME: Replace linear search
        let pos = self.users.iter().position(
            |u| u.spark_person_id == person_id,
        );
        let user: &'a mut User = match pos {
            Some(pos) => &mut self.users[pos],
            None => {
                self.users.push(User::new(
                    String::from(person_id),
                    String::from(email),
                ));
                self.users.iter_mut().last().unwrap()
            }
        };
        user.enabled = enabled;
        user
    }

    fn get_approvals_msg(&self, event: gerrit::Event) -> Option<(&User, String)> {
        println!("[D] Incoming approvals: {:?}", event);

        let author = event.author;
        let change = event.change;
        let approvals = event.approvals;

        let approver = author.unwrap().username.clone();
        if approver == change.owner.username {
            // No need to notify about user's own approvals.
            return None;
        }

        if let Some(ref owner_email) = change.owner.email {
            // TODO: Fix linear search
            let users = &self.users;
            for user in users.iter() {
                if &user.email == owner_email {
                    if !user.enabled {
                        break;
                    }

                    if let Some(approvals) = approvals {
                        let msgs: Vec<String> = approvals
                            .iter()
                            .filter(|approval| {
                                let filtered = if let Some(ref old_value) = approval.old_value {
                                    old_value != &approval.value && approval.value != "0"
                                } else {
                                    approval.value != "0"
                                };
                                println!("Filtered approval: {:?}", !filtered);
                                filtered
                            })
                            .map(|approval| {
                                format!(
                                    "{}: {} ({}) from {}",
                                    change.subject,
                                    format_approval_value(&approval.value),
                                    approval.approval_type,
                                    approver
                                )
                            })
                            .collect();
                        return if !msgs.is_empty() {
                            Some((user, msgs.join("\n")))
                        } else {
                            None
                        };
                    }
                }
            }
        }
        None
    }

    pub fn save<P>(self, filename: P) -> Result<(), BotError>
    where
        P: AsRef<Path>,
    {
        let f = File::create(filename)?;
        serde_json::to_writer(f, &self)?;
        Ok(())
    }

    pub fn load<P>(filename: P) -> Result<Self, BotError>
    where
        P: AsRef<Path>,
    {
        let f = File::open(filename)?;
        let bot: Bot = serde_json::from_reader(f)?;
        Ok(bot)
    }

    pub fn num_users(&self) -> usize {
        self.users.len()
    }
}

#[derive(Debug)]
pub enum Action {
    Enable(spark::PersonId, spark::Email),
    Disable(spark::PersonId, spark::Email),
    UpdateApprovals(gerrit::Event),
    Help(spark::PersonId),
    Unknown(spark::PersonId),
    NoOp,
}

#[derive(Debug)]
pub struct Response {
    // TODO: Switch to a reference, since it should be alive inside of the Bot state
    pub person_id: spark::PersonId,
    pub message: String,
}

impl Response {
    pub fn new(person_id: spark::PersonId, message: String) -> Response {
        Response {
            person_id: person_id,
            message: message,
        }
    }
}

#[derive(Debug)]
pub enum Task {
    Reply(Response),
    ReplyAndSave(Response),
}

const GREETINGS_MSG: &'static str =
    r#"Hi. I am GerritBot (**in a very early alpha**). I can watch Gerrit reviews for you, and notify you about new +1/-1's.

To enable notifications, just type in 'enable'. A small note: your email in Spark and in Gerrit has to be the same. Otherwise, I can't match your accounts.

For more information, type in **help**.

By the way, my icon is made by
[ Madebyoliver ](http://www.flaticon.com/authors/madebyoliver)
from
[ www.flaticon.com ](http://www.flaticon.com)
and is licensed by
[ CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/).
"#;

const HELP_MSG: &'static str = r#"Commands:

`enable` I will start notifying you.

`disable` I will stop notifying you.

`help` This message
"#;

/// Action controller
/// Return new bot state and an optional message to send to the user
pub fn update(action: Action, bot: Bot) -> (Bot, Option<Task>) {
    let mut bot = bot;
    let task = match action {
        Action::Enable(person_id, email) => {
            bot.enable(&person_id, &email, true);
            let task = Task::ReplyAndSave(Response::new(
                person_id,
                String::from("Got it! Happy reviewing!"),
            ));
            Some(task)
        }
        Action::Disable(person_id, email) => {
            bot.enable(&person_id, &email, false);
            let task = Task::ReplyAndSave(Response::new(
                person_id,
                String::from("Got it! I will stay silent."),
            ));
            Some(task)
        }
        Action::UpdateApprovals(event) => {
            bot.get_approvals_msg(event).map(|(user, message)| {
                Task::Reply(Response::new(user.spark_person_id.clone(), message))
            })
        }
        Action::Help(person_id) => {
            Some(Task::Reply(
                Response::new(person_id, String::from(HELP_MSG)),
            ))
        }
        Action::Unknown(person_id) => {
            Some(Task::Reply(
                Response::new(person_id, String::from(GREETINGS_MSG)),
            ))
        }
        _ => None,
    };
    (bot, task)
}
<commit_msg>Reply with the link to the review.<commit_after>use std::path::Path;
use std::io;
use std::fs::File;
use std::convert;

use serde_json;

use gerrit;
use spark;

#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    spark_person_id: spark::PersonId,
    email: spark::Email,
    enabled: bool,
}

impl User {
    fn new(person_id: spark::PersonId, email: spark::Email) -> User {
        User {
            spark_person_id: person_id,
            email: email,
            enabled: true,
        }
    }
}

/// Describes a state of the bot
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bot {
    gerrit_username: Option<String>, // TODO: this should not be part of the state
    users: Vec<User>,
}

#[derive(Debug)]
pub enum BotError {
    Io(io::Error),
    Serialization(serde_json::Error),
}

impl convert::From<io::Error> for BotError {
    fn from(err: io::Error) -> BotError {
        BotError::Io(err)
    }
}

impl convert::From<serde_json::Error> for BotError {
    fn from(err: serde_json::Error) -> BotError {
        BotError::Serialization(err)
    }
}

fn format_approval_value(value: &str) -> String {
    let value: i8 = value.parse().unwrap_or(0);
    // TODO: when Spark will be allow to format text with different colors,
    // set green resp. red color here.
    if value > 0 {
        format!("+{}", value)
    } else {
        format!("{}", value)
    }
}

impl Bot {
    pub fn new(gerrit_username: gerrit::Username) -> Bot {
        Bot {
            gerrit_username: Some(gerrit_username),
            users: Vec::new(),
        }
    }

    pub fn default() -> Bot {
        Bot {
            gerrit_username: None,
            users: Vec::new(),
        }
    }

    fn enable<'a>(&'a mut self, person_id: &str, email: &str, enabled: bool) -> &'a User {
        // FIXME: Replace linear search
        let pos = self.users.iter().position(
            |u| u.spark_person_id == person_id,
        );
        let user: &'a mut User = match pos {
            Some(pos) => &mut self.users[pos],
            None => {
                self.users.push(User::new(
                    String::from(person_id),
                    String::from(email),
                ));
                self.users.iter_mut().last().unwrap()
            }
        };
        user.enabled = enabled;
        user
    }

    fn get_approvals_msg(&self, event: gerrit::Event) -> Option<(&User, String)> {
        println!("[D] Incoming approvals: {:?}", event);

        let author = event.author;
        let change = event.change;
        let approvals = event.approvals;

        let approver = author.unwrap().username.clone();
        if approver == change.owner.username {
            // No need to notify about user's own approvals.
            return None;
        }

        if let Some(ref owner_email) = change.owner.email {
            // TODO: Fix linear search
            let users = &self.users;
            for user in users.iter() {
                if &user.email == owner_email {
                    if !user.enabled {
                        break;
                    }

                    if let Some(approvals) = approvals {
                        let msgs: Vec<String> = approvals
                            .iter()
                            .filter(|approval| {
                                let filtered = if let Some(ref old_value) = approval.old_value {
                                    old_value != &approval.value && approval.value != "0"
                                } else {
                                    approval.value != "0"
                                };
                                println!("Filtered approval: {:?}", !filtered);
                                filtered
                            })
                            .map(|approval| {
                                format!(
                                    "[{}]({}): {} ({}) from {}",
                                    change.subject,
                                    change.url,
                                    format_approval_value(&approval.value),
                                    approval.approval_type,
                                    approver
                                )
                            })
                            .collect();
                        return if !msgs.is_empty() {
                            Some((user, msgs.join("\n")))
                        } else {
                            None
                        };
                    }
                }
            }
        }
        None
    }

    pub fn save<P>(self, filename: P) -> Result<(), BotError>
    where
        P: AsRef<Path>,
    {
        let f = File::create(filename)?;
        serde_json::to_writer(f, &self)?;
        Ok(())
    }

    pub fn load<P>(filename: P) -> Result<Self, BotError>
    where
        P: AsRef<Path>,
    {
        let f = File::open(filename)?;
        let bot: Bot = serde_json::from_reader(f)?;
        Ok(bot)
    }

    pub fn num_users(&self) -> usize {
        self.users.len()
    }
}

#[derive(Debug)]
pub enum Action {
    Enable(spark::PersonId, spark::Email),
    Disable(spark::PersonId, spark::Email),
    UpdateApprovals(gerrit::Event),
    Help(spark::PersonId),
    Unknown(spark::PersonId),
    NoOp,
}

#[derive(Debug)]
pub struct Response {
    // TODO: Switch to a reference, since it should be alive inside of the Bot state
    pub person_id: spark::PersonId,
    pub message: String,
}

impl Response {
    pub fn new(person_id: spark::PersonId, message: String) -> Response {
        Response {
            person_id: person_id,
            message: message,
        }
    }
}

#[derive(Debug)]
pub enum Task {
    Reply(Response),
    ReplyAndSave(Response),
}

const GREETINGS_MSG: &'static str =
    r#"Hi. I am GerritBot (**in a very early alpha**). I can watch Gerrit reviews for you, and notify you about new +1/-1's.

To enable notifications, just type in 'enable'. A small note: your email in Spark and in Gerrit has to be the same. Otherwise, I can't match your accounts.

For more information, type in **help**.

By the way, my icon is made by
[ Madebyoliver ](http://www.flaticon.com/authors/madebyoliver)
from
[ www.flaticon.com ](http://www.flaticon.com)
and is licensed by
[ CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/).
"#;

const HELP_MSG: &'static str = r#"Commands:

`enable` I will start notifying you.

`disable` I will stop notifying you.

`help` This message
"#;

/// Action controller
/// Return new bot state and an optional message to send to the user
pub fn update(action: Action, bot: Bot) -> (Bot, Option<Task>) {
    let mut bot = bot;
    let task = match action {
        Action::Enable(person_id, email) => {
            bot.enable(&person_id, &email, true);
            let task = Task::ReplyAndSave(Response::new(
                person_id,
                String::from("Got it! Happy reviewing!"),
            ));
            Some(task)
        }
        Action::Disable(person_id, email) => {
            bot.enable(&person_id, &email, false);
            let task = Task::ReplyAndSave(Response::new(
                person_id,
                String::from("Got it! I will stay silent."),
            ));
            Some(task)
        }
        Action::UpdateApprovals(event) => {
            bot.get_approvals_msg(event).map(|(user, message)| {
                Task::Reply(Response::new(user.spark_person_id.clone(), message))
            })
        }
        Action::Help(person_id) => {
            Some(Task::Reply(
                Response::new(person_id, String::from(HELP_MSG)),
            ))
        }
        Action::Unknown(person_id) => {
            Some(Task::Reply(
                Response::new(person_id, String::from(GREETINGS_MSG)),
            ))
        }
        _ => None,
    };
    (bot, task)
}
<|endoftext|>


<commit_before>#![allow(clippy::type_complexity)]

mod app;
mod extract;
mod handler;
// mod info;
pub mod blocking;
mod config;
pub mod guard;
pub mod middleware;
mod request;
mod resource;
mod responder;
mod route;
mod scope;
mod server;
mod service;
mod state;
pub mod test;

#[allow(unused_imports)]
#[macro_use]
extern crate actix_web_codegen;

#[doc(hidden)]
pub use actix_web_codegen::*;

// re-export for convenience
pub use actix_http::Response as HttpResponse;
pub use actix_http::{body, error, http, Error, HttpMessage, ResponseError, Result};

pub use crate::app::App;
pub use crate::extract::FromRequest;
pub use crate::request::HttpRequest;
pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::scope::Scope;
pub use crate::server::HttpServer;
pub use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};

pub mod dev {
    //! The `actix-web` prelude for library developers
    //!
    //! The purpose of this module is to alleviate imports of many common actix
    //! traits by adding a glob import to the top of actix heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use actix_web::dev::*;
    //! ```

    pub use crate::app::AppRouter;
    pub use crate::config::AppConfig;
    pub use crate::service::HttpServiceFactory;

    pub use actix_http::body::{Body, BodyLength, MessageBody, ResponseBody};
    pub use actix_http::dev::ResponseBuilder as HttpResponseBuilder;
    pub use actix_http::{
        Extensions, Payload, PayloadStream, RequestHead, ResponseHead,
    };
    pub use actix_router::{Path, ResourceDef, Url};

    pub(crate) fn insert_slash(path: &str) -> String {
        let mut path = path.to_owned();
        if !path.is_empty() && !path.starts_with('/') {
            path.insert(0, '/');
        };
        path
    }
}

pub mod web {
    use actix_http::{http::Method, Error, Response};
    use futures::IntoFuture;

    pub use actix_http::Response as HttpResponse;
    pub use bytes::{Bytes, BytesMut};

    use crate::extract::FromRequest;
    use crate::handler::{AsyncFactory, Factory};
    use crate::resource::Resource;
    use crate::responder::Responder;
    use crate::route::Route;
    use crate::scope::Scope;

    pub use crate::extract::{Form, Json, Path, Payload, Query};
    pub use crate::extract::{FormConfig, JsonConfig, PayloadConfig};
    pub use crate::request::HttpRequest;
    pub use crate::state::State;

    /// Create resource for a specific path.
    ///
    /// Resources may have variable path segments. For example, a
    /// resource with the path `/a/{name}/c` would match all incoming
    /// requests with paths such as `/a/b/c`, `/a/1/c`, or `/a/etc/c`.
    ///
    /// A variable segment is specified in the form `{identifier}`,
    /// where the identifier can be used later in a request handler to
    /// access the matched value for that segment. This is done by
    /// looking up the identifier in the `Params` object returned by
    /// `HttpRequest.match_info()` method.
    ///
    /// By default, each segment matches the regular expression `[^{}/]+`.
    ///
    /// You can also specify a custom regex in the form `{identifier:regex}`:
    ///
    /// For instance, to route `GET`-requests on any route matching
    /// `/users/{userid}/{friend}` and store `userid` and `friend` in
    /// the exposed `Params` object:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// use actix_web::{web, http, App, HttpResponse};
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::resource("/users/{userid}/{friend}")
    ///             .route(web::get().to(|| HttpResponse::Ok()))
    ///             .route(web::head().to(|| HttpResponse::MethodNotAllowed()))
    ///     );
    /// }
    /// ```
    pub fn resource
(path: &str) -> Resource
 {
        Resource::new(path)
    }

    /// Configure scope for common root path.
    ///
    /// Scopes collect multiple paths under a common path prefix.
    /// Scope path can contain variable path segments as resources.
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// use actix_web::{web, App, HttpRequest, HttpResponse};
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::scope("/{project_id}")
    ///             .service(web::resource("/path1").to(|| HttpResponse::Ok()))
    ///             .service(web::resource("/path2").to(|| HttpResponse::Ok()))
    ///             .service(web::resource("/path3").to(|| HttpResponse::MethodNotAllowed()))
    ///     );
    /// }
    /// ```
    ///
    /// In the above example, three routes get added:
    ///  * /{project_id}/path1
    ///  * /{project_id}/path2
    ///  * /{project_id}/path3
    ///
    pub fn scope
(path: &str) -> Scope
 {
        Scope::new(path)
    }

    /// Create **route** without configuration.
    pub fn route
() -> Route
 {
        Route::new()
    }

    /// Create **route** with `GET` method guard.
    pub fn get
() -> Route
 {
        Route::get()
    }

    /// Create **route** with `POST` method guard.
    pub fn post
() -> Route
 {
        Route::post()
    }

    /// Create **route** with `PUT` method guard.
    pub fn put
() -> Route
 {
        Route::put()
    }

    /// Create **route** with `DELETE` method guard.
    pub fn delete
() -> Route
 {
        Route::delete()
    }

    /// Create **route** with `HEAD` method guard.
    pub fn head
() -> Route
 {
        Route::new().method(Method::HEAD)
    }

    /// Create **route** and add method guard.
    pub fn method
(method: Method) -> Route
 {
        Route::new().method(method)
    }

    /// Create a new route and add handler.
    ///
    /// ```rust
    /// use actix_web::{web, App, HttpResponse};
    ///
    /// fn index() -> HttpResponse {
    ///    unimplemented!()
    /// }
    ///
    /// App::new().service(
    ///     web::resource("/").route(
    ///         web::to(index))
    /// );
    /// ```
    pub fn to<F, I, R, P: 'static>(handler: F) -> Route

    where
        F: Factory + 'static,
        I: FromRequest
 + 'static,
        R: Responder + 'static,
    {
        Route::new().to(handler)
    }

    /// Create a new route and add async handler.
    ///
    /// ```rust
    /// use actix_web::{web, App, HttpResponse, Error};
    ///
    /// fn index() -> impl futures::Future<Item=HttpResponse, Error=Error> {
    ///     futures::future::ok(HttpResponse::Ok().finish())
    /// }
    ///
    /// App::new().service(web::resource("/").route(
    ///     web::to_async(index))
    /// );
    /// ```
    pub fn to_async<F, I, R, P: 'static>(handler: F) -> Route

    where
        F: AsyncFactory,
        I: FromRequest
 + 'static,
        R: IntoFuture + 'static,
        R::Item: Into<Response>,
        R::Error: Into<Error>,
    {
        Route::new().to_async(handler)
    }
}
<commit_msg>export blocking via web module<commit_after>#![allow(clippy::type_complexity)]

mod app;
mod extract;
mod handler;
// mod info;
pub mod blocking;
mod config;
pub mod guard;
pub mod middleware;
mod request;
mod resource;
mod responder;
mod route;
mod scope;
mod server;
mod service;
mod state;
pub mod test;

#[allow(unused_imports)]
#[macro_use]
extern crate actix_web_codegen;

#[doc(hidden)]
pub use actix_web_codegen::*;

// re-export for convenience
pub use actix_http::Response as HttpResponse;
pub use actix_http::{body, error, http, Error, HttpMessage, ResponseError, Result};

pub use crate::app::App;
pub use crate::extract::FromRequest;
pub use crate::request::HttpRequest;
pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::scope::Scope;
pub use crate::server::HttpServer;
pub use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};

pub mod dev {
    //! The `actix-web` prelude for library developers
    //!
    //! The purpose of this module is to alleviate imports of many common actix
    //! traits by adding a glob import to the top of actix heavy modules:
    //!
    //! ```
    //! # #![allow(unused_imports)]
    //! use actix_web::dev::*;
    //! ```

    pub use crate::app::AppRouter;
    pub use crate::config::AppConfig;
    pub use crate::service::HttpServiceFactory;

    pub use actix_http::body::{Body, BodyLength, MessageBody, ResponseBody};
    pub use actix_http::dev::ResponseBuilder as HttpResponseBuilder;
    pub use actix_http::{
        Extensions, Payload, PayloadStream, RequestHead, ResponseHead,
    };
    pub use actix_router::{Path, ResourceDef, Url};

    pub(crate) fn insert_slash(path: &str) -> String {
        let mut path = path.to_owned();
        if !path.is_empty() && !path.starts_with('/') {
            path.insert(0, '/');
        };
        path
    }
}

pub mod web {
    use actix_http::{http::Method, Error, Response};
    use futures::IntoFuture;

    pub use actix_http::Response as HttpResponse;
    pub use bytes::{Bytes, BytesMut};

    use crate::blocking::CpuFuture;
    use crate::extract::FromRequest;
    use crate::handler::{AsyncFactory, Factory};
    use crate::resource::Resource;
    use crate::responder::Responder;
    use crate::route::Route;
    use crate::scope::Scope;

    pub use crate::extract::{Form, Json, Path, Payload, Query};
    pub use crate::extract::{FormConfig, JsonConfig, PayloadConfig};
    pub use crate::request::HttpRequest;
    pub use crate::state::State;

    /// Create resource for a specific path.
    ///
    /// Resources may have variable path segments. For example, a
    /// resource with the path `/a/{name}/c` would match all incoming
    /// requests with paths such as `/a/b/c`, `/a/1/c`, or `/a/etc/c`.
    ///
    /// A variable segment is specified in the form `{identifier}`,
    /// where the identifier can be used later in a request handler to
    /// access the matched value for that segment. This is done by
    /// looking up the identifier in the `Params` object returned by
    /// `HttpRequest.match_info()` method.
    ///
    /// By default, each segment matches the regular expression `[^{}/]+`.
    ///
    /// You can also specify a custom regex in the form `{identifier:regex}`:
    ///
    /// For instance, to route `GET`-requests on any route matching
    /// `/users/{userid}/{friend}` and store `userid` and `friend` in
    /// the exposed `Params` object:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// use actix_web::{web, http, App, HttpResponse};
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::resource("/users/{userid}/{friend}")
    ///             .route(web::get().to(|| HttpResponse::Ok()))
    ///             .route(web::head().to(|| HttpResponse::MethodNotAllowed()))
    ///     );
    /// }
    /// ```
    pub fn resource
(path: &str) -> Resource
 {
        Resource::new(path)
    }

    /// Configure scope for common root path.
    ///
    /// Scopes collect multiple paths under a common path prefix.
    /// Scope path can contain variable path segments as resources.
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// use actix_web::{web, App, HttpRequest, HttpResponse};
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::scope("/{project_id}")
    ///             .service(web::resource("/path1").to(|| HttpResponse::Ok()))
    ///             .service(web::resource("/path2").to(|| HttpResponse::Ok()))
    ///             .service(web::resource("/path3").to(|| HttpResponse::MethodNotAllowed()))
    ///     );
    /// }
    /// ```
    ///
    /// In the above example, three routes get added:
    ///  * /{project_id}/path1
    ///  * /{project_id}/path2
    ///  * /{project_id}/path3
    ///
    pub fn scope
(path: &str) -> Scope
 {
        Scope::new(path)
    }

    /// Create **route** without configuration.
    pub fn route
() -> Route
 {
        Route::new()
    }

    /// Create **route** with `GET` method guard.
    pub fn get
() -> Route
 {
        Route::get()
    }

    /// Create **route** with `POST` method guard.
    pub fn post
() -> Route
 {
        Route::post()
    }

    /// Create **route** with `PUT` method guard.
    pub fn put
() -> Route
 {
        Route::put()
    }

    /// Create **route** with `DELETE` method guard.
    pub fn delete
() -> Route
 {
        Route::delete()
    }

    /// Create **route** with `HEAD` method guard.
    pub fn head
() -> Route
 {
        Route::new().method(Method::HEAD)
    }

    /// Create **route** and add method guard.
    pub fn method
(method: Method) -> Route
 {
        Route::new().method(method)
    }

    /// Create a new route and add handler.
    ///
    /// ```rust
    /// use actix_web::{web, App, HttpResponse};
    ///
    /// fn index() -> HttpResponse {
    ///    unimplemented!()
    /// }
    ///
    /// App::new().service(
    ///     web::resource("/").route(
    ///         web::to(index))
    /// );
    /// ```
    pub fn to<F, I, R, P: 'static>(handler: F) -> Route

    where
        F: Factory + 'static,
        I: FromRequest
 + 'static,
        R: Responder + 'static,
    {
        Route::new().to(handler)
    }

    /// Create a new route and add async handler.
    ///
    /// ```rust
    /// use actix_web::{web, App, HttpResponse, Error};
    ///
    /// fn index() -> impl futures::Future<Item=HttpResponse, Error=Error> {
    ///     futures::future::ok(HttpResponse::Ok().finish())
    /// }
    ///
    /// App::new().service(web::resource("/").route(
    ///     web::to_async(index))
    /// );
    /// ```
    pub fn to_async<F, I, R, P: 'static>(handler: F) -> Route

    where
        F: AsyncFactory,
        I: FromRequest
 + 'static,
        R: IntoFuture + 'static,
        R::Item: Into<Response>,
        R::Error: Into<Error>,
    {
        Route::new().to_async(handler)
    }

    /// Execute blocking function on a thread pool, returns future that resolves
    /// to result of the function execution.
    pub fn blocking<F, I, E>(f: F) -> CpuFuture
    where
        F: FnOnce() -> Result + Send + 'static,
        I: Send + 'static,
        E: Send + std::fmt::Debug + 'static,
    {
        crate::blocking::run(f)
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::net::TcpListener;
use std::sync::mpsc;
use std::time::Duration;

use base::{error, info, Tube, TubeError};

use sync::Mutex;
use vm_control::{
    VcpuControl, VcpuDebug, VcpuDebugStatus, VcpuDebugStatusMessage, VmRequest, VmResponse,
};
use vm_memory::GuestAddress;

use gdbstub::arch::Arch;
use gdbstub::target::ext::base::singlethread::{ResumeAction, SingleThreadOps, StopReason};
use gdbstub::target::ext::base::{BaseOps, GdbInterrupt};
use gdbstub::target::ext::breakpoints::{Breakpoints, BreakpointsOps, HwBreakpoint};
use gdbstub::target::TargetError::NonFatal;
use gdbstub::target::{Target, TargetResult};
use gdbstub::Connection;
#[cfg(target_arch = "x86_64")]
use gdbstub_arch::x86::X86_64_SSE as GdbArch;
use remain::sorted;
use thiserror::Error as ThisError;

#[cfg(target_arch = "x86_64")]
type ArchUsize = u64;

pub fn gdb_thread(mut gdbstub: GdbStub, port: u32) {
    let addr = format!("0.0.0.0:{}", port);
    let listener = match TcpListener::bind(addr.clone()) {
        Ok(s) => s,
        Err(e) => {
            error!("Failed to create a TCP listener: {}", e);
            return;
        }
    };
    info!("Waiting for a GDB connection on {:?}...", addr);

    let (stream, addr) = match listener.accept() {
        Ok(v) => v,
        Err(e) => {
            error!("Failed to accept a connection from GDB: {}", e);
            return;
        }
    };
    info!("GDB connected from {}", addr);

    let connection: Box<dyn Connection<Error = std::io::Error>> = Box::new(stream);
    let mut gdb = gdbstub::GdbStub::new(connection);

    match gdb.run(&mut gdbstub) {
        Ok(reason) => {
            info!("GDB session closed: {:?}", reason);
        }
        Err(e) => {
            error!("error occurred in GDB session: {}", e);
        }
    }

    // Resume the VM when GDB session is disconnected.
    if let Err(e) = gdbstub.vm_request(VmRequest::Resume) {
        error!("Failed to resume the VM after GDB disconnected: {}", e);
    }
}

#[sorted]
#[derive(ThisError, Debug)]
enum Error {
    /// Got an unexpected VM response.
    #[error("Got an unexpected VM response: {0}")]
    UnexpectedVmResponse(VmResponse),
    /// Failed to send a vCPU request.
    #[error("failed to send a vCPU request: {0}")]
    VcpuRequest(mpsc::SendError<VcpuControl>),
    /// Failed to receive a vCPU response.
    #[error("failed to receive a vCPU response: {0}")]
    VcpuResponse(mpsc::RecvTimeoutError),
    /// Failed to send a VM request.
    #[error("failed to send a VM request: {0}")]
    VmRequest(TubeError),
    /// Failed to receive a VM request.
    #[error("failed to receive a VM response: {0}")]
    VmResponse(TubeError),
}
type GdbResult<T> = std::result::Result<T, Error>;

pub struct GdbStub {
    vm_tube: Mutex<Tube>,
    vcpu_com: Vec<mpsc::Sender<VcpuControl>>,
    from_vcpu: mpsc::Receiver<VcpuDebugStatusMessage>,

    hw_breakpoints: Vec<GuestAddress>,
}

impl GdbStub {
    pub fn new(
        vm_tube: Tube,
        vcpu_com: Vec<mpsc::Sender<VcpuControl>>,
        from_vcpu: mpsc::Receiver<VcpuDebugStatusMessage>,
    ) -> Self {
        GdbStub {
            vm_tube: Mutex::new(vm_tube),
            vcpu_com,
            from_vcpu,
            hw_breakpoints: Default::default(),
        }
    }

    fn vcpu_request(&self, request: VcpuControl) -> GdbResult<VcpuDebugStatus> {
        // We use the only one vCPU when GDB is enabled.
        self.vcpu_com[0].send(request).map_err(Error::VcpuRequest)?;

        match self.from_vcpu.recv_timeout(Duration::from_millis(500)) {
            Ok(msg) => Ok(msg.msg),
            Err(e) => Err(Error::VcpuResponse(e)),
        }
    }

    fn vm_request(&self, request: VmRequest) -> GdbResult<()> {
        let vm_tube = self.vm_tube.lock();
        vm_tube.send(&request).map_err(Error::VmRequest)?;
        match vm_tube.recv() {
            Ok(VmResponse::Ok) => Ok(()),
            Ok(r) => Err(Error::UnexpectedVmResponse(r)),
            Err(e) => Err(Error::VmResponse(e)),
        }
    }
}

impl Target for GdbStub {
    // TODO(keiichiw): Replace `()` with `X86_64CoreRegId` when we update the gdbstub crate.
    type Arch = GdbArch<()>;
    type Error = &'static str;

    fn base_ops(&mut self) -> BaseOps<Self::Arch, Self::Error> {
        BaseOps::SingleThread(self)
    }

    // TODO(keiichiw): sw_breakpoint, hw_watchpoint, extended_mode, monitor_cmd, section_offsets
    fn breakpoints(&mut self) -> Option<BreakpointsOps<Self>> {
        Some(self)
    }
}

impl SingleThreadOps for GdbStub {
    fn resume(
        &mut self,
        action: ResumeAction,
        check_gdb_interrupt: GdbInterrupt,
    ) -> Result<StopReason<ArchUsize>, Self::Error> {
        let single_step = ResumeAction::Step == action;

        if single_step {
            match self.vcpu_request(VcpuControl::Debug(VcpuDebug::EnableSinglestep)) {
                Ok(VcpuDebugStatus::CommandComplete) => {}
                Ok(s) => {
                    error!("Unexpected vCPU response for EnableSinglestep: {:?}", s);
                    return Err("Unexpected vCPU response for EnableSinglestep");
                }
                Err(e) => {
                    error!("Failed to request EnableSinglestep: {}", e);
                    return Err("Failed to request EnableSinglestep");
                }
            };
        }

        self.vm_request(VmRequest::Resume).map_err(|e| {
            error!("Failed to resume the target: {}", e);
            "Failed to resume the target"
        })?;

        let mut check_gdb_interrupt = check_gdb_interrupt.no_async();
        // Polling
        loop {
            // TODO(keiichiw): handle error?
            if let Ok(msg) = self
                .from_vcpu
                .recv_timeout(std::time::Duration::from_millis(100))
            {
                match msg.msg {
                    VcpuDebugStatus::HitBreakPoint => {
                        if single_step {
                            return Ok(StopReason::DoneStep);
                        } else {
                            return Ok(StopReason::HwBreak);
                        }
                    }
                    status => {
                        error!("Unexpected VcpuDebugStatus: {:?}", status);
                    }
                }
            }

            if check_gdb_interrupt.pending() {
                self.vm_request(VmRequest::Suspend).map_err(|e| {
                    error!("Failed to suspend the target: {}", e);
                    "Failed to suspend the target"
                })?;
                return Ok(StopReason::GdbInterrupt);
            }
        }
    }

    fn read_registers(
        &mut self,
        regs: &mut <Self::Arch as Arch>::Registers,
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::ReadRegs)) {
            Ok(VcpuDebugStatus::RegValues(r)) => {
                *regs = r;
                Ok(())
            }
            Ok(s) => {
                error!("Unexpected vCPU response for ReadRegs: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request ReadRegs: {}", e);
                Err(NonFatal)
            }
        }
    }

    fn write_registers(
        &mut self,
        regs: &<Self::Arch as Arch>::Registers,
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::WriteRegs(Box::new(
            regs.clone(),
        )))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(()),
            Ok(s) => {
                error!("Unexpected vCPU response for WriteRegs: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request WriteRegs: {}", e);
                Err(NonFatal)
            }
        }
    }

    fn read_addrs(
        &mut self,
        start_addr: <Self::Arch as Arch>::Usize,
        data: &mut [u8],
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::ReadMem(
            GuestAddress(start_addr),
            data.len(),
        ))) {
            Ok(VcpuDebugStatus::MemoryRegion(r)) => {
                for (dst, v) in data.iter_mut().zip(r.iter()) {
                    *dst = *v;
                }
                Ok(())
            }
            Ok(s) => {
                error!("Unexpected vCPU response for ReadMem: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request ReadMem: {}", e);
                Err(NonFatal)
            }
        }
    }

    fn write_addrs(
        &mut self,
        start_addr: <Self::Arch as Arch>::Usize,
        data: &[u8],
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::WriteMem(
            GuestAddress(start_addr),
            data.to_owned(),
        ))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(()),
            Ok(s) => {
                error!("Unexpected vCPU response for WriteMem: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request WriteMem: {}", e);
                Err(NonFatal)
            }
        }
    }
}

impl HwBreakpoint for GdbStub {
    /// Add a new hardware breakpoint.
    /// Return `Ok(false)` if the operation could not be completed.
    fn add_hw_breakpoint(
        &mut self,
        addr: <Self::Arch as Arch>::Usize,
        _kind: <Self::Arch as Arch>::BreakpointKind,
    ) -> TargetResult<bool, Self> {
        // If we already have 4 breakpoints, we cannot set a new one.
        if self.hw_breakpoints.len() >= 4 {
            error!("Not allowed to set more than 4 HW breakpoints");
            return Err(NonFatal);
        }
        self.hw_breakpoints.push(GuestAddress(addr));

        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::SetHwBreakPoint(
            self.hw_breakpoints.clone(),
        ))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(true),
            Ok(s) => {
                error!("Unexpected vCPU response for SetHwBreakPoint: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request SetHwBreakPoint: {}", e);
                Err(NonFatal)
            }
        }
    }

    /// Remove an existing hardware breakpoint.
    /// Return `Ok(false)` if the operation could not be completed.
    fn remove_hw_breakpoint(
        &mut self,
        addr: <Self::Arch as Arch>::Usize,
        _kind: <Self::Arch as Arch>::BreakpointKind,
    ) -> TargetResult<bool, Self> {
        self.hw_breakpoints.retain(|&b| b.0 != addr);

        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::SetHwBreakPoint(
            self.hw_breakpoints.clone(),
        ))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(true),
            Ok(s) => {
                error!("Unexpected vCPU response for SetHwBreakPoint: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request SetHwBreakPoint: {}", e);
                Err(NonFatal)
            }
        }
    }
}

impl Breakpoints for GdbStub {}
<commit_msg>Add missing HwBreakpointOps impl to GdbStub<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::net::TcpListener;
use std::sync::mpsc;
use std::time::Duration;

use base::{error, info, Tube, TubeError};

use sync::Mutex;
use vm_control::{
    VcpuControl, VcpuDebug, VcpuDebugStatus, VcpuDebugStatusMessage, VmRequest, VmResponse,
};
use vm_memory::GuestAddress;

use gdbstub::arch::Arch;
use gdbstub::target::ext::base::singlethread::{ResumeAction, SingleThreadOps, StopReason};
use gdbstub::target::ext::base::{BaseOps, GdbInterrupt};
use gdbstub::target::ext::breakpoints::{
    Breakpoints, BreakpointsOps, HwBreakpoint, HwBreakpointOps,
};
use gdbstub::target::TargetError::NonFatal;
use gdbstub::target::{Target, TargetResult};
use gdbstub::Connection;
#[cfg(target_arch = "x86_64")]
use gdbstub_arch::x86::X86_64_SSE as GdbArch;
use remain::sorted;
use thiserror::Error as ThisError;

#[cfg(target_arch = "x86_64")]
type ArchUsize = u64;

pub fn gdb_thread(mut gdbstub: GdbStub, port: u32) {
    let addr = format!("0.0.0.0:{}", port);
    let listener = match TcpListener::bind(addr.clone()) {
        Ok(s) => s,
        Err(e) => {
            error!("Failed to create a TCP listener: {}", e);
            return;
        }
    };
    info!("Waiting for a GDB connection on {:?}...", addr);

    let (stream, addr) = match listener.accept() {
        Ok(v) => v,
        Err(e) => {
            error!("Failed to accept a connection from GDB: {}", e);
            return;
        }
    };
    info!("GDB connected from {}", addr);

    let connection: Box<dyn Connection<Error = std::io::Error>> = Box::new(stream);
    let mut gdb = gdbstub::GdbStub::new(connection);

    match gdb.run(&mut gdbstub) {
        Ok(reason) => {
            info!("GDB session closed: {:?}", reason);
        }
        Err(e) => {
            error!("error occurred in GDB session: {}", e);
        }
    }

    // Resume the VM when GDB session is disconnected.
    if let Err(e) = gdbstub.vm_request(VmRequest::Resume) {
        error!("Failed to resume the VM after GDB disconnected: {}", e);
    }
}

#[sorted]
#[derive(ThisError, Debug)]
enum Error {
    /// Got an unexpected VM response.
    #[error("Got an unexpected VM response: {0}")]
    UnexpectedVmResponse(VmResponse),
    /// Failed to send a vCPU request.
    #[error("failed to send a vCPU request: {0}")]
    VcpuRequest(mpsc::SendError<VcpuControl>),
    /// Failed to receive a vCPU response.
    #[error("failed to receive a vCPU response: {0}")]
    VcpuResponse(mpsc::RecvTimeoutError),
    /// Failed to send a VM request.
    #[error("failed to send a VM request: {0}")]
    VmRequest(TubeError),
    /// Failed to receive a VM request.
    #[error("failed to receive a VM response: {0}")]
    VmResponse(TubeError),
}
type GdbResult<T> = std::result::Result<T, Error>;

pub struct GdbStub {
    vm_tube: Mutex<Tube>,
    vcpu_com: Vec<mpsc::Sender<VcpuControl>>,
    from_vcpu: mpsc::Receiver<VcpuDebugStatusMessage>,

    hw_breakpoints: Vec<GuestAddress>,
}

impl GdbStub {
    pub fn new(
        vm_tube: Tube,
        vcpu_com: Vec<mpsc::Sender<VcpuControl>>,
        from_vcpu: mpsc::Receiver<VcpuDebugStatusMessage>,
    ) -> Self {
        GdbStub {
            vm_tube: Mutex::new(vm_tube),
            vcpu_com,
            from_vcpu,
            hw_breakpoints: Default::default(),
        }
    }

    fn vcpu_request(&self, request: VcpuControl) -> GdbResult<VcpuDebugStatus> {
        // We use the only one vCPU when GDB is enabled.
        self.vcpu_com[0].send(request).map_err(Error::VcpuRequest)?;

        match self.from_vcpu.recv_timeout(Duration::from_millis(500)) {
            Ok(msg) => Ok(msg.msg),
            Err(e) => Err(Error::VcpuResponse(e)),
        }
    }

    fn vm_request(&self, request: VmRequest) -> GdbResult<()> {
        let vm_tube = self.vm_tube.lock();
        vm_tube.send(&request).map_err(Error::VmRequest)?;
        match vm_tube.recv() {
            Ok(VmResponse::Ok) => Ok(()),
            Ok(r) => Err(Error::UnexpectedVmResponse(r)),
            Err(e) => Err(Error::VmResponse(e)),
        }
    }
}

impl Target for GdbStub {
    // TODO(keiichiw): Replace `()` with `X86_64CoreRegId` when we update the gdbstub crate.
    type Arch = GdbArch<()>;
    type Error = &'static str;

    fn base_ops(&mut self) -> BaseOps<Self::Arch, Self::Error> {
        BaseOps::SingleThread(self)
    }

    // TODO(keiichiw): sw_breakpoint, hw_watchpoint, extended_mode, monitor_cmd, section_offsets
    fn breakpoints(&mut self) -> Option<BreakpointsOps<Self>> {
        Some(self)
    }
}

impl SingleThreadOps for GdbStub {
    fn resume(
        &mut self,
        action: ResumeAction,
        check_gdb_interrupt: GdbInterrupt,
    ) -> Result<StopReason<ArchUsize>, Self::Error> {
        let single_step = ResumeAction::Step == action;

        if single_step {
            match self.vcpu_request(VcpuControl::Debug(VcpuDebug::EnableSinglestep)) {
                Ok(VcpuDebugStatus::CommandComplete) => {}
                Ok(s) => {
                    error!("Unexpected vCPU response for EnableSinglestep: {:?}", s);
                    return Err("Unexpected vCPU response for EnableSinglestep");
                }
                Err(e) => {
                    error!("Failed to request EnableSinglestep: {}", e);
                    return Err("Failed to request EnableSinglestep");
                }
            };
        }

        self.vm_request(VmRequest::Resume).map_err(|e| {
            error!("Failed to resume the target: {}", e);
            "Failed to resume the target"
        })?;

        let mut check_gdb_interrupt = check_gdb_interrupt.no_async();
        // Polling
        loop {
            // TODO(keiichiw): handle error?
            if let Ok(msg) = self
                .from_vcpu
                .recv_timeout(std::time::Duration::from_millis(100))
            {
                match msg.msg {
                    VcpuDebugStatus::HitBreakPoint => {
                        if single_step {
                            return Ok(StopReason::DoneStep);
                        } else {
                            return Ok(StopReason::HwBreak);
                        }
                    }
                    status => {
                        error!("Unexpected VcpuDebugStatus: {:?}", status);
                    }
                }
            }

            if check_gdb_interrupt.pending() {
                self.vm_request(VmRequest::Suspend).map_err(|e| {
                    error!("Failed to suspend the target: {}", e);
                    "Failed to suspend the target"
                })?;
                return Ok(StopReason::GdbInterrupt);
            }
        }
    }

    fn read_registers(
        &mut self,
        regs: &mut <Self::Arch as Arch>::Registers,
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::ReadRegs)) {
            Ok(VcpuDebugStatus::RegValues(r)) => {
                *regs = r;
                Ok(())
            }
            Ok(s) => {
                error!("Unexpected vCPU response for ReadRegs: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request ReadRegs: {}", e);
                Err(NonFatal)
            }
        }
    }

    fn write_registers(
        &mut self,
        regs: &<Self::Arch as Arch>::Registers,
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::WriteRegs(Box::new(
            regs.clone(),
        )))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(()),
            Ok(s) => {
                error!("Unexpected vCPU response for WriteRegs: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request WriteRegs: {}", e);
                Err(NonFatal)
            }
        }
    }

    fn read_addrs(
        &mut self,
        start_addr: <Self::Arch as Arch>::Usize,
        data: &mut [u8],
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::ReadMem(
            GuestAddress(start_addr),
            data.len(),
        ))) {
            Ok(VcpuDebugStatus::MemoryRegion(r)) => {
                for (dst, v) in data.iter_mut().zip(r.iter()) {
                    *dst = *v;
                }
                Ok(())
            }
            Ok(s) => {
                error!("Unexpected vCPU response for ReadMem: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request ReadMem: {}", e);
                Err(NonFatal)
            }
        }
    }

    fn write_addrs(
        &mut self,
        start_addr: <Self::Arch as Arch>::Usize,
        data: &[u8],
    ) -> TargetResult<(), Self> {
        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::WriteMem(
            GuestAddress(start_addr),
            data.to_owned(),
        ))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(()),
            Ok(s) => {
                error!("Unexpected vCPU response for WriteMem: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request WriteMem: {}", e);
                Err(NonFatal)
            }
        }
    }
}

impl Breakpoints for GdbStub {
    fn hw_breakpoint(&mut self) -> Option<HwBreakpointOps<Self>> {
        Some(self)
    }
}

impl HwBreakpoint for GdbStub {
    /// Add a new hardware breakpoint.
    /// Return `Ok(false)` if the operation could not be completed.
    fn add_hw_breakpoint(
        &mut self,
        addr: <Self::Arch as Arch>::Usize,
        _kind: <Self::Arch as Arch>::BreakpointKind,
    ) -> TargetResult<bool, Self> {
        // If we already have 4 breakpoints, we cannot set a new one.
        if self.hw_breakpoints.len() >= 4 {
            error!("Not allowed to set more than 4 HW breakpoints");
            return Err(NonFatal);
        }
        self.hw_breakpoints.push(GuestAddress(addr));

        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::SetHwBreakPoint(
            self.hw_breakpoints.clone(),
        ))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(true),
            Ok(s) => {
                error!("Unexpected vCPU response for SetHwBreakPoint: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request SetHwBreakPoint: {}", e);
                Err(NonFatal)
            }
        }
    }

    /// Remove an existing hardware breakpoint.
    /// Return `Ok(false)` if the operation could not be completed.
    fn remove_hw_breakpoint(
        &mut self,
        addr: <Self::Arch as Arch>::Usize,
        _kind: <Self::Arch as Arch>::BreakpointKind,
    ) -> TargetResult<bool, Self> {
        self.hw_breakpoints.retain(|&b| b.0 != addr);

        match self.vcpu_request(VcpuControl::Debug(VcpuDebug::SetHwBreakPoint(
            self.hw_breakpoints.clone(),
        ))) {
            Ok(VcpuDebugStatus::CommandComplete) => Ok(true),
            Ok(s) => {
                error!("Unexpected vCPU response for SetHwBreakPoint: {:?}", s);
                Err(NonFatal)
            }
            Err(e) => {
                error!("Failed to request SetHwBreakPoint: {}", e);
                Err(NonFatal)
            }
        }
    }
}
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/cookie")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/cookie")]
#![crate_name = "cookie"]
#![deny(missing_doc)]
#![feature(phase)]
#![feature(globs)]

//! Cookie parsing/setting middleware for the [iron](https://github.com/iron/iron) framework.

extern crate time;
extern crate rustc;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate url;
extern crate serialize;
extern crate iron;
extern crate http;
extern crate "rust-crypto" as crypto;
#[cfg(test)]
extern crate "iron-test" as test;

pub use cookie::Cookie;
pub use parser::CookieParser;
pub use response::SetCookie;
pub use response::HeaderCollection;

mod parser;
mod response;
mod cookie;
<commit_msg>Update lib.rs<commit_after>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/cookie")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/cookie")]
#![crate_name = "cookie"]
#![deny(missing_doc)]
#![feature(phase)]
#![feature(globs)]

//! Cookie parsing/setting middleware for the [iron](https://github.com/iron/iron) framework.

extern crate time;
extern crate rustc;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate url;
extern crate serialize;
extern crate iron;
extern crate http;
extern crate rust-crypto as crypto;
#[cfg(test)]
extern crate iron-test as test;

pub use cookie::Cookie;
pub use parser::CookieParser;
pub use response::SetCookie;
pub use response::HeaderCollection;

mod parser;
mod response;
mod cookie;
<|endoftext|>