<commit_before>#[macro_use]
extern crate derive_builder;

mod field_level {
    #[derive(Debug, PartialEq, Default, Builder, Clone)]
    struct Lorem {
        required: String,
        #[builder(default)]
        explicit_default: String,
        #[builder(default="\"foo\".to_string()")]
        escaped_default: String,
        #[builder(default=r#"format!("Hello {}!", "World")"#)]
        raw_default: String,
        #[builder(default=r#"format!("{}-{}-{}-{}",
                             Clone::clone(self.required
                                .as_ref()
                                .ok_or("required must be initialized")?),
                             match self.explicit_default { Some(ref x) => x, None => "EMPTY" },
                             self.escaped_default.as_ref().map(|x| x.as_ref()).unwrap_or("EMPTY"),
                             if let Some(ref x) = self.raw_default { x } else { "EMPTY" })"#)]
        computed_default: String,
    }

    #[test]
    #[should_panic(expected="`required` must be initialized")]
    fn panic_if_uninitialized() {
        LoremBuilder::default().build().unwrap();
    }

    #[test]
    fn custom_default() {
        let x = LoremBuilder::default()
            .required("ipsum".to_string())
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            required: "ipsum".to_string(),
            explicit_default: "".to_string(),
            escaped_default: "foo".to_string(),
            raw_default: "Hello World!".to_string(),
            computed_default: "ipsum-EMPTY-EMPTY-EMPTY".to_string(),
        });
    }

    #[test]
    fn builder() {
        let x = LoremBuilder::default()
            .required("ipsum".to_string())
            .explicit_default("lorem".to_string())
            .escaped_default("dolor".to_string())
            .raw_default("sit".to_string())
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            required: "ipsum".to_string(),
            explicit_default: "lorem".to_string(),
            escaped_default: "dolor".to_string(),
            raw_default: "sit".to_string(),
            computed_default: "ipsum-lorem-dolor-sit".to_string(),
        });
    }
}

mod struct_level {
    #[derive(Debug, PartialEq, Default, Builder, Clone)]
    #[builder(default)]
    struct Lorem {
        implicit_default: String,
        #[builder(default)]
        explicit_default: String,
        #[builder(default="\"foo\".to_string()")]
        escaped_default: String,
        #[builder(default=r#"format!("Hello {}!", "World")"#)]
        raw_default: String,
    }

    #[test]
    fn implicit_default() {
        let x = LoremBuilder::default()
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            implicit_default: "".to_string(),
            explicit_default: "".to_string(),
            escaped_default: "foo".to_string(),
            raw_default: "Hello World!".to_string(),
        });
    }

    #[test]
    fn builder() {
        let x = LoremBuilder::default()
            .implicit_default("ipsum".to_string())
            .explicit_default("lorem".to_string())
            .escaped_default("dolor".to_string())
            .raw_default("sit".to_string())
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            implicit_default: "ipsum".to_string(),
            explicit_default: "lorem".to_string(),
            escaped_default: "dolor".to_string(),
            raw_default: "sit".to_string(),
        });
    }
}

mod struct_impl {
    #[derive(Debug, Clone, PartialEq, Eq, Builder)]
    #[builder(default)]
    struct Ipsum {
        not_type_default: Option<u16>,
        also_custom: bool,
        is_type_default: String,
    }

    impl Default for Ipsum {
        fn default() -> Self {
            Ipsum {
                not_type_default: Some(20),
                also_custom: true,
                is_type_default: Default::default(),
            }
        }
    }

    #[test]
    fn defaults_are_equal() {
        assert_eq!(Ok(Ipsum::default()), IpsumBuilder::default().build());
    }

    #[test]
    fn overrides_work() {
        let ipsum = IpsumBuilder::default()
            .not_type_default(None)
            .build()
            .expect("Struct-level default makes all fields optional");
        assert_eq!(None, ipsum.not_type_default);
    }
}<commit_msg>Only run new test when feature enabled<commit_after>#[macro_use]
extern crate derive_builder;

mod field_level {
    #[derive(Debug, PartialEq, Default, Builder, Clone)]
    struct Lorem {
        required: String,
        #[builder(default)]
        explicit_default: String,
        #[builder(default="\"foo\".to_string()")]
        escaped_default: String,
        #[builder(default=r#"format!("Hello {}!", "World")"#)]
        raw_default: String,
        #[builder(default=r#"format!("{}-{}-{}-{}",
                             Clone::clone(self.required
                                .as_ref()
                                .ok_or("required must be initialized")?),
                             match self.explicit_default { Some(ref x) => x, None => "EMPTY" },
                             self.escaped_default.as_ref().map(|x| x.as_ref()).unwrap_or("EMPTY"),
                             if let Some(ref x) = self.raw_default { x } else { "EMPTY" })"#)]
        computed_default: String,
    }

    #[test]
    #[should_panic(expected="`required` must be initialized")]
    fn panic_if_uninitialized() {
        LoremBuilder::default().build().unwrap();
    }

    #[test]
    fn custom_default() {
        let x = LoremBuilder::default()
            .required("ipsum".to_string())
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            required: "ipsum".to_string(),
            explicit_default: "".to_string(),
            escaped_default: "foo".to_string(),
            raw_default: "Hello World!".to_string(),
            computed_default: "ipsum-EMPTY-EMPTY-EMPTY".to_string(),
        });
    }

    #[test]
    fn builder() {
        let x = LoremBuilder::default()
            .required("ipsum".to_string())
            .explicit_default("lorem".to_string())
            .escaped_default("dolor".to_string())
            .raw_default("sit".to_string())
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            required: "ipsum".to_string(),
            explicit_default: "lorem".to_string(),
            escaped_default: "dolor".to_string(),
            raw_default: "sit".to_string(),
            computed_default: "ipsum-lorem-dolor-sit".to_string(),
        });
    }
}

mod struct_level {
    #[derive(Debug, PartialEq, Default, Builder, Clone)]
    #[builder(default)]
    struct Lorem {
        implicit_default: String,
        #[builder(default)]
        explicit_default: String,
        #[builder(default="\"foo\".to_string()")]
        escaped_default: String,
        #[builder(default=r#"format!("Hello {}!", "World")"#)]
        raw_default: String,
    }

    #[test]
    fn implicit_default() {
        let x = LoremBuilder::default()
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            implicit_default: "".to_string(),
            explicit_default: "".to_string(),
            escaped_default: "foo".to_string(),
            raw_default: "Hello World!".to_string(),
        });
    }

    #[test]
    fn builder() {
        let x = LoremBuilder::default()
            .implicit_default("ipsum".to_string())
            .explicit_default("lorem".to_string())
            .escaped_default("dolor".to_string())
            .raw_default("sit".to_string())
            .build()
            .unwrap();

        assert_eq!(x, Lorem {
            implicit_default: "ipsum".to_string(),
            explicit_default: "lorem".to_string(),
            escaped_default: "dolor".to_string(),
            raw_default: "sit".to_string(),
        });
    }
}

mod struct_impl {
    #[derive(Debug, Clone, PartialEq, Eq, Builder)]
    #[builder(default)]
    struct Ipsum {
        not_type_default: Option<u16>,
        also_custom: bool,
        is_type_default: String,
    }

    impl Default for Ipsum {
        fn default() -> Self {
            Ipsum {
                not_type_default: Some(20),
                also_custom: true,
                is_type_default: Default::default(),
            }
        }
    }

    #[test]
    #[cfg(feature = "struct_default")]
    fn defaults_are_equal() {
        assert_eq!(Ok(Ipsum::default()), IpsumBuilder::default().build());
    }

    #[test]
    fn overrides_work() {
        let ipsum = IpsumBuilder::default()
            .not_type_default(None)
            .build()
            .expect("Struct-level default makes all fields optional");
        assert_eq!(None, ipsum.not_type_default);
    }
}<|endoftext|>


<commit_before><commit_msg>sys_util: netlink: implement AsRawDescriptor for netlink generic socket<commit_after><|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 , Unscoped
                                 };
use core::semantic::types::*;
use core::semantic::ast::*;
use core::position::*;

use std::rc::Rc;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Unicode code point for the lambda character
const LAMBDA: &'static str = "\u{03bb}";

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

    /// Wrap a function into a MnParser with this environment
    fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                -> MnParser<'a, 'b, I, T> {
        MnParser { env: self, parser: parser }
    }

    #[allow(dead_code)]
    fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        let function_form
            = self.name()
                  .and(self.function())
                  .map(|(name, fun)| DefForm::Function { name: name
                                                       , fun: fun });
        let top_level
            = self.name()
                  .and(self.type_annotation())
                  .and(self.expr())
                  .map(|((name, ty), body)|
                    DefForm::TopLevel { name: name
                                      , annot: ty
                                      , value: Rc::new(body) });

        self.reserved("defn").or(self.reserved("define"))
            .with(function_form.or(top_level))
            .map(Form::Define)
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        self.reserved("if")
            .with(self.expr())
            .and(self.expr())
            .and(optional(self.expr()))
            .map(|((cond, if_clause), else_clause)|
                Form::If { condition: Rc::new(cond)
                         , if_clause: Rc::new(if_clause)
                         , else_clause: else_clause.map(Rc::new)
                         })
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        self.reserved("lambda")
            .or(self.reserved(LAMBDA))
            .with(self.function())
            .map(Form::Lambda)
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_function(&self, input: State<I>) -> ParseResult<Function<'a, U>, I> {
        unimplemented!()
    }

    #[allow(dead_code)]
    fn parse_primitive_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        choice([ self.reserved("int")
                     .with(value(Primitive::IntSize))
               , self.reserved("uint")
                     .with(value(Primitive::IntSize))
               , self.reserved("float")
                     .with(value(Primitive::Float))
               , self.reserved("double")
                     .with(value(Primitive::Double))
               , self.reserved("bool")
                     .with(value(Primitive::Bool))
               , self.reserved("i8")
                     .with(value(Primitive::Int(Int::Int8)))
               , self.reserved("i16")
                     .with(value(Primitive::Int(Int::Int16)))
               , self.reserved("i32")
                    .with(value(Primitive::Int(Int::Int32)))
               , self.reserved("i64")
                     .with(value(Primitive::Int(Int::Int64)))
              , self.reserved("u8")
                    .with(value(Primitive::Uint(Int::Int8)))
              , self.reserved("u16")
                    .with(value(Primitive::Uint(Int::Int16)))
              , self.reserved("u32")
                    .with(value(Primitive::Uint(Int::Int32)))
              , self.reserved("u64")
                    .with(value(Primitive::Uint(Int::Int64)))
               ])
               .map(|primitive| Type::Prim(primitive))
               .parse_state(input)
    }

    fn raw_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        char('*').with(self.type_annotation())
                 .map(|t| Type::Ref(Reference::Raw(Rc::new(t))))
                 .parse_state(input)
    }

    fn unique_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        char('@').with(self.type_annotation())
                 .map(|t| Type::Ref(Reference::Unique(Rc::new(t))))
                 .parse_state(input)
    }

    fn borrow_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        char('&').with(self.type_annotation())
                 .map(|t| Type::Ref(Reference::Borrowed(Rc::new(t))))
                 .parse_state(input)
    }
    fn parse_type(&self, input: State<I>) -> ParseResult<Type, I> {
        choice([ self.parser(MnEnv::parse_primitive_ty)
               , self.parser(MnEnv::raw_ptr_ty)
               , self.parser(MnEnv::unique_ptr_ty)
               , self.parser(MnEnv::borrow_ptr_ty)
               ])
            .parse_state(input)
    }

    fn parse_binding(&self, input: State<I>)
                    -> ParseResult<Unscoped<'a, Binding<'a, U>>, I> {
        let pos = input.position.clone();
        self.parser(MnEnv::parse_name)
            .and(self.type_annotation())
            .and(self.expr())
            .map(|((name, typ), value)|
                Annotated::new( Binding { name: name
                                        , typ: typ
                                        , value: Rc::new(value)
                                        }
                               , Position::from(pos)
                           ))
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_logical(&self, input: State<I>)
                    -> ParseResult<Logical<'a, U>, I> {
        let and = self.reserved("and")
                      .with(self.expr())
                      .and(self.expr())
                      .map(|(a, b)| Logical::And { a: Rc::new(a)
                                                 , b: Rc::new(b)
                                                 });

         let or = self.reserved("or")
                      .with(self.expr())
                      .and(self.expr())
                      .map(|(a, b)| Logical::And { a: Rc::new(a)
                                                 , b: Rc::new(b)
                                                 });

        and.or(or)
           .parse_state(input)
    }

    fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {

        let binding_form =
            self.reserved("let")
                .with(many(self.parens(self.binding())))
                .and(many(self.expr()))
                .map(|(bindings, body)| LetForm::Let { bindings: bindings
                                                     , body: body });

        choice([ binding_form ])
            .map(Form::Let)
            .parse_state(input)
    }

    fn parse_name (&self, input: State<I>) -> ParseResult<Ident, I> {
        let position = input.position.clone();
        self.env.identifier::<'b>()
            .map(|name| Positional { pos: Position::from(position)
                                   , value: name })
            .parse_state(input)
    }

    fn parse_call(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        self.name()
            .and(many(self.expr()))
            .map(|(name, args)| Form::Call { fun: name, body: args })
            .parse_state(input)
    }

    fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
        let pos = Position::from(input.position.clone());
        self.env
            .parens(choice([ self.def()
                           , self.if_form()
                           , self.lambda()
                           , self.let_form()
                           , self.call()
                           ]))
            .map(|f| Annotated::new(f, pos) )
            .parse_state(input)
    }

    fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
        self.parser(MnEnv::parse_expr)
    }

    fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_def)
    }

    fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_if)
    }

    fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_let)
    }

    fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_lambda)
    }

    fn call(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_call)
    }

    fn name(&'b self) -> MnParser<'a, 'b, I, Ident> {
        self.parser(MnEnv::parse_name)
    }

    fn binding(&'b self)
              -> MnParser< 'a, 'b, I, Unscoped<'a, Binding<'a, U>>> {
        self.parser(MnEnv::parse_binding)
    }

    fn type_annotation(&'b self) -> MnParser<'a, 'b, I, types::Type> {
        self.parser(MnEnv::parse_type)
    }

    fn function(&'b self) -> MnParser<'a, 'b, I, Function<'a, U>> {
        self.parser(MnEnv::parse_function)
    }

}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"      , LAMBDA
                      , "let"               , "let*"        , "letrec"
                      , "or"
                      , "quasiquote"        , "quote"       , "unquote"
                      , "set!"
                      , "unquote-splicing"
                      , "i8"                , "u8"
                      , "i16"               , "u16"
                      , "i32"               , "u32"         , "f32"
                      , "i64"               , "u64"         , "f64"
                      , "int"               , "uint"        , "float"
                      , "bool"                              , "double"
                      ].iter().map(|x| (*x).into())
                       .collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Main expr parser actually happens now<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 , Unscoped
                                 };
use core::semantic::types::*;
use core::semantic::ast::*;
use core::position::*;

use std::rc::Rc;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Unicode code point for the lambda character
const LAMBDA: &'static str = "\u{03bb}";

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

    /// Wrap a function into a MnParser with this environment
    fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                -> MnParser<'a, 'b, I, T> {
        MnParser { env: self, parser: parser }
    }

    #[allow(dead_code)]
    fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        let function_form
            = self.name()
                  .and(self.function())
                  .map(|(name, fun)| DefForm::Function { name: name
                                                       , fun: fun });
        let top_level
            = self.name()
                  .and(self.type_annotation())
                  .and(self.expr())
                  .map(|((name, ty), body)|
                    DefForm::TopLevel { name: name
                                      , annot: ty
                                      , value: Rc::new(body) });

        self.reserved("defn").or(self.reserved("define"))
            .with(function_form.or(top_level))
            .map(Form::Define)
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        self.reserved("if")
            .with(self.expr())
            .and(self.expr())
            .and(optional(self.expr()))
            .map(|((cond, if_clause), else_clause)|
                Form::If { condition: Rc::new(cond)
                         , if_clause: Rc::new(if_clause)
                         , else_clause: else_clause.map(Rc::new)
                         })
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        self.reserved("lambda")
            .or(self.reserved(LAMBDA))
            .with(self.function())
            .map(Form::Lambda)
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_function(&self, input: State<I>) -> ParseResult<Function<'a, U>, I> {
        unimplemented!()
    }

    #[allow(dead_code)]
    fn parse_primitive_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        choice([ self.reserved("int")
                     .with(value(Primitive::IntSize))
               , self.reserved("uint")
                     .with(value(Primitive::IntSize))
               , self.reserved("float")
                     .with(value(Primitive::Float))
               , self.reserved("double")
                     .with(value(Primitive::Double))
               , self.reserved("bool")
                     .with(value(Primitive::Bool))
               , self.reserved("i8")
                     .with(value(Primitive::Int(Int::Int8)))
               , self.reserved("i16")
                     .with(value(Primitive::Int(Int::Int16)))
               , self.reserved("i32")
                    .with(value(Primitive::Int(Int::Int32)))
               , self.reserved("i64")
                     .with(value(Primitive::Int(Int::Int64)))
              , self.reserved("u8")
                    .with(value(Primitive::Uint(Int::Int8)))
              , self.reserved("u16")
                    .with(value(Primitive::Uint(Int::Int16)))
              , self.reserved("u32")
                    .with(value(Primitive::Uint(Int::Int32)))
              , self.reserved("u64")
                    .with(value(Primitive::Uint(Int::Int64)))
               ])
               .map(|primitive| Type::Prim(primitive))
               .parse_state(input)
    }

    fn raw_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        char('*').with(self.type_annotation())
                 .map(|t| Type::Ref(Reference::Raw(Rc::new(t))))
                 .parse_state(input)
    }

    fn unique_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        char('@').with(self.type_annotation())
                 .map(|t| Type::Ref(Reference::Unique(Rc::new(t))))
                 .parse_state(input)
    }

    fn borrow_ptr_ty(&self, input: State<I>) -> ParseResult<Type, I> {
        char('&').with(self.type_annotation())
                 .map(|t| Type::Ref(Reference::Borrowed(Rc::new(t))))
                 .parse_state(input)
    }
    fn parse_type(&self, input: State<I>) -> ParseResult<Type, I> {
        choice([ self.parser(MnEnv::parse_primitive_ty)
               , self.parser(MnEnv::raw_ptr_ty)
               , self.parser(MnEnv::unique_ptr_ty)
               , self.parser(MnEnv::borrow_ptr_ty)
               ])
            .parse_state(input)
    }

    fn parse_binding(&self, input: State<I>)
                    -> ParseResult<Unscoped<'a, Binding<'a, U>>, I> {
        let pos = input.position.clone();
        self.parser(MnEnv::parse_name)
            .and(self.type_annotation())
            .and(self.expr())
            .map(|((name, typ), value)|
                Annotated::new( Binding { name: name
                                        , typ: typ
                                        , value: Rc::new(value)
                                        }
                               , Position::from(pos)
                           ))
            .parse_state(input)
    }

    #[allow(dead_code)]
    fn parse_logical(&self, input: State<I>)
                    -> ParseResult<Logical<'a, U>, I> {
        let and = self.reserved("and")
                      .with(self.expr())
                      .and(self.expr())
                      .map(|(a, b)| Logical::And { a: Rc::new(a)
                                                 , b: Rc::new(b)
                                                 });

         let or = self.reserved("or")
                      .with(self.expr())
                      .and(self.expr())
                      .map(|(a, b)| Logical::And { a: Rc::new(a)
                                                 , b: Rc::new(b)
                                                 });

        and.or(or)
           .parse_state(input)
    }

    fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {

        let binding_form =
            self.reserved("let")
                .with(many(self.parens(self.binding())))
                .and(many(self.expr()))
                .map(|(bindings, body)| LetForm::Let { bindings: bindings
                                                     , body: body });

        choice([ binding_form ])
            .map(Form::Let)
            .parse_state(input)
    }

    fn parse_name (&self, input: State<I>) -> ParseResult<Ident, I> {
        let position = input.position.clone();
        self.env.identifier::<'b>()
            .map(|name| Positional { pos: Position::from(position)
                                   , value: name })
            .parse_state(input)
    }

    fn parse_call(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        self.name()
            .and(many(self.expr()))
            .map(|(name, args)| Form::Call { fun: name, body: args })
            .parse_state(input)
    }

    fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
        let pos = Position::from(input.position.clone());
        self.env
            .parens(choice([ self.def()
                           , self.if_form()
                           , self.lambda()
                           , self.let_form()
                           , self.call()
                           ]))
            .map(|f| Annotated::new(f, pos) )
            .parse_state(input)
    }

    fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
        self.parser(MnEnv::parse_expr)
    }

    fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_def)
    }

    fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_if)
    }

    fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_let)
    }

    fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_lambda)
    }

    fn call(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
        self.parser(MnEnv::parse_call)
    }

    fn name(&'b self) -> MnParser<'a, 'b, I, Ident> {
        self.parser(MnEnv::parse_name)
    }

    fn binding(&'b self)
              -> MnParser< 'a, 'b, I, Unscoped<'a, Binding<'a, U>>> {
        self.parser(MnEnv::parse_binding)
    }

    fn type_annotation(&'b self) -> MnParser<'a, 'b, I, types::Type> {
        self.parser(MnEnv::parse_type)
    }

    fn function(&'b self) -> MnParser<'a, 'b, I, Function<'a, U>> {
        self.parser(MnEnv::parse_function)
    }

}
pub fn parse_module<'a>(code: &'a str)
                        -> Result< Vec<Expr<'a, UnscopedState>>
                                 , ParseError<&str>>
 {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(move |c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(move |c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"      , LAMBDA
                      , "let"               , "let*"        , "letrec"
                      , "or"
                      , "quasiquote"        , "quote"       , "unquote"
                      , "set!"              , "unquote-splicing"
                      , "i8"                , "u8"
                      , "i16"               , "u16"
                      , "i32"               , "u32"         , "f32"
                      , "i64"               , "u64"         , "f64"
                      , "int"               , "uint"        , "float"
                      , "bool"                              , "double"
                      ].iter().map(|x| (*x).into())
                       .collect()
        }
      , op: Identifier {
            start: satisfy(move |c| ops.contains(c))
          , rest:  satisfy(move |c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .with(many1::<Vec<Expr<'a, U>>, _>(env.expr()))
       .parse(code)
       .map(|(e, _)| e)
}
<|endoftext|>


<commit_before>use parking_lot::Mutex;
use scoped_threadpool::Pool;
use std::sync::Arc;

use ctxt::VM;
use driver::cmd::Args;
use gc::root::{get_rootset, Slot};
use gc::swiper::card::CardTable;
use gc::swiper::controller::{choose_collection_kind, resize_gens, HeapConfig, SharedHeapConfig};
use gc::swiper::crossing::CrossingMap;
use gc::swiper::full::FullCollector;
use gc::swiper::large::LargeSpace;
use gc::swiper::minor::MinorCollector;
use gc::swiper::old::OldGen;
use gc::swiper::verify::{Verifier, VerifierPhase};
use gc::swiper::young::YoungGen;
use gc::tlab;
use gc::Collector;
use gc::{arena, GcReason};
use gc::{formatted_size, Address, Region, K, M};
use mem;

pub mod card;
mod controller;
mod crossing;
mod full;
mod large;
mod marking;
mod minor;
pub mod old;
mod paged_old;
mod verify;
pub mod young;

// determines size of young generation in heap
// young generation size = heap size / YOUNG_RATIO
const YOUNG_RATIO: usize = 2;

// heap is divided into cards of size CARD_SIZE.
// card entry determines whether this part of the heap was modified
// in minor collections those parts of the heap need to be analyzed
pub const CARD_SIZE: usize = 512;
pub const CARD_SIZE_BITS: usize = 9;

pub const LARGE_OBJECT_SIZE: usize = 16 * K;

pub struct Swiper {
    // contiguous memory for young/old generation and large space
    heap: Region,

    // contains heap and also card table and crossing map
    reserved_area: Region,

    young: YoungGen,
    old: OldGen,
    large: LargeSpace,

    card_table: CardTable,
    crossing_map: CrossingMap,

    card_table_offset: usize,

    // minimum & maximum heap size
    min_heap_size: usize,
    max_heap_size: usize,

    threadpool: Mutex<Pool>,

    stats: GcStats,
    config: SharedHeapConfig,
}

impl Swiper {
    pub fn new(args: &Args) -> Swiper {
        let min_heap_size = args.min_heap_size();
        let max_heap_size = args.max_heap_size();

        let (eden_size, semi_size) = (12 * M, 8 * M);

        // determine size for card table
        let card_size = mem::page_align((4 * max_heap_size) >> CARD_SIZE_BITS);

        // determine size for crossing map
        let crossing_size = mem::page_align(max_heap_size >> CARD_SIZE_BITS);

        // determine full memory size
        let reserve_size = max_heap_size * 4 + card_size + crossing_size;

        // reserve full memory
        let ptr = arena::reserve(reserve_size);

        // heap is young/old generation & large space
        let heap_start = ptr;
        let heap_end = ptr.offset(4 * max_heap_size);

        // reserved area also contains card table & crossing map
        let reserved_area = heap_start.region_start(reserve_size);

        // determine offset to card table (card table starts right after heap)
        // offset = card_table_start - (heap_start >> CARD_SIZE_BITS)
        let card_table_offset = heap_end.to_usize() - (heap_start.to_usize() >> CARD_SIZE_BITS);

        // determine boundaries for card table
        let card_start = heap_end;
        let card_end = card_start.offset(card_size);

        arena::commit(card_start, card_size, false);

        // determine boundaries for crossing map
        let crossing_start = card_end;
        let crossing_end = crossing_start.offset(crossing_size);

        arena::commit(crossing_start, crossing_size, false);

        // determine boundaries of young generation
        let young_start = heap_start;
        let young_end = young_start.offset(max_heap_size);
        let young = Region::new(young_start, young_end);

        // determine boundaries of old generation
        let old_start = young_end;
        let old_end = old_start.offset(max_heap_size);

        let init_old_size = max_heap_size;
        let young_size = eden_size + semi_size;
        let config = HeapConfig::new(eden_size, semi_size, 0, init_old_size - young_size);
        let config = Arc::new(Mutex::new(config));

        // determine large object space
        let large_start = old_end;
        let large_end = large_start.offset(2 * max_heap_size);

        let card_table = CardTable::new(
            card_start,
            card_end,
            Region::new(old_start, large_end),
            old_end,
            max_heap_size,
        );
        let crossing_map = CrossingMap::new(crossing_start, crossing_end, max_heap_size);
        let young = YoungGen::new(young, eden_size, semi_size, args.flag_gc_verify);
        let old = OldGen::new(
            old_start,
            old_end,
            crossing_map.clone(),
            card_table.clone(),
            config.clone(),
        );
        let large = LargeSpace::new(large_start, large_end, config.clone());

        if args.flag_gc_verbose {
            println!(
                "GC: heap info: {}, eden {}, semi {}, card {}, crossing {}",
                formatted_size(max_heap_size),
                formatted_size(eden_size),
                formatted_size(semi_size),
                formatted_size(card_size),
                formatted_size(crossing_size)
            );
        }

        let nworkers = args.gc_workers();

        Swiper {
            heap: Region::new(heap_start, heap_end),
            reserved_area: reserved_area,

            young: young,
            old: old,
            large: large,

            card_table: card_table,
            crossing_map: crossing_map,
            config: config,

            card_table_offset: card_table_offset,

            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,

            threadpool: Mutex::new(Pool::new(nworkers as u32)),
            stats: GcStats::new(),
        }
    }

    fn perform_collection_and_choose(&self, vm: &VM, reason: GcReason) -> CollectionKind {
        let kind = choose_collection_kind(&self.config, &self.young);
        self.perform_collection(vm, kind, reason)
    }

    fn perform_collection(
        &self,
        vm: &VM,
        kind: CollectionKind,
        reason: GcReason,
    ) -> CollectionKind {
        let kind = match kind {
            CollectionKind::Minor => {
                let promotion_failed = self.minor_collect(vm, reason);

                if promotion_failed {
                    self.full_collect(vm, GcReason::PromotionFailure);
                    CollectionKind::Full
                } else {
                    CollectionKind::Minor
                }
            }

            CollectionKind::Full => {
                self.full_collect(vm, reason);
                CollectionKind::Full
            }
        };

        resize_gens(
            self.max_heap_size,
            &self.config,
            &self.young,
            &self.old,
            &self.large,
            vm.args.flag_gc_verbose,
        );

        kind
    }

    fn minor_collect(&self, vm: &VM, reason: GcReason) -> bool {
        // make heap iterable
        tlab::make_iterable(vm);
        let rootset = get_rootset(vm);

        self.verify(vm, VerifierPhase::PreMinor, "pre-minor", &rootset, false);
        let promotion_failed = {
            let mut pool = self.threadpool.lock();
            let mut collector = MinorCollector::new(
                vm,
                &self.young,
                &self.old,
                &self.large,
                &self.card_table,
                &self.crossing_map,
                &rootset,
                reason,
                self.min_heap_size,
                self.max_heap_size,
                &self.stats,
                &mut pool,
            );
            collector.collect()
        };
        self.verify(
            vm,
            VerifierPhase::PostMinor,
            "post-minor",
            &rootset,
            promotion_failed,
        );

        promotion_failed
    }

    fn full_collect(&self, vm: &VM, reason: GcReason) {
        // make heap iterable
        tlab::make_iterable(vm);

        let rootset = get_rootset(vm);

        self.verify(
            vm,
            VerifierPhase::PreFull,
            "pre-full",
            &rootset,
            reason == GcReason::PromotionFailure,
        );

        {
            let mut pool = self.threadpool.lock();
            let mut collector = FullCollector::new(
                vm,
                self.heap.clone(),
                &self.young,
                &self.old,
                &self.large,
                &self.card_table,
                &self.crossing_map,
                &vm.gc.perm_space,
                &rootset,
                reason,
                &mut pool,
                self.min_heap_size,
                self.max_heap_size,
                &self.stats,
            );
            collector.collect();
        }

        self.verify(vm, VerifierPhase::PostFull, "post-full", &rootset, false);
    }

    fn verify(
        &self,
        vm: &VM,
        phase: VerifierPhase,
        _name: &str,
        rootset: &[Slot],
        promotion_failed: bool,
    ) {
        if vm.args.flag_gc_verify {
            if vm.args.flag_gc_dev_verbose {
                println!("GC: Verify {}", _name);
            }

            let perm_space = &vm.gc.perm_space;

            let mut verifier = Verifier::new(
                &self.young,
                &self.old,
                &self.card_table,
                &self.crossing_map,
                rootset,
                &self.large,
                &*perm_space,
                self.reserved_area.clone(),
                phase,
                promotion_failed,
            );
            verifier.verify();

            if vm.args.flag_gc_dev_verbose {
                println!("GC: Verify {} finished", _name);
            }
        }
    }
}

impl Collector for Swiper {
    fn alloc_tlab_area(&self, vm: &VM, size: usize) -> Option<Region> {
        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return Some(ptr.region_start(size));
        }

        self.perform_collection_and_choose(vm, GcReason::AllocationFailure);

        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return Some(ptr.region_start(size));
        }

        self.perform_collection(vm, CollectionKind::Full, GcReason::AllocationFailure);
        let ptr = self.young.bump_alloc(size);

        return if ptr.is_null() {
            None
        } else {
            Some(ptr.region_start(size))
        };
    }

    fn alloc_normal(&self, vm: &VM, size: usize, array_ref: bool) -> Address {
        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return ptr;
        }

        self.perform_collection_and_choose(vm, GcReason::AllocationFailure);

        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return ptr;
        }

        self.old.bump_alloc(size, array_ref)
    }

    fn alloc_large(&self, vm: &VM, size: usize, _: bool) -> Address {
        let ptr = self.large.alloc(size);

        if !ptr.is_null() {
            return ptr;
        }

        self.perform_collection(vm, CollectionKind::Full, GcReason::AllocationFailure);

        self.large.alloc(size)
    }

    fn collect(&self, vm: &VM, reason: GcReason) {
        self.perform_collection(vm, CollectionKind::Full, reason);
    }

    fn minor_collect(&self, vm: &VM, reason: GcReason) {
        self.perform_collection(vm, CollectionKind::Minor, reason);
    }

    fn needs_write_barrier(&self) -> bool {
        return true;
    }

    fn card_table_offset(&self) -> usize {
        self.card_table_offset
    }

    fn dump_summary(&self, runtime: f32) {
        self.stats.update(|stats| {
            let total_gc = stats.minor_runtime() + stats.full_runtime();
            let gc_percentage = ((total_gc / runtime) * 100.0).round();
            let mutator_percentage = 100.0 - gc_percentage;

            println!(
                "GC summary: {:.1}ms minor ({}), {:.1}ms full ({}), {:.1}ms runtime ({}% mutator, {}% GC)",
                stats.minor_runtime(),
                stats.minor_collections(),
                stats.full_runtime(),
                stats.full_collections(),
                runtime,
                mutator_percentage,
                gc_percentage,
            );
        })
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct CardIdx(usize);

impl CardIdx {
    pub fn to_usize(self) -> usize {
        self.0
    }

    pub fn offset(self, val: usize) -> CardIdx {
        (self.0 + val).into()
    }
}

impl From<usize> for CardIdx {
    fn from(val: usize) -> CardIdx {
        CardIdx(val)
    }
}

fn on_different_cards(curr: Address, next: Address) -> bool {
    (curr.to_usize() >> CARD_SIZE_BITS) != (next.to_usize() >> CARD_SIZE_BITS)
}

pub enum CollectionKind {
    Minor,
    Full,
}

pub struct GcStats {
    stats: Mutex<GcStatsProtected>,
}

impl GcStats {
    fn new() -> GcStats {
        GcStats {
            stats: Mutex::new(GcStatsProtected::new()),
        }
    }

    fn update<F>(&self, fct: F)
    where
        F: FnOnce(&mut GcStatsProtected),
    {
        let mut stats = self.stats.lock();
        fct(&mut *stats);
    }
}

struct GcStatsProtected {
    // number of minor GCs
    minor_collections: usize,

    // total runtime of minor GCs
    minor_runtime: f32,

    // number of full GCs
    full_collections: usize,

    // total runtime of full GCs
    full_runtime: f32,
}

impl GcStatsProtected {
    fn new() -> GcStatsProtected {
        GcStatsProtected {
            minor_collections: 0,
            minor_runtime: 0.0,
            full_collections: 0,
            full_runtime: 0.0,
        }
    }

    fn incr_minor_collections(&mut self) {
        self.minor_collections += 1;
    }

    fn minor_collections(&self) -> usize {
        self.minor_collections
    }

    fn incr_minor_runtime(&mut self, time: f32) {
        self.minor_runtime += time;
    }

    fn minor_runtime(&self) -> f32 {
        self.minor_runtime
    }

    fn incr_full_collections(&mut self) {
        self.full_collections += 1;
    }

    fn full_collections(&self) -> usize {
        self.full_collections
    }

    fn incr_full_runtime(&mut self, time: f32) {
        self.full_runtime += time;
    }

    fn full_runtime(&self) -> f32 {
        self.full_runtime
    }
}
<commit_msg>swiper: move rootset into perform_collection<commit_after>use parking_lot::Mutex;
use scoped_threadpool::Pool;
use std::sync::Arc;

use ctxt::VM;
use driver::cmd::Args;
use gc::root::{get_rootset, Slot};
use gc::swiper::card::CardTable;
use gc::swiper::controller::{choose_collection_kind, resize_gens, HeapConfig, SharedHeapConfig};
use gc::swiper::crossing::CrossingMap;
use gc::swiper::full::FullCollector;
use gc::swiper::large::LargeSpace;
use gc::swiper::minor::MinorCollector;
use gc::swiper::old::OldGen;
use gc::swiper::verify::{Verifier, VerifierPhase};
use gc::swiper::young::YoungGen;
use gc::tlab;
use gc::Collector;
use gc::{arena, GcReason};
use gc::{formatted_size, Address, Region, K, M};
use mem;

pub mod card;
mod controller;
mod crossing;
mod full;
mod large;
mod marking;
mod minor;
pub mod old;
mod paged_old;
mod verify;
pub mod young;

// determines size of young generation in heap
// young generation size = heap size / YOUNG_RATIO
const YOUNG_RATIO: usize = 2;

// heap is divided into cards of size CARD_SIZE.
// card entry determines whether this part of the heap was modified
// in minor collections those parts of the heap need to be analyzed
pub const CARD_SIZE: usize = 512;
pub const CARD_SIZE_BITS: usize = 9;

pub const LARGE_OBJECT_SIZE: usize = 16 * K;

pub struct Swiper {
    // contiguous memory for young/old generation and large space
    heap: Region,

    // contains heap and also card table and crossing map
    reserved_area: Region,

    young: YoungGen,
    old: OldGen,
    large: LargeSpace,

    card_table: CardTable,
    crossing_map: CrossingMap,

    card_table_offset: usize,

    // minimum & maximum heap size
    min_heap_size: usize,
    max_heap_size: usize,

    threadpool: Mutex<Pool>,

    stats: GcStats,
    config: SharedHeapConfig,
}

impl Swiper {
    pub fn new(args: &Args) -> Swiper {
        let min_heap_size = args.min_heap_size();
        let max_heap_size = args.max_heap_size();

        let (eden_size, semi_size) = (12 * M, 8 * M);

        // determine size for card table
        let card_size = mem::page_align((4 * max_heap_size) >> CARD_SIZE_BITS);

        // determine size for crossing map
        let crossing_size = mem::page_align(max_heap_size >> CARD_SIZE_BITS);

        // determine full memory size
        let reserve_size = max_heap_size * 4 + card_size + crossing_size;

        // reserve full memory
        let ptr = arena::reserve(reserve_size);

        // heap is young/old generation & large space
        let heap_start = ptr;
        let heap_end = ptr.offset(4 * max_heap_size);

        // reserved area also contains card table & crossing map
        let reserved_area = heap_start.region_start(reserve_size);

        // determine offset to card table (card table starts right after heap)
        // offset = card_table_start - (heap_start >> CARD_SIZE_BITS)
        let card_table_offset = heap_end.to_usize() - (heap_start.to_usize() >> CARD_SIZE_BITS);

        // determine boundaries for card table
        let card_start = heap_end;
        let card_end = card_start.offset(card_size);

        arena::commit(card_start, card_size, false);

        // determine boundaries for crossing map
        let crossing_start = card_end;
        let crossing_end = crossing_start.offset(crossing_size);

        arena::commit(crossing_start, crossing_size, false);

        // determine boundaries of young generation
        let young_start = heap_start;
        let young_end = young_start.offset(max_heap_size);
        let young = Region::new(young_start, young_end);

        // determine boundaries of old generation
        let old_start = young_end;
        let old_end = old_start.offset(max_heap_size);

        let init_old_size = max_heap_size;
        let young_size = eden_size + semi_size;
        let config = HeapConfig::new(eden_size, semi_size, 0, init_old_size - young_size);
        let config = Arc::new(Mutex::new(config));

        // determine large object space
        let large_start = old_end;
        let large_end = large_start.offset(2 * max_heap_size);

        let card_table = CardTable::new(
            card_start,
            card_end,
            Region::new(old_start, large_end),
            old_end,
            max_heap_size,
        );
        let crossing_map = CrossingMap::new(crossing_start, crossing_end, max_heap_size);
        let young = YoungGen::new(young, eden_size, semi_size, args.flag_gc_verify);
        let old = OldGen::new(
            old_start,
            old_end,
            crossing_map.clone(),
            card_table.clone(),
            config.clone(),
        );
        let large = LargeSpace::new(large_start, large_end, config.clone());

        if args.flag_gc_verbose {
            println!(
                "GC: heap info: {}, eden {}, semi {}, card {}, crossing {}",
                formatted_size(max_heap_size),
                formatted_size(eden_size),
                formatted_size(semi_size),
                formatted_size(card_size),
                formatted_size(crossing_size)
            );
        }

        let nworkers = args.gc_workers();

        Swiper {
            heap: Region::new(heap_start, heap_end),
            reserved_area: reserved_area,

            young: young,
            old: old,
            large: large,

            card_table: card_table,
            crossing_map: crossing_map,
            config: config,

            card_table_offset: card_table_offset,

            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,

            threadpool: Mutex::new(Pool::new(nworkers as u32)),
            stats: GcStats::new(),
        }
    }

    fn perform_collection_and_choose(&self, vm: &VM, reason: GcReason) -> CollectionKind {
        let kind = choose_collection_kind(&self.config, &self.young);
        self.perform_collection(vm, kind, reason)
    }

    fn perform_collection(
        &self,
        vm: &VM,
        kind: CollectionKind,
        reason: GcReason,
    ) -> CollectionKind {
        tlab::make_iterable(vm);
        let rootset = get_rootset(vm);

        let kind = match kind {
            CollectionKind::Minor => {
                let promotion_failed = self.minor_collect(vm, reason, &rootset);

                if promotion_failed {
                    self.full_collect(vm, GcReason::PromotionFailure, &rootset);
                    CollectionKind::Full
                } else {
                    CollectionKind::Minor
                }
            }

            CollectionKind::Full => {
                self.full_collect(vm, reason, &rootset);
                CollectionKind::Full
            }
        };

        resize_gens(
            self.max_heap_size,
            &self.config,
            &self.young,
            &self.old,
            &self.large,
            vm.args.flag_gc_verbose,
        );

        kind
    }

    fn minor_collect(&self, vm: &VM, reason: GcReason, rootset: &[Slot]) -> bool {
        self.verify(vm, VerifierPhase::PreMinor, "pre-minor", &rootset, false);

        let mut pool = self.threadpool.lock();
        let mut collector = MinorCollector::new(
            vm,
            &self.young,
            &self.old,
            &self.large,
            &self.card_table,
            &self.crossing_map,
            &rootset,
            reason,
            self.min_heap_size,
            self.max_heap_size,
            &self.stats,
            &mut pool,
        );
        let promotion_failed = collector.collect();

        self.verify(
            vm,
            VerifierPhase::PostMinor,
            "post-minor",
            &rootset,
            promotion_failed,
        );

        promotion_failed
    }

    fn full_collect(&self, vm: &VM, reason: GcReason, rootset: &[Slot]) {
        self.verify(
            vm,
            VerifierPhase::PreFull,
            "pre-full",
            &rootset,
            reason == GcReason::PromotionFailure,
        );

        let mut pool = self.threadpool.lock();
        let mut collector = FullCollector::new(
            vm,
            self.heap.clone(),
            &self.young,
            &self.old,
            &self.large,
            &self.card_table,
            &self.crossing_map,
            &vm.gc.perm_space,
            &rootset,
            reason,
            &mut pool,
            self.min_heap_size,
            self.max_heap_size,
            &self.stats,
        );
        collector.collect();

        self.verify(vm, VerifierPhase::PostFull, "post-full", &rootset, false);
    }

    fn verify(
        &self,
        vm: &VM,
        phase: VerifierPhase,
        _name: &str,
        rootset: &[Slot],
        promotion_failed: bool,
    ) {
        if vm.args.flag_gc_verify {
            if vm.args.flag_gc_dev_verbose {
                println!("GC: Verify {}", _name);
            }

            let perm_space = &vm.gc.perm_space;

            let mut verifier = Verifier::new(
                &self.young,
                &self.old,
                &self.card_table,
                &self.crossing_map,
                rootset,
                &self.large,
                &*perm_space,
                self.reserved_area.clone(),
                phase,
                promotion_failed,
            );
            verifier.verify();

            if vm.args.flag_gc_dev_verbose {
                println!("GC: Verify {} finished", _name);
            }
        }
    }
}

impl Collector for Swiper {
    fn alloc_tlab_area(&self, vm: &VM, size: usize) -> Option<Region> {
        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return Some(ptr.region_start(size));
        }

        self.perform_collection_and_choose(vm, GcReason::AllocationFailure);

        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return Some(ptr.region_start(size));
        }

        self.perform_collection(vm, CollectionKind::Full, GcReason::AllocationFailure);
        let ptr = self.young.bump_alloc(size);

        return if ptr.is_null() {
            None
        } else {
            Some(ptr.region_start(size))
        };
    }

    fn alloc_normal(&self, vm: &VM, size: usize, array_ref: bool) -> Address {
        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return ptr;
        }

        self.perform_collection_and_choose(vm, GcReason::AllocationFailure);

        let ptr = self.young.bump_alloc(size);

        if !ptr.is_null() {
            return ptr;
        }

        self.old.bump_alloc(size, array_ref)
    }

    fn alloc_large(&self, vm: &VM, size: usize, _: bool) -> Address {
        let ptr = self.large.alloc(size);

        if !ptr.is_null() {
            return ptr;
        }

        self.perform_collection(vm, CollectionKind::Full, GcReason::AllocationFailure);

        self.large.alloc(size)
    }

    fn collect(&self, vm: &VM, reason: GcReason) {
        self.perform_collection(vm, CollectionKind::Full, reason);
    }

    fn minor_collect(&self, vm: &VM, reason: GcReason) {
        self.perform_collection(vm, CollectionKind::Minor, reason);
    }

    fn needs_write_barrier(&self) -> bool {
        return true;
    }

    fn card_table_offset(&self) -> usize {
        self.card_table_offset
    }

    fn dump_summary(&self, runtime: f32) {
        self.stats.update(|stats| {
            let total_gc = stats.minor_runtime() + stats.full_runtime();
            let gc_percentage = ((total_gc / runtime) * 100.0).round();
            let mutator_percentage = 100.0 - gc_percentage;

            println!(
                "GC summary: {:.1}ms minor ({}), {:.1}ms full ({}), {:.1}ms runtime ({}% mutator, {}% GC)",
                stats.minor_runtime(),
                stats.minor_collections(),
                stats.full_runtime(),
                stats.full_collections(),
                runtime,
                mutator_percentage,
                gc_percentage,
            );
        })
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct CardIdx(usize);

impl CardIdx {
    pub fn to_usize(self) -> usize {
        self.0
    }

    pub fn offset(self, val: usize) -> CardIdx {
        (self.0 + val).into()
    }
}

impl From<usize> for CardIdx {
    fn from(val: usize) -> CardIdx {
        CardIdx(val)
    }
}

fn on_different_cards(curr: Address, next: Address) -> bool {
    (curr.to_usize() >> CARD_SIZE_BITS) != (next.to_usize() >> CARD_SIZE_BITS)
}

pub enum CollectionKind {
    Minor,
    Full,
}

pub struct GcStats {
    stats: Mutex<GcStatsProtected>,
}

impl GcStats {
    fn new() -> GcStats {
        GcStats {
            stats: Mutex::new(GcStatsProtected::new()),
        }
    }

    fn update<F>(&self, fct: F)
    where
        F: FnOnce(&mut GcStatsProtected),
    {
        let mut stats = self.stats.lock();
        fct(&mut *stats);
    }
}

struct GcStatsProtected {
    // number of minor GCs
    minor_collections: usize,

    // total runtime of minor GCs
    minor_runtime: f32,

    // number of full GCs
    full_collections: usize,

    // total runtime of full GCs
    full_runtime: f32,
}

impl GcStatsProtected {
    fn new() -> GcStatsProtected {
        GcStatsProtected {
            minor_collections: 0,
            minor_runtime: 0.0,
            full_collections: 0,
            full_runtime: 0.0,
        }
    }

    fn incr_minor_collections(&mut self) {
        self.minor_collections += 1;
    }

    fn minor_collections(&self) -> usize {
        self.minor_collections
    }

    fn incr_minor_runtime(&mut self, time: f32) {
        self.minor_runtime += time;
    }

    fn minor_runtime(&self) -> f32 {
        self.minor_runtime
    }

    fn incr_full_collections(&mut self) {
        self.full_collections += 1;
    }

    fn full_collections(&self) -> usize {
        self.full_collections
    }

    fn incr_full_runtime(&mut self, time: f32) {
        self.full_runtime += time;
    }

    fn full_runtime(&self) -> f32 {
        self.full_runtime
    }
}
<|endoftext|>


<commit_before>//! Diagnostic reporting support for the codespan crate

use codespan::ByteSpan;

use Severity;

/// A style for the label
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LabelStyle {
    /// The main focus of the diagnostic
    Primary,
    /// Supporting labels that may help to isolate the cause of the diagnostic
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic
#[derive(Clone, Debug)]
pub struct Label {
    /// The span we are going to include in the final snippet.
    pub span: ByteSpan,
    /// A message to provide some additional information for the underlined code.
    pub message: Option<String>,
    /// The style to use for the label.
    pub style: LabelStyle,
}

impl Label {
    pub fn new_primary<S: Into<String>>(span: ByteSpan, message: S) -> Label {
        Label {
            span,
            message: Some(message.into()),
            style: LabelStyle::Primary,
        }
    }

    pub fn new_secondary<S: Into<String>>(span: ByteSpan, message: S) -> Label {
        Label {
            span,
            message: Some(message.into()),
            style: LabelStyle::Primary,
        }
    }
}

/// Represents a diagnostic message and associated child messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// The main message associated with this diagnostic
    pub message: String,
    /// The labelled spans marking the regions of code that cause this
    /// diagnostic to be raised
    pub labels: Vec<Label>,
}

impl Diagnostic {
    pub fn new<S: Into<String>>(severity: Severity, message: S) -> Diagnostic {
        Diagnostic {
            severity,
            message: message.into(),
            labels: Vec::new(),
        }
    }

    pub fn new_bug<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Bug, message)
    }

    pub fn new_error<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Error, message)
    }

    pub fn new_warning<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Warning, message)
    }

    pub fn new_note<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Note, message)
    }

    pub fn new_help<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Help, message)
    }

    pub fn with_label(mut self, label: Label) -> Diagnostic {
        self.labels.push(label);
        self
    }

    pub fn with_primary_label<S: Into<String>>(self, span: ByteSpan, message: S) -> Diagnostic {
        self.with_label(Label::new_primary(span, message))
    }

    pub fn with_secondary_label<S: Into<String>>(self, span: ByteSpan, message: S) -> Diagnostic {
        self.with_label(Label::new_secondary(span, message))
    }
}
<commit_msg>Default to label message being none<commit_after>//! Diagnostic reporting support for the codespan crate

use codespan::ByteSpan;

use Severity;

/// A style for the label
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LabelStyle {
    /// The main focus of the diagnostic
    Primary,
    /// Supporting labels that may help to isolate the cause of the diagnostic
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic
#[derive(Clone, Debug)]
pub struct Label {
    /// The span we are going to include in the final snippet.
    pub span: ByteSpan,
    /// A message to provide some additional information for the underlined code.
    pub message: Option<String>,
    /// The style to use for the label.
    pub style: LabelStyle,
}

impl Label {
    pub fn new(span: ByteSpan, style: LabelStyle) -> Label {
        Label {
            span,
            message: None,
            style,
        }
    }

    pub fn new_primary(span: ByteSpan) -> Label {
        Label::new(span, LabelStyle::Primary)
    }

    pub fn new_secondary(span: ByteSpan) -> Label {
        Label::new(span, LabelStyle::Primary)
    }

    pub fn with_message<S: Into<String>>(mut self, message: S) -> Label {
        self.message = Some(message.into());
        self
    }
}

/// Represents a diagnostic message and associated child messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// The main message associated with this diagnostic
    pub message: String,
    /// The labelled spans marking the regions of code that cause this
    /// diagnostic to be raised
    pub labels: Vec<Label>,
}

impl Diagnostic {
    pub fn new<S: Into<String>>(severity: Severity, message: S) -> Diagnostic {
        Diagnostic {
            severity,
            message: message.into(),
            labels: Vec::new(),
        }
    }

    pub fn new_bug<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Bug, message)
    }

    pub fn new_error<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Error, message)
    }

    pub fn new_warning<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Warning, message)
    }

    pub fn new_note<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Note, message)
    }

    pub fn new_help<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Help, message)
    }

    pub fn with_label(mut self, label: Label) -> Diagnostic {
        self.labels.push(label);
        self
    }

    pub fn with_primary_label<S: Into<String>>(self, span: ByteSpan, message: S) -> Diagnostic {
        self.with_label(Label::new_primary(span).with_message(message))
    }

    pub fn with_secondary_label<S: Into<String>>(self, span: ByteSpan, message: S) -> Diagnostic {
        self.with_label(Label::new_secondary(span).with_message(message))
    }
}
<|endoftext|>


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

#![crate_name="html5ever-macros"]
#![crate_type="dylib"]

#![feature(macro_rules, plugin_registrar, quote, managed_boxes)]

extern crate syntax;
extern crate rustc;
extern crate serialize;
extern crate debug;

use rustc::plugin::Registry;

// Internal macros for use in defining other macros.

#[macro_escape]
macro_rules! bail ( ($cx:expr, $sp:expr, $msg:expr) => ({
    $cx.span_err($sp, $msg);
    return ::syntax::ext::base::DummyResult::any($sp);
}))

#[macro_escape]
macro_rules! bail_if ( ($e:expr, $cx:expr, $sp:expr, $msg:expr) => (
    if $e { bail!($cx, $sp, $msg) }
))

#[macro_escape]
macro_rules! expect ( ($cx:expr, $sp:expr, $e:expr, $msg:expr) => (
    match $e {
        Some(x) => x,
        None => bail!($cx, $sp, $msg),
    }
))

// Make these public so that rustdoc will generate documentation for them.
pub mod named_entities;
pub mod atom;
pub mod match_token;

#[macro_export]
macro_rules! unwrap_or_return ( ($opt:expr, $retval:expr) => (
    match $opt {
        None => return $retval,
        Some(x) => x,
    }
))

#[macro_export]
macro_rules! test_eq ( ($name:ident, $left:expr, $right:expr) => (
    #[test]
    fn $name() {
        assert_eq!($left, $right);
    }
))

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("named_entities", named_entities::expand);
    reg.register_macro("static_atom_map", atom::expand_static_atom_map);
    reg.register_macro("static_atom_array", atom::expand_static_atom_array);
    reg.register_macro("atom", atom::expand_atom);
    reg.register_macro("match_token", match_token::expand);
}
<commit_msg>Remove useless `#[macro_escape]`s<commit_after>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name="html5ever-macros"]
#![crate_type="dylib"]

#![feature(macro_rules, plugin_registrar, quote, managed_boxes)]

extern crate syntax;
extern crate rustc;
extern crate serialize;
extern crate debug;

use rustc::plugin::Registry;

// Internal macros for use in defining other macros.

macro_rules! bail ( ($cx:expr, $sp:expr, $msg:expr) => ({
    $cx.span_err($sp, $msg);
    return ::syntax::ext::base::DummyResult::any($sp);
}))

macro_rules! bail_if ( ($e:expr, $cx:expr, $sp:expr, $msg:expr) => (
    if $e { bail!($cx, $sp, $msg) }
))

macro_rules! expect ( ($cx:expr, $sp:expr, $e:expr, $msg:expr) => (
    match $e {
        Some(x) => x,
        None => bail!($cx, $sp, $msg),
    }
))

// Make these public so that rustdoc will generate documentation for them.
pub mod named_entities;
pub mod atom;
pub mod match_token;

#[macro_export]
macro_rules! unwrap_or_return ( ($opt:expr, $retval:expr) => (
    match $opt {
        None => return $retval,
        Some(x) => x,
    }
))

#[macro_export]
macro_rules! test_eq ( ($name:ident, $left:expr, $right:expr) => (
    #[test]
    fn $name() {
        assert_eq!($left, $right);
    }
))

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("named_entities", named_entities::expand);
    reg.register_macro("static_atom_map", atom::expand_static_atom_map);
    reg.register_macro("static_atom_array", atom::expand_static_atom_array);
    reg.register_macro("atom", atom::expand_atom);
    reg.register_macro("match_token", match_token::expand);
}
<|endoftext|>


<commit_before>#![crate_name = "input"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate viewport;

use std::fmt;
use std::any::Any;
use std::sync::Arc;
use std::path::PathBuf;

pub use mouse::MouseButton;
pub use keyboard::Key;
pub use controller::{ControllerAxisArgs, ControllerButton, ControllerHat};

pub mod controller;
pub mod keyboard;
pub mod mouse;

pub use after_render::{AfterRenderArgs, AfterRenderEvent};
pub use close::{CloseArgs, CloseEvent};
pub use controller::ControllerAxisEvent;
pub use cursor::CursorEvent;
pub use focus::FocusEvent;
pub use generic_event::GenericEvent;
pub use idle::{IdleArgs, IdleEvent};
pub use mouse::{MouseCursorEvent, MouseRelativeEvent, MouseScrollEvent};
pub use button::{ButtonState, ButtonArgs, ButtonEvent, PressEvent, ReleaseEvent};
pub use resize::ResizeEvent;
pub use render::{RenderArgs, RenderEvent};
pub use text::TextEvent;
pub use touch::{Touch, TouchArgs, TouchEvent};
pub use update::{UpdateArgs, UpdateEvent};

pub mod generic_event;

mod after_render;
mod button;
mod close;
mod cursor;
mod focus;
mod idle;
mod render;
mod resize;
mod text;
mod touch;
mod update;

/// Used to identify events arguments provided by traits.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct EventId(pub &'static str);

const AFTER_RENDER: EventId = EventId("piston/after_render");
const CONTROLLER_AXIS: EventId = EventId("piston/controller_axis");
const CURSOR: EventId = EventId("piston/cursor");
const FOCUS: EventId = EventId("piston/focus");
const CLOSE: EventId = EventId("piston/close");
const IDLE: EventId = EventId("piston/idle");
const MOUSE_SCROLL: EventId = EventId("piston/mouse_scroll");
const MOUSE_RELATIVE: EventId = EventId("piston/mouse_relative");
const MOUSE_CURSOR: EventId = EventId("piston/mouse_cursor");
const BUTTON: EventId = EventId("piston/button");
const RENDER: EventId = EventId("piston/render");
const RESIZE: EventId = EventId("piston/resize");
const TEXT: EventId = EventId("piston/text");
const TOUCH: EventId = EventId("piston/touch");
const UPDATE: EventId = EventId("piston/update");
const FILE_DRAG: EventId = EventId("piston/file_drag");

/// Models different kinds of buttons.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Hash, Debug)]
pub enum Button {
    /// A keyboard button.
    Keyboard(Key),
    /// A mouse button.
    Mouse(MouseButton),
    /// A controller button.
    Controller(ControllerButton),
    /// A controller hat (d-Pad)
    Hat(ControllerHat),
}

/// Models different kinds of motion.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
    /// controller axis move event.
    ControllerAxis(ControllerAxisArgs),
    /// touch event.
    Touch(TouchArgs),
}

#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
#[allow(missing_docs)]
pub enum HatState {
  Centered,
  Up,
  Right,
  Down,
  Left,
  RightUp,
  RightDown,
  LeftUp,
  LeftDown,
}

/// Models dragging and dropping files.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum FileDrag {
    /// A file is being hovered over the window.
    Hover(PathBuf),
    /// A file has been dropped into the window.
    Drop(PathBuf),
    /// A file was hovered, but has exited the window.
    Cancel,
}

/// Models input events.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Input {
    /// Changed button state.
    Button(ButtonArgs),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(f64, f64),
    /// Window gained or lost focus.
    Focus(bool),
    /// Window gained or lost cursor.
    Cursor(bool),
    /// A file is being dragged or dropped over the window.
    FileDrag(FileDrag),
    /// Window closed.
    Close(CloseArgs),
}

/// Models loop events.
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Loop {
    /// Render graphics.
    Render(RenderArgs),
    /// After rendering and swapping buffers.
    AfterRender(AfterRenderArgs),
    /// Update the state of the application.
    Update(UpdateArgs),
    /// Do background tasks that can be done incrementally.
    Idle(IdleArgs),
}

/// Models all events.
#[derive(Clone)]
pub enum Event {
    /// Input events.
    Input(Input),
    /// Events that commonly used by event loops.
    Loop(Loop),
    /// Custom event.
    ///
    /// When comparing two custom events for equality,
    /// they always return `false`.
    Custom(EventId, Arc<Any + Send + Sync>),
}

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Event::Input(ref input) => write!(f, "{:?}", input),
            Event::Loop(ref l) => write!(f, "{:?}", l),
            Event::Custom(ref id, _) => write!(f, "Custom({:?}, _)", id),
        }
    }
}

impl PartialEq for Event {
    fn eq(&self, other: &Event) -> bool {
        use Event::*;

        match (self, other) {
            (&Input(ref a), &Input(ref b)) => a == b,
            (&Loop(ref a), &Loop(ref b)) => a == b,
            (_, _) => false,
        }
    }
}

impl From<Key> for Button {
    fn from(key: Key) -> Self {
        Button::Keyboard(key)
    }
}

impl From<MouseButton> for Button {
    fn from(btn: MouseButton) -> Self {
        Button::Mouse(btn)
    }
}

impl From<ControllerButton> for Button {
    fn from(btn: ControllerButton) -> Self {
        Button::Controller(btn)
    }
}

impl From<ButtonArgs> for Input {
    fn from(args: ButtonArgs) -> Self {
        Input::Button(args)
    }
}

impl From<ControllerAxisArgs> for Motion {
    fn from(args: ControllerAxisArgs) -> Self {
        Motion::ControllerAxis(args)
    }
}

impl From<ControllerAxisArgs> for Input {
    fn from(args: ControllerAxisArgs) -> Self {
        Input::Move(Motion::ControllerAxis(args))
    }
}

impl From<TouchArgs> for Motion {
    fn from(args: TouchArgs) -> Self {
        Motion::Touch(args)
    }
}

impl From<TouchArgs> for Input {
    fn from(args: TouchArgs) -> Self {
        Input::Move(Motion::Touch(args))
    }
}

impl From<Motion> for Input {
    fn from(motion: Motion) -> Self {
        Input::Move(motion)
    }
}

impl From<RenderArgs> for Loop {
    fn from(args: RenderArgs) -> Self {
        Loop::Render(args)
    }
}

impl From<RenderArgs> for Event {
    fn from(args: RenderArgs) -> Self {
        Event::Loop(Loop::Render(args))
    }
}

impl From<AfterRenderArgs> for Loop {
    fn from(args: AfterRenderArgs) -> Self {
        Loop::AfterRender(args)
    }
}

impl From<AfterRenderArgs> for Event {
    fn from(args: AfterRenderArgs) -> Self {
        Event::Loop(Loop::AfterRender(args))
    }
}

impl From<UpdateArgs> for Loop {
    fn from(args: UpdateArgs) -> Self {
        Loop::Update(args)
    }
}

impl From<UpdateArgs> for Event {
    fn from(args: UpdateArgs) -> Self {
        Event::Loop(Loop::Update(args))
    }
}

impl From<IdleArgs> for Loop {
    fn from(args: IdleArgs) -> Self {
        Loop::Idle(args)
    }
}

impl From<IdleArgs> for Event {
    fn from(args: IdleArgs) -> Self {
        Event::Loop(Loop::Idle(args))
    }
}

impl From<CloseArgs> for Input {
    fn from(args: CloseArgs) -> Self {
        Input::Close(args)
    }
}

impl<T> From<T> for Event
    where Input: From<T>
{
    fn from(args: T) -> Self {
        Event::Input(args.into())
    }
}

impl From<Loop> for Event {
    fn from(l: Loop) -> Self {
        Event::Loop(l)
    }
}

impl Into<Option<Input>> for Event {
    fn into(self) -> Option<Input> {
        if let Event::Input(input) = self {
            Some(input)
        } else {
            None
        }
    }
}

impl Into<Option<Loop>> for Event {
    fn into(self) -> Option<Loop> {
        if let Event::Loop(l) = self {
            Some(l)
        } else {
            None
        }
    }
}

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

    #[test]
    fn test_input_sync_send() {
        fn chk<T: Sync + Send>() {}

        chk::<Input>();
    }
}
<commit_msg>Added missing docs for `HatState`<commit_after>#![crate_name = "input"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate viewport;

use std::fmt;
use std::any::Any;
use std::sync::Arc;
use std::path::PathBuf;

pub use mouse::MouseButton;
pub use keyboard::Key;
pub use controller::{ControllerAxisArgs, ControllerButton, ControllerHat};

pub mod controller;
pub mod keyboard;
pub mod mouse;

pub use after_render::{AfterRenderArgs, AfterRenderEvent};
pub use close::{CloseArgs, CloseEvent};
pub use controller::ControllerAxisEvent;
pub use cursor::CursorEvent;
pub use focus::FocusEvent;
pub use generic_event::GenericEvent;
pub use idle::{IdleArgs, IdleEvent};
pub use mouse::{MouseCursorEvent, MouseRelativeEvent, MouseScrollEvent};
pub use button::{ButtonState, ButtonArgs, ButtonEvent, PressEvent, ReleaseEvent};
pub use resize::ResizeEvent;
pub use render::{RenderArgs, RenderEvent};
pub use text::TextEvent;
pub use touch::{Touch, TouchArgs, TouchEvent};
pub use update::{UpdateArgs, UpdateEvent};

pub mod generic_event;

mod after_render;
mod button;
mod close;
mod cursor;
mod focus;
mod idle;
mod render;
mod resize;
mod text;
mod touch;
mod update;

/// Used to identify events arguments provided by traits.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct EventId(pub &'static str);

const AFTER_RENDER: EventId = EventId("piston/after_render");
const CONTROLLER_AXIS: EventId = EventId("piston/controller_axis");
const CURSOR: EventId = EventId("piston/cursor");
const FOCUS: EventId = EventId("piston/focus");
const CLOSE: EventId = EventId("piston/close");
const IDLE: EventId = EventId("piston/idle");
const MOUSE_SCROLL: EventId = EventId("piston/mouse_scroll");
const MOUSE_RELATIVE: EventId = EventId("piston/mouse_relative");
const MOUSE_CURSOR: EventId = EventId("piston/mouse_cursor");
const BUTTON: EventId = EventId("piston/button");
const RENDER: EventId = EventId("piston/render");
const RESIZE: EventId = EventId("piston/resize");
const TEXT: EventId = EventId("piston/text");
const TOUCH: EventId = EventId("piston/touch");
const UPDATE: EventId = EventId("piston/update");
const FILE_DRAG: EventId = EventId("piston/file_drag");

/// Models different kinds of buttons.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Hash, Debug)]
pub enum Button {
    /// A keyboard button.
    Keyboard(Key),
    /// A mouse button.
    Mouse(MouseButton),
    /// A controller button.
    Controller(ControllerButton),
    /// A controller hat (d-Pad)
    Hat(ControllerHat),
}

/// Models different kinds of motion.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
    /// controller axis move event.
    ControllerAxis(ControllerAxisArgs),
    /// touch event.
    Touch(TouchArgs),
}

/// Stores controller hat state.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
pub enum HatState {
    /// Centered (no direction).
    Centered,
    /// Up direction.
    Up,
    /// Right direction.
    Right,
    /// Down direction.
    Down,
    /// Left direction.
    Left,
    /// Right-up direction.
    RightUp,
    /// Right-down direction.
    RightDown,
    /// Left-up direction.
    LeftUp,
    /// Left-down direction.
    LeftDown,
}

/// Models dragging and dropping files.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum FileDrag {
    /// A file is being hovered over the window.
    Hover(PathBuf),
    /// A file has been dropped into the window.
    Drop(PathBuf),
    /// A file was hovered, but has exited the window.
    Cancel,
}

/// Models input events.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Input {
    /// Changed button state.
    Button(ButtonArgs),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(f64, f64),
    /// Window gained or lost focus.
    Focus(bool),
    /// Window gained or lost cursor.
    Cursor(bool),
    /// A file is being dragged or dropped over the window.
    FileDrag(FileDrag),
    /// Window closed.
    Close(CloseArgs),
}

/// Models loop events.
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Loop {
    /// Render graphics.
    Render(RenderArgs),
    /// After rendering and swapping buffers.
    AfterRender(AfterRenderArgs),
    /// Update the state of the application.
    Update(UpdateArgs),
    /// Do background tasks that can be done incrementally.
    Idle(IdleArgs),
}

/// Models all events.
#[derive(Clone)]
pub enum Event {
    /// Input events.
    Input(Input),
    /// Events that commonly used by event loops.
    Loop(Loop),
    /// Custom event.
    ///
    /// When comparing two custom events for equality,
    /// they always return `false`.
    Custom(EventId, Arc<Any + Send + Sync>),
}

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Event::Input(ref input) => write!(f, "{:?}", input),
            Event::Loop(ref l) => write!(f, "{:?}", l),
            Event::Custom(ref id, _) => write!(f, "Custom({:?}, _)", id),
        }
    }
}

impl PartialEq for Event {
    fn eq(&self, other: &Event) -> bool {
        use Event::*;

        match (self, other) {
            (&Input(ref a), &Input(ref b)) => a == b,
            (&Loop(ref a), &Loop(ref b)) => a == b,
            (_, _) => false,
        }
    }
}

impl From<Key> for Button {
    fn from(key: Key) -> Self {
        Button::Keyboard(key)
    }
}

impl From<MouseButton> for Button {
    fn from(btn: MouseButton) -> Self {
        Button::Mouse(btn)
    }
}

impl From<ControllerButton> for Button {
    fn from(btn: ControllerButton) -> Self {
        Button::Controller(btn)
    }
}

impl From<ButtonArgs> for Input {
    fn from(args: ButtonArgs) -> Self {
        Input::Button(args)
    }
}

impl From<ControllerAxisArgs> for Motion {
    fn from(args: ControllerAxisArgs) -> Self {
        Motion::ControllerAxis(args)
    }
}

impl From<ControllerAxisArgs> for Input {
    fn from(args: ControllerAxisArgs) -> Self {
        Input::Move(Motion::ControllerAxis(args))
    }
}

impl From<TouchArgs> for Motion {
    fn from(args: TouchArgs) -> Self {
        Motion::Touch(args)
    }
}

impl From<TouchArgs> for Input {
    fn from(args: TouchArgs) -> Self {
        Input::Move(Motion::Touch(args))
    }
}

impl From<Motion> for Input {
    fn from(motion: Motion) -> Self {
        Input::Move(motion)
    }
}

impl From<RenderArgs> for Loop {
    fn from(args: RenderArgs) -> Self {
        Loop::Render(args)
    }
}

impl From<RenderArgs> for Event {
    fn from(args: RenderArgs) -> Self {
        Event::Loop(Loop::Render(args))
    }
}

impl From<AfterRenderArgs> for Loop {
    fn from(args: AfterRenderArgs) -> Self {
        Loop::AfterRender(args)
    }
}

impl From<AfterRenderArgs> for Event {
    fn from(args: AfterRenderArgs) -> Self {
        Event::Loop(Loop::AfterRender(args))
    }
}

impl From<UpdateArgs> for Loop {
    fn from(args: UpdateArgs) -> Self {
        Loop::Update(args)
    }
}

impl From<UpdateArgs> for Event {
    fn from(args: UpdateArgs) -> Self {
        Event::Loop(Loop::Update(args))
    }
}

impl From<IdleArgs> for Loop {
    fn from(args: IdleArgs) -> Self {
        Loop::Idle(args)
    }
}

impl From<IdleArgs> for Event {
    fn from(args: IdleArgs) -> Self {
        Event::Loop(Loop::Idle(args))
    }
}

impl From<CloseArgs> for Input {
    fn from(args: CloseArgs) -> Self {
        Input::Close(args)
    }
}

impl<T> From<T> for Event
    where Input: From<T>
{
    fn from(args: T) -> Self {
        Event::Input(args.into())
    }
}

impl From<Loop> for Event {
    fn from(l: Loop) -> Self {
        Event::Loop(l)
    }
}

impl Into<Option<Input>> for Event {
    fn into(self) -> Option<Input> {
        if let Event::Input(input) = self {
            Some(input)
        } else {
            None
        }
    }
}

impl Into<Option<Loop>> for Event {
    fn into(self) -> Option<Loop> {
        if let Event::Loop(l) = self {
            Some(l)
        } else {
            None
        }
    }
}

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

    #[test]
    fn test_input_sync_send() {
        fn chk<T: Sync + Send>() {}

        chk::<Input>();
    }
}
<|endoftext|>