<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;

/// 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 }
    }

    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)
    }

    fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        unimplemented!()
    }

    fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        unimplemented!()
    }

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

    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)
    }

    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"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "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>Now with lambdas<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 }
    }

    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)
    }

    fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
        unimplemented!()
    }

    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)
    }

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

    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)
    }

    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"
                      , "set!"              , "unquote"
                      , "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!()
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::ast;
use syntax::ast::P;
use syntax::ext::base::ExtCtxt;
use syntax::codemap::DUMMY_SP;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a, 'b, 'c> {
  builder: &'a mut Builder,
  cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> BuildSetters<'a, 'b, 'c> {
  pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
             -> BuildSetters<'a, 'b, 'c> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a, 'b, 'c> node::RegVisitor for BuildSetters<'a, 'b, 'c> {
  fn visit_prim_reg<'a>(&'a mut self, path: &Vec<String>,
      reg: &'a node::Reg, _width: node::RegWidth, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => d.node,
    None => cx.ident_of("no documentation"),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $name {
      value: $packed_ty,
      mask: $packed_ty,
      reg: &'static $reg_ty,
    }
  );
  item.unwrap()
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>)
                 -> P<ast::Item> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let item = quote_item!(cx,
    #[doc="Create a new updater"]
    pub fn new(reg: &'static $reg_ty) -> $setter_ty {
      $setter_ty {
        value: 0,
        mask: 0,
        reg: reg,
      }
    });
  item.unwrap()
}

fn build_drop<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  let item = quote_item!(cx,
    #[unsafe_destructor]
    #[doc = "This performs the register update"]
    impl Drop for $setter_ty {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = self.reg.value.get() & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done<'a>(cx: &'a ExtCtxt) -> P<ast::Method>
{
  quote_method!(cx,
    #[doc="Commit changes to register. This is to allow chains of `set_*` \
           invocations to be used as a statement."]
    pub fn done(self) {}
  )
}

fn build_impl<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path);
  let setter_ty: P<ast::Ty> = cx.ty_ident(
    DUMMY_SP,
    utils::setter_name(cx, path));
  let methods: Vec<P<ast::Method>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done: P<ast::Method> = build_done(cx);
  let impl_ = quote_item!(cx,
    #[allow(dead_code)]
    impl $setter_ty {
      $new
      $methods
      $done
    }
    );
  impl_.unwrap()
}

fn build_field_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> Option<P<ast::Method>>
{
  match field.access {
    node::ReadOnly => None,
    node::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                          field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self, new_value: $field_ty)
          -> &'a mut $setter_ty {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self, idx: uint, new_value: $field_ty)
        -> &'a mut $setter_ty {
          self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
          self.mask |= $mask << $shift;
          self
      }
    )
  }
}

fn build_field_clear_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self) -> &'a mut $setter_ty {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self, idx: uint)
                          -> &'a mut $setter_ty {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
      }
    )
  }
}
<commit_msg>ioreg: No need to read from write-only registers<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::ast;
use syntax::ast::P;
use syntax::ext::base::ExtCtxt;
use syntax::codemap::DUMMY_SP;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a, 'b, 'c> {
  builder: &'a mut Builder,
  cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> BuildSetters<'a, 'b, 'c> {
  pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
             -> BuildSetters<'a, 'b, 'c> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a, 'b, 'c> node::RegVisitor for BuildSetters<'a, 'b, 'c> {
  fn visit_prim_reg<'a>(&'a mut self, path: &Vec<String>,
      reg: &'a node::Reg, _width: node::RegWidth, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => d.node,
    None => cx.ident_of("no documentation"),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $name {
      value: $packed_ty,
      mask: $packed_ty,
      reg: &'static $reg_ty,
    }
  );
  item.unwrap()
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>)
                 -> P<ast::Item> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let item = quote_item!(cx,
    #[doc="Create a new updater"]
    pub fn new(reg: &'static $reg_ty) -> $setter_ty {
      $setter_ty {
        value: 0,
        mask: 0,
        reg: reg,
      }
    });
  item.unwrap()
}

fn build_drop<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, self.reg.value.get())
    };

  let item = quote_item!(cx,
    #[unsafe_destructor]
    #[doc = "This performs the register update"]
    impl Drop for $setter_ty {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done<'a>(cx: &'a ExtCtxt) -> P<ast::Method>
{
  quote_method!(cx,
    #[doc="Commit changes to register. This is to allow chains of `set_*` \
           invocations to be used as a statement."]
    pub fn done(self) {}
  )
}

fn build_impl<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path);
  let setter_ty: P<ast::Ty> = cx.ty_ident(
    DUMMY_SP,
    utils::setter_name(cx, path));
  let methods: Vec<P<ast::Method>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done: P<ast::Method> = build_done(cx);
  let impl_ = quote_item!(cx,
    #[allow(dead_code)]
    impl $setter_ty {
      $new
      $methods
      $done
    }
    );
  impl_.unwrap()
}

fn build_field_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> Option<P<ast::Method>>
{
  match field.access {
    node::ReadOnly => None,
    node::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                          field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self, new_value: $field_ty)
          -> &'a mut $setter_ty {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self, idx: uint, new_value: $field_ty)
        -> &'a mut $setter_ty {
          self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
          self.mask |= $mask << $shift;
          self
      }
    )
  }
}

fn build_field_clear_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self) -> &'a mut $setter_ty {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'a>(&'a mut self, idx: uint)
                          -> &'a mut $setter_ty {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
      }
    )
  }
}
<|endoftext|>


<commit_before>extern crate pb_rs;
extern crate prost_build;
extern crate protobuf_codegen_pure;

use pb_rs::types::{Config, FileDescriptor, RpcService};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::{env, fs};

fn generate_rpc_test<W: Write + ?Sized>(
    rpc: &RpcService,
    w: &mut W,
) -> Result<(), pb_rs::errors::Error> {
    /* Example:
        trait <service> {
            fn <func>(&self, arg: &<arg>) -> Result<<ret>, failure::Error>;
        }
    */

    writeln!(w, "\npub trait {SERVICE} {{", SERVICE = rpc.service_name)?;
    for func in rpc.functions.iter() {
        writeln!(
            w,
            "   fn {FUNC}(&self, arg: &{ARG}) -> std::result::Result<{RET}, quick_protobuf::Error>;",
            FUNC = func.name,
            ARG = func.arg,
            RET = func.ret
        )?;
    }
    writeln!(w, "}}\n")?;

    Ok(())
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    // protobuf
    protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
        out_dir: "src",
        input: &["src/perftest_data.proto"],
        includes: &["src"],
        customize: protobuf_codegen_pure::Customize {
            ..Default::default()
        },
    })
    .expect("protoc");

    // quick-protobuf
    let quick_dest = Path::new(&out_dir).join("perftest_data_quick.rs");
    let config = Config {
        in_file: PathBuf::from("src/perftest_data.proto"),
        out_file: quick_dest,
        single_module: true,
        import_search_path: vec![PathBuf::from("src")],
        no_output: false,
        error_cycle: false,
        headers: false,
        dont_use_cow: false,
        custom_struct_derive: vec![],
        custom_repr: None,
        custom_rpc_generator: Box::new(|rpc, writer| generate_rpc_test(rpc, writer)),
        custom_includes: Vec::new(),
        owned: false,
        hashbrown: false,
        nostd: false,
    };
    FileDescriptor::write_proto(&config).unwrap();

    // prost
    let old = ::std::env::var("OUT_DIR");
    env::set_var("OUT_DIR", ".");
    prost_build::compile_protos(&["src/perftest_data.proto"], &["src"]).unwrap();
    let _ = old.map(|val| env::set_var("OUT_DIR", &val));
    fs::rename("perftest_data.rs", "src/perftest_data_prost.rs").unwrap();
}
<commit_msg>Add missing gen_info field<commit_after>extern crate pb_rs;
extern crate prost_build;
extern crate protobuf_codegen_pure;

use pb_rs::types::{Config, FileDescriptor, RpcService};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::{env, fs};

fn generate_rpc_test<W: Write + ?Sized>(
    rpc: &RpcService,
    w: &mut W,
) -> Result<(), pb_rs::errors::Error> {
    /* Example:
        trait <service> {
            fn <func>(&self, arg: &<arg>) -> Result<<ret>, failure::Error>;
        }
    */

    writeln!(w, "\npub trait {SERVICE} {{", SERVICE = rpc.service_name)?;
    for func in rpc.functions.iter() {
        writeln!(
            w,
            "   fn {FUNC}(&self, arg: &{ARG}) -> std::result::Result<{RET}, quick_protobuf::Error>;",
            FUNC = func.name,
            ARG = func.arg,
            RET = func.ret
        )?;
    }
    writeln!(w, "}}\n")?;

    Ok(())
}

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    // protobuf
    protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
        out_dir: "src",
        input: &["src/perftest_data.proto"],
        includes: &["src"],
        customize: protobuf_codegen_pure::Customize {
            ..Default::default()
        },
    })
    .expect("protoc");

    // quick-protobuf
    let quick_dest = Path::new(&out_dir).join("perftest_data_quick.rs");
    let config = Config {
        in_file: PathBuf::from("src/perftest_data.proto"),
        out_file: quick_dest,
        single_module: true,
        import_search_path: vec![PathBuf::from("src")],
        no_output: false,
        error_cycle: false,
        headers: false,
        dont_use_cow: false,
        custom_struct_derive: vec![],
        custom_repr: None,
        custom_rpc_generator: Box::new(|rpc, writer| generate_rpc_test(rpc, writer)),
        custom_includes: Vec::new(),
        owned: false,
        hashbrown: false,
        nostd: false,
        gen_info: false,
    };
    FileDescriptor::write_proto(&config).unwrap();

    // prost
    let old = ::std::env::var("OUT_DIR");
    env::set_var("OUT_DIR", ".");
    prost_build::compile_protos(&["src/perftest_data.proto"], &["src"]).unwrap();
    let _ = old.map(|val| env::set_var("OUT_DIR", &val));
    fs::rename("perftest_data.rs", "src/perftest_data_prost.rs").unwrap();
}
<|endoftext|>


<commit_before>mod partially_persistent_nonindexed_set {
  use std::sync::{Arc};
  use std::sync::atomic::{AtomicBool, Ordering};
  use std::cmp::min;
  use std::collections::HashSet;
  use std::hash::Hash;
  use std::mem;
  use std::cell::{UnsafeCell};
  use std::marker;use std::fmt::Debug;
use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

  #[derive (Clone, Debug)]
  struct Entry <K: Clone + Eq> {
    key: K,
    insertion: bool,
  }
  //using Vec< in this buffer type has unnecessary indirection, but I was unable to find
  //a library that does the job safely without it.
  //Compare Arc<[Entry<K>]>, which could behave unsafely if I
  //didn't initialize it, but would waste time if I did.
  #[derive (Debug)]
  struct BufferInner <K: Clone + Eq> {
    data: Vec<Entry <K>>,
    marker: AtomicBool,
  }
  #[derive (Clone, Debug)]
  struct Buffer <K: Clone + Eq> {
    data: Arc <UnsafeCell <BufferInner <K> >>,
    deletions: usize,
  }

  #[derive (Debug)]
  pub struct Snapshot <K: Clone + Eq> {
    buffer: Buffer <K>,
    used_length: usize,
  }
  #[derive (Debug)]
  pub struct SnapshotIter <'a, K: Clone + Eq + Hash + 'a> {
    snapshot: & 'a Snapshot <K>,
    position: usize,
    ignore: HashSet <K>,
  }

  #[derive (Debug)]
  pub struct Set <K: Clone + Eq> {
    live_buffer: Buffer <K>,
    next_buffer: Buffer <K>,
    next_transfer_index: usize,
    potential_next_buffer_usage: usize,
    operating: bool,
  }
  unsafe impl<K: Clone + Eq + Sync> Send for Snapshot <K>{}
  unsafe impl<K: Clone + Eq + Sync> Sync for Snapshot <K>{}
  impl<K: Clone + Eq + Hash> Snapshot <K> {
    pub fn iter <'a> (& 'a self)->SnapshotIter <'a, K> {
      //this Acquire should sync with at least the Release performed just after the
      //last insertion into this buffer.
      //To make sure we only need to do this once, at the beginning of iteration,
      //we deliberately unimplemented Send for the iterator type
      unsafe {(*self.buffer.data.get()).marker.load (Ordering::Acquire)};

      SnapshotIter {
        snapshot: self,
        position: self.used_length,
        ignore: HashSet::with_capacity(self.buffer.deletions),
      }
    }
  }
  impl<'a, K> !marker::Send for SnapshotIter <'a, K> {}
  impl<'a, K: Clone + Eq + Hash> SnapshotIter <'a, K> {
    /// Do a single iteration step, which MAY return an iteration result,
    /// and is guaranteed to finish in O(1) time (worst-case except for bad luck with hashing).
    pub fn step (&mut self)->Option <Option <K>> {
      if self.position == 0 {return Some (None);}
      self.position -= 1;
      let entry = unsafe {& (*self.snapshot.buffer.data.get()).data [self.position]};
      if entry.insertion == false {
        self.ignore.insert (entry.key.clone());
      }
      else if !self.ignore.contains (& entry.key) {
        return Some (Some (entry.key.clone()));
      }
      None
    }
  }
  impl<'a, K: Clone + Eq + Hash > Iterator for SnapshotIter <'a, K> {
    type Item = K;
    fn next (&mut self)->Option <K> {
      loop {
        if let Some (result) = self.step() {return result;}
      }
    }
  }
  impl<K: Clone + Eq + Debug> Set <K> {
    pub fn new()->Set <K> {
      Set {
        live_buffer: Buffer {data: Arc::new (UnsafeCell::new (BufferInner {data: Vec::new (), marker: AtomicBool::new(false)})), deletions: 0},
        next_buffer: Buffer {data: Arc::new (UnsafeCell::new (BufferInner {data: Vec:: with_capacity(2), marker: AtomicBool::new(false)})), deletions: 0},
        next_transfer_index: 0,
        potential_next_buffer_usage: 0,
        operating: false,
      }
    }
    /// Adds a value to the set.
    ///
    /// Complexity: O(1) worst-case if K does not implement Drop, O(1) amortized otherwise.
    pub fn insert <F: Fn (& K)->bool> (&mut self, key: K, currently_existent: & F) {
      assert!(!self.operating, "Attempt to call PartiallyPersistentNonindexedSet::insert() from inside its own existence checker callback; what ghastly code led to this situation?");
      self.operating = true;
      self.make_room (currently_existent);
      let live_data = unsafe {self.live_buffer.data.get().as_mut().unwrap()};
      live_data.data.push (Entry {key: key, insertion: true});
      self.potential_next_buffer_usage += 1;
      live_data.marker.store (false, Ordering::Release);
      self.operating = false;
    }
    /// Removes a value from the set.
    ///
    /// Complexity: O(1) worst-case if K does not implement Drop, O(1) amortized otherwise.
    pub fn remove <F: Fn (& K)->bool> (&mut self, key: K, currently_existent: & F) {
      assert!(!self.operating, "Attempt to call PartiallyPersistentNonindexedSet::insert() from inside its own existence checker callback; what ghastly code led to this situation?");
      self.operating = true;
      self.make_room (currently_existent);
      let live_data = unsafe {self.live_buffer.data.get().as_mut().unwrap()};
      let next_data = unsafe {self.next_buffer.data.get().as_mut().unwrap()};
      self.live_buffer.deletions += 1;
      live_data.data.push (Entry {key: key.clone(), insertion: false});
      // the next buffer doesn't necessarily have an insertion
      // corresponding to this deletion, so this could be wasteful. However,
      // it would also be wasteful to look up whether the insertion is there
      // (we currently get away with not even being ABLE to do so)
      self.next_buffer.deletions += 1;
      next_data.data.push (Entry {key: key, insertion: false});
      self.potential_next_buffer_usage += 1;
      live_data.marker.store (false, Ordering::Release);
      self.operating = false;
    }
    /// Takes out a snapshot to the current state of the set.
    ///
    /// These snapshots can safely be passed to other threads
    /// even as you continue to modify the set.
    ///
    /// Complexity: O(1) worst-case if K does not implement Drop, O(1) amortized otherwise.
    pub fn snapshot (&self)->Snapshot <K> {
      Snapshot {buffer: self.live_buffer.clone(), used_length: unsafe {(*self.live_buffer.data.get()).data.len()}}
    }

    //After let ops = operations_before_reset_possibly_needed operations, there may be in next buffer: current live insertions - current legit live deletions - ops insertions, and current next deletions + ops deletions. We want deletions/insertions <= 1/6 on reset, so…
    //(Next deletions + ops)/(live insertions - legit deletions - ops) <= 1/6
    //next deletions + ops <= (live insertions - legit deletions - ops)/3
    //6 (next deletions + ops) <= live insertions - legit deletions - ops
    //7 ops <= live insertions - legit deletions - 6 next deletions
    //it's okay to overestimate legit deletions, resulting in the following more strict condition on ops:
    //7 ops <= live insertions - live deletions - 6 next deletions
    //ops <= ((live insertions - live deletions - 6 next deletions)/7)
    //ops <= ((live insertions - live deletions - 6 next deletions)/7).floor()
    //But actually we have to tolerate one extra deletion to deal with
    //the case where a deletion is added immediately after a reset.
    //After reset + deletion, new ops could be forced as low as
    //new ops <= (((live insertions - legit deletions - ops) - ops - 7)/7).floor()
    //we also need to obey the condition
    //(new ops + 1)*X >= ((live insertions - legit deletions) + ops + new ops)
    //(new ops)*(X+1) + X >= ((live insertions - legit deletions) + ops)
    //new ops >= ((live insertions - legit deletions) + ops - X)/(X+1)
    //(((live insertions - legit deletions - ops) - ops - 7)/7 >= ((live insertions - legit deletions) + ops - X)/(X+1)
    //(((live insertions - legit deletions - ops) - ops - 7)*(X+1) >= ((live insertions - legit deletions) + ops - X)*7
    //(live insertions - legit deletions)*(X + 1 - 7) + (7)*(X+1) >= ops*(7 + 2X + 2) - X*7
    //(live insertions - legit deletions)*(X + 1 - 7) + 7 >= ops*(7 + 2X + 2)

    //(live insertions - legit deletions - 2*ops)*(X) >= ops*(9) + (live insertions - legit deletions)*6 - 7
    //X >= (ops*(9) + (live insertions - legit deletions)*6 - 7)/(live insertions - legit deletions - 2*ops)
    //and ops can be up to 1/7 of that insertion count, so
    //X >= (Z*(9/7) + Z*6 - 7)/(Z - 2*Z/7)
    //X >= (Z*(51/7) - 7)/(5*Z/7)
    //X >= (Z*(51) - 49)/(5*Z)
    //X >= 51/5 >10
    fn make_room <F: Fn (& K)->bool> (&mut self, currently_existent: F) {
  const MAX_TRANSFER_SPEED: usize = 11;
      unsafe {assert!((*self.next_buffer.data.get()).data.len() <= self.potential_next_buffer_usage)};
      let live_data = unsafe {self.live_buffer.data.get().as_ref().unwrap()};
      let next_data = unsafe {self.next_buffer.data.get().as_mut().unwrap()};
      //printlnerr!("starting {:?} \n LIFE: {:?}\n NEXT: {:?}\n CAPACITIES: {} {} DELETIONS: {}/{} {}/{} ", self, live_data, next_data, live_data.data.capacity(), next_data.data.capacity(), self.live_buffer.deletions, live_data.data.len(), self.next_buffer.deletions, next_data.data.len());
      let buffer_pushes_before_reset_needed = min (
        live_data.data.capacity() - live_data.data.len(),
        next_data.data.capacity()/2 - self.potential_next_buffer_usage,
      );
      let current_insertions = live_data.data.len() - self.live_buffer.deletions;
      //let tolerable_deletions = (current_insertions*5)/12;
      //let deletions_before_reset_needed = tolerable_deletions - self.live_buffer.deletions;
      let deletions_before_reset_needed = (current_insertions + 7 - self.live_buffer.deletions - 6*self.next_buffer.deletions)/7;
      let operations_before_reset_possibly_needed = min (buffer_pushes_before_reset_needed, deletions_before_reset_needed);
      assert!(self.next_transfer_index <= live_data.data.len() );
      let transfer_steps_needed_before_reset_possible = live_data.data.len() + operations_before_reset_possibly_needed - self.next_transfer_index;
      //printlnerr!("NEEDED {:?} \n OPERATIONS: {:?}\n (buffer pushes): {:?}\n (deletions): {} {} ", transfer_steps_needed_before_reset_possible , operations_before_reset_possibly_needed , buffer_pushes_before_reset_needed , deletions_before_reset_needed , "something");
      assert!(transfer_steps_needed_before_reset_possible <= (operations_before_reset_possibly_needed + 1) * MAX_TRANSFER_SPEED);
      if transfer_steps_needed_before_reset_possible >operations_before_reset_possibly_needed * MAX_TRANSFER_SPEED {
        for _ in 0..MAX_TRANSFER_SPEED {
          if let Some (entry) = live_data.data.get (self.next_transfer_index) {
            if entry.insertion && currently_existent (& entry.key) {
              next_data.data.push ((*entry).clone());
            }
            self.next_transfer_index += 1;
          }
          else {break;}
        }
      }
      //printlnerr!("ending {:?} \n LIFE: {:?}\n NEXT: {:?}\n CAPACITIES: {} {} ", self, live_data, next_data, live_data.data.capacity(), next_data.data.capacity());
      if operations_before_reset_possibly_needed == 0 {
        self.next_transfer_index = 0;
        self.potential_next_buffer_usage = next_data.data.len() - self.next_buffer.deletions;
        mem::swap (&mut self.live_buffer, &mut self.next_buffer);
        //danger: after we overwrite self.next_buffer, we may have deallocated
        //the memory for live_data
        self.next_buffer = Buffer {
          data: Arc::new (UnsafeCell::new (BufferInner {data: Vec::with_capacity ((self.potential_next_buffer_usage + 1)*4), marker: AtomicBool::new(false)})), deletions: 0,
        };
      }
      //printlnerr!("ending {:?}", self);
      unsafe {
        assert!((*self.live_buffer.data.get()).data.len() < (*self.live_buffer.data.get()).data.capacity());
        assert!((*self.next_buffer.data.get()).data.len() <= self.potential_next_buffer_usage);
        assert!(self.potential_next_buffer_usage < (*self.next_buffer.data.get()).data.capacity()/2);
      }
    }
  }
#[cfg (test)]
mod tests {
use super::*; use std::collections::HashSet;        use std::thread; use std::sync::mpsc::channel;
  #[quickcheck]
  fn test_operation_sequence (operations: Vec<(usize, bool)>)->bool {
    let mut existences: HashSet <usize> = HashSet::new();
    let mut set: Set <usize> = Set::new();

    let (send_snapshot, receive_snapshot) = channel::<Option <(Snapshot <usize>, HashSet <usize>)>>();
    let (send_results, receive_results) = channel();
    let check_thread = thread::spawn ( move | | {
      while let Some ((snapshot, checker)) = receive_snapshot.recv().unwrap() {
        let checker_2 = snapshot.iter().collect();
        send_results.send (checker == checker_2);
      }
    });
    for operation in operations {
      if existences.contains(& operation.0) != operation.1 {
        if operation.1 {
          existences.insert (operation.0);
          set.insert (operation.0, & | value | existences.contains (value));
        } else {
          existences.remove (& operation. 0);
          set.remove (operation.0, & | value | existences.contains (value));
        }
        let checker = existences.clone();
        let snapshot = set.snapshot();

        send_snapshot.send (Some ((snapshot, checker)));
        if ! receive_results.recv().unwrap() {send_snapshot.send (None); check_thread.join(); return false;}
      }
    }
    send_snapshot.send (None); check_thread.join();
    true
}
//#[test]
fn hack () {

//test_operation_sequence ((0..100).map (| number | (number, true)).collect());
}}
}
<commit_msg>Use a smaller key size for tests, which might make successful deletions more common<commit_after>mod partially_persistent_nonindexed_set {
  use std::sync::{Arc};
  use std::sync::atomic::{AtomicBool, Ordering};
  use std::cmp::min;
  use std::collections::HashSet;
  use std::hash::Hash;
  use std::mem;
  use std::cell::{UnsafeCell};
  use std::marker;use std::fmt::Debug;
use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

  #[derive (Clone, Debug)]
  struct Entry <K: Clone + Eq> {
    key: K,
    insertion: bool,
  }
  //using Vec< in this buffer type has unnecessary indirection, but I was unable to find
  //a library that does the job safely without it.
  //Compare Arc<[Entry<K>]>, which could behave unsafely if I
  //didn't initialize it, but would waste time if I did.
  #[derive (Debug)]
  struct BufferInner <K: Clone + Eq> {
    data: Vec<Entry <K>>,
    marker: AtomicBool,
  }
  #[derive (Clone, Debug)]
  struct Buffer <K: Clone + Eq> {
    data: Arc <UnsafeCell <BufferInner <K> >>,
    deletions: usize,
  }

  #[derive (Debug)]
  pub struct Snapshot <K: Clone + Eq> {
    buffer: Buffer <K>,
    used_length: usize,
  }
  #[derive (Debug)]
  pub struct SnapshotIter <'a, K: Clone + Eq + Hash + 'a> {
    snapshot: & 'a Snapshot <K>,
    position: usize,
    ignore: HashSet <K>,
  }

  #[derive (Debug)]
  pub struct Set <K: Clone + Eq> {
    live_buffer: Buffer <K>,
    next_buffer: Buffer <K>,
    next_transfer_index: usize,
    potential_next_buffer_usage: usize,
    operating: bool,
  }
  unsafe impl<K: Clone + Eq + Sync> Send for Snapshot <K>{}
  unsafe impl<K: Clone + Eq + Sync> Sync for Snapshot <K>{}
  impl<K: Clone + Eq + Hash> Snapshot <K> {
    pub fn iter <'a> (& 'a self)->SnapshotIter <'a, K> {
      //this Acquire should sync with at least the Release performed just after the
      //last insertion into this buffer.
      //To make sure we only need to do this once, at the beginning of iteration,
      //we deliberately unimplemented Send for the iterator type
      unsafe {(*self.buffer.data.get()).marker.load (Ordering::Acquire)};

      SnapshotIter {
        snapshot: self,
        position: self.used_length,
        ignore: HashSet::with_capacity(self.buffer.deletions),
      }
    }
  }
  impl<'a, K> !marker::Send for SnapshotIter <'a, K> {}
  impl<'a, K: Clone + Eq + Hash> SnapshotIter <'a, K> {
    /// Do a single iteration step, which MAY return an iteration result,
    /// and is guaranteed to finish in O(1) time (worst-case except for bad luck with hashing).
    pub fn step (&mut self)->Option <Option <K>> {
      if self.position == 0 {return Some (None);}
      self.position -= 1;
      let entry = unsafe {& (*self.snapshot.buffer.data.get()).data [self.position]};
      if entry.insertion == false {
        self.ignore.insert (entry.key.clone());
      }
      else if !self.ignore.contains (& entry.key) {
        return Some (Some (entry.key.clone()));
      }
      None
    }
  }
  impl<'a, K: Clone + Eq + Hash > Iterator for SnapshotIter <'a, K> {
    type Item = K;
    fn next (&mut self)->Option <K> {
      loop {
        if let Some (result) = self.step() {return result;}
      }
    }
  }
  impl<K: Clone + Eq + Debug> Set <K> {
    pub fn new()->Set <K> {
      Set {
        live_buffer: Buffer {data: Arc::new (UnsafeCell::new (BufferInner {data: Vec::new (), marker: AtomicBool::new(false)})), deletions: 0},
        next_buffer: Buffer {data: Arc::new (UnsafeCell::new (BufferInner {data: Vec:: with_capacity(2), marker: AtomicBool::new(false)})), deletions: 0},
        next_transfer_index: 0,
        potential_next_buffer_usage: 0,
        operating: false,
      }
    }
    /// Adds a value to the set.
    ///
    /// Complexity: O(1) worst-case if K does not implement Drop, O(1) amortized otherwise.
    pub fn insert <F: Fn (& K)->bool> (&mut self, key: K, currently_existent: & F) {
      assert!(!self.operating, "Attempt to call PartiallyPersistentNonindexedSet::insert() from inside its own existence checker callback; what ghastly code led to this situation?");
      self.operating = true;
      self.make_room (currently_existent);
      let live_data = unsafe {self.live_buffer.data.get().as_mut().unwrap()};
      live_data.data.push (Entry {key: key, insertion: true});
      self.potential_next_buffer_usage += 1;
      live_data.marker.store (false, Ordering::Release);
      self.operating = false;
    }
    /// Removes a value from the set.
    ///
    /// Complexity: O(1) worst-case if K does not implement Drop, O(1) amortized otherwise.
    pub fn remove <F: Fn (& K)->bool> (&mut self, key: K, currently_existent: & F) {
      assert!(!self.operating, "Attempt to call PartiallyPersistentNonindexedSet::insert() from inside its own existence checker callback; what ghastly code led to this situation?");
      self.operating = true;
      self.make_room (currently_existent);
      let live_data = unsafe {self.live_buffer.data.get().as_mut().unwrap()};
      let next_data = unsafe {self.next_buffer.data.get().as_mut().unwrap()};
      self.live_buffer.deletions += 1;
      live_data.data.push (Entry {key: key.clone(), insertion: false});
      // the next buffer doesn't necessarily have an insertion
      // corresponding to this deletion, so this could be wasteful. However,
      // it would also be wasteful to look up whether the insertion is there
      // (we currently get away with not even being ABLE to do so)
      self.next_buffer.deletions += 1;
      next_data.data.push (Entry {key: key, insertion: false});
      self.potential_next_buffer_usage += 1;
      live_data.marker.store (false, Ordering::Release);
      self.operating = false;
    }
    /// Takes out a snapshot to the current state of the set.
    ///
    /// These snapshots can safely be passed to other threads
    /// even as you continue to modify the set.
    ///
    /// Complexity: O(1) worst-case if K does not implement Drop, O(1) amortized otherwise.
    pub fn snapshot (&self)->Snapshot <K> {
      Snapshot {buffer: self.live_buffer.clone(), used_length: unsafe {(*self.live_buffer.data.get()).data.len()}}
    }

    //After let ops = operations_before_reset_possibly_needed operations, there may be in next buffer: current live insertions - current legit live deletions - ops insertions, and current next deletions + ops deletions. We want deletions/insertions <= 1/6 on reset, so…
    //(Next deletions + ops)/(live insertions - legit deletions - ops) <= 1/6
    //next deletions + ops <= (live insertions - legit deletions - ops)/3
    //6 (next deletions + ops) <= live insertions - legit deletions - ops
    //7 ops <= live insertions - legit deletions - 6 next deletions
    //it's okay to overestimate legit deletions, resulting in the following more strict condition on ops:
    //7 ops <= live insertions - live deletions - 6 next deletions
    //ops <= ((live insertions - live deletions - 6 next deletions)/7)
    //ops <= ((live insertions - live deletions - 6 next deletions)/7).floor()
    //But actually we have to tolerate one extra deletion to deal with
    //the case where a deletion is added immediately after a reset.
    //After reset + deletion, new ops could be forced as low as
    //new ops <= (((live insertions - legit deletions - ops) - ops - 7)/7).floor()
    //we also need to obey the condition
    //(new ops + 1)*X >= ((live insertions - legit deletions) + ops + new ops)
    //(new ops)*(X+1) + X >= ((live insertions - legit deletions) + ops)
    //new ops >= ((live insertions - legit deletions) + ops - X)/(X+1)
    //(((live insertions - legit deletions - ops) - ops - 7)/7 >= ((live insertions - legit deletions) + ops - X)/(X+1)
    //(((live insertions - legit deletions - ops) - ops - 7)*(X+1) >= ((live insertions - legit deletions) + ops - X)*7
    //(live insertions - legit deletions)*(X + 1 - 7) + (7)*(X+1) >= ops*(7 + 2X + 2) - X*7
    //(live insertions - legit deletions)*(X + 1 - 7) + 7 >= ops*(7 + 2X + 2)

    //(live insertions - legit deletions - 2*ops)*(X) >= ops*(9) + (live insertions - legit deletions)*6 - 7
    //X >= (ops*(9) + (live insertions - legit deletions)*6 - 7)/(live insertions - legit deletions - 2*ops)
    //and ops can be up to 1/7 of that insertion count, so
    //X >= (Z*(9/7) + Z*6 - 7)/(Z - 2*Z/7)
    //X >= (Z*(51/7) - 7)/(5*Z/7)
    //X >= (Z*(51) - 49)/(5*Z)
    //X >= 51/5 >10
    fn make_room <F: Fn (& K)->bool> (&mut self, currently_existent: F) {
  const MAX_TRANSFER_SPEED: usize = 11;
      unsafe {assert!((*self.next_buffer.data.get()).data.len() <= self.potential_next_buffer_usage)};
      let live_data = unsafe {self.live_buffer.data.get().as_ref().unwrap()};
      let next_data = unsafe {self.next_buffer.data.get().as_mut().unwrap()};
      //printlnerr!("starting {:?} \n LIFE: {:?}\n NEXT: {:?}\n CAPACITIES: {} {} DELETIONS: {}/{} {}/{} ", self, live_data, next_data, live_data.data.capacity(), next_data.data.capacity(), self.live_buffer.deletions, live_data.data.len(), self.next_buffer.deletions, next_data.data.len());
      let buffer_pushes_before_reset_needed = min (
        live_data.data.capacity() - live_data.data.len(),
        next_data.data.capacity()/2 - self.potential_next_buffer_usage,
      );
      let current_insertions = live_data.data.len() - self.live_buffer.deletions;
      //let tolerable_deletions = (current_insertions*5)/12;
      //let deletions_before_reset_needed = tolerable_deletions - self.live_buffer.deletions;
      let deletions_before_reset_needed = (current_insertions + 7 - self.live_buffer.deletions - 6*self.next_buffer.deletions)/7;
      let operations_before_reset_possibly_needed = min (buffer_pushes_before_reset_needed, deletions_before_reset_needed);
      assert!(self.next_transfer_index <= live_data.data.len() );
      let transfer_steps_needed_before_reset_possible = live_data.data.len() + operations_before_reset_possibly_needed - self.next_transfer_index;
      //printlnerr!("NEEDED {:?} \n OPERATIONS: {:?}\n (buffer pushes): {:?}\n (deletions): {} {} ", transfer_steps_needed_before_reset_possible , operations_before_reset_possibly_needed , buffer_pushes_before_reset_needed , deletions_before_reset_needed , "something");
      assert!(transfer_steps_needed_before_reset_possible <= (operations_before_reset_possibly_needed + 1) * MAX_TRANSFER_SPEED);
      if transfer_steps_needed_before_reset_possible >operations_before_reset_possibly_needed * MAX_TRANSFER_SPEED {
        for _ in 0..MAX_TRANSFER_SPEED {
          if let Some (entry) = live_data.data.get (self.next_transfer_index) {
            if entry.insertion && currently_existent (& entry.key) {
              next_data.data.push ((*entry).clone());
            }
            self.next_transfer_index += 1;
          }
          else {break;}
        }
      }
      //printlnerr!("ending {:?} \n LIFE: {:?}\n NEXT: {:?}\n CAPACITIES: {} {} ", self, live_data, next_data, live_data.data.capacity(), next_data.data.capacity());
      if operations_before_reset_possibly_needed == 0 {
        self.next_transfer_index = 0;
        self.potential_next_buffer_usage = next_data.data.len() - self.next_buffer.deletions;
        mem::swap (&mut self.live_buffer, &mut self.next_buffer);
        //danger: after we overwrite self.next_buffer, we may have deallocated
        //the memory for live_data
        self.next_buffer = Buffer {
          data: Arc::new (UnsafeCell::new (BufferInner {data: Vec::with_capacity ((self.potential_next_buffer_usage + 1)*4), marker: AtomicBool::new(false)})), deletions: 0,
        };
      }
      //printlnerr!("ending {:?}", self);
      unsafe {
        assert!((*self.live_buffer.data.get()).data.len() < (*self.live_buffer.data.get()).data.capacity());
        assert!((*self.next_buffer.data.get()).data.len() <= self.potential_next_buffer_usage);
        assert!(self.potential_next_buffer_usage < (*self.next_buffer.data.get()).data.capacity()/2);
      }
    }
  }
#[cfg (test)]
mod tests {
use super::*; use std::collections::HashSet;        use std::thread; use std::sync::mpsc::channel;
type key = u8;
  #[quickcheck]
  fn test_operation_sequence (operations: Vec<(key, bool)>)->bool {
    let mut existences: HashSet <key> = HashSet::new();
    let mut set: Set <key> = Set::new();

    let (send_snapshot, receive_snapshot) = channel::<Option <(Snapshot <key>, HashSet <key>)>>();
    let (send_results, receive_results) = channel();
    let check_thread = thread::spawn ( move | | {
      while let Some ((snapshot, checker)) = receive_snapshot.recv().unwrap() {
        let checker_2 = snapshot.iter().collect();
        send_results.send (checker == checker_2);
      }
    });
    for operation in operations {
      if existences.contains(& operation.0) != operation.1 {
        if operation.1 {
          existences.insert (operation.0);
          set.insert (operation.0, & | value | existences.contains (value));
        } else {
          existences.remove (& operation. 0);
          set.remove (operation.0, & | value | existences.contains (value));
        }
        let checker = existences.clone();
        let snapshot = set.snapshot();

        send_snapshot.send (Some ((snapshot, checker)));
        if ! receive_results.recv().unwrap() {send_snapshot.send (None); check_thread.join(); return false;}
      }
    }
    send_snapshot.send (None); check_thread.join();
    true
}
//#[test]
fn hack () {

//test_operation_sequence ((0..100).map (| number | (number, true)).collect());
}}
}
<|endoftext|>


<commit_before>fn main() {
    // Prevent building SPIRV-Cross on wasm32 target
    let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH");
    if let Ok(arch) = target_arch {
        if "wasm32" == arch {
            return;
        }
    }

    let target_os = std::env::var("CARGO_CFG_TARGET_OS");
    let is_macos = target_os.is_ok() && target_os.unwrap() == "macos";

    let mut build = cc::Build::new();
    build.cpp(true);

    let compiler = build.try_get_compiler();
    let is_clang = compiler.is_ok() && compiler.unwrap().is_like_clang();

    if is_macos && is_clang {
        build.flag("-std=c++14").cpp_set_stdlib("c++");
    } else {
        build.flag_if_supported("-std=c++14");
    }

    build
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_parsed_ir.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_parser.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp");

    // Ideally the GLSL compiler would be omitted here, but the HLSL and MSL compiler
    // currently inherit from it. So it's necessary to unconditionally include it here.
    build
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_GLSL");

    #[cfg(feature = "hlsl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_HLSL");

    #[cfg(feature = "msl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_MSL");

    build.compile("spirv-cross-rust-wrapper");
}
<commit_msg>workaround ios build issues<commit_after>fn main() {
    // Prevent building SPIRV-Cross on wasm32 target
    let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH");
    if let Ok(arch) = target_arch {
        if "wasm32" == arch {
            return;
        }
    }

    let target_vendor = std::env::var("CARGO_CFG_TARGET_VENDOR");
    let is_apple = target_vendor.is_ok() && target_vendor.unwrap() == "apple";

    let target_os = std::env::var("CARGO_CFG_TARGET_OS");
    let is_ios = target_os.is_ok() && target_os.unwrap() == "ios";

    let mut build = cc::Build::new();
    build.cpp(true);

    let compiler = build.try_get_compiler();
    let is_clang = compiler.is_ok() && compiler.unwrap().is_like_clang();

    if is_apple && (is_clang || is_ios) {
        build.flag("-std=c++14").cpp_set_stdlib("c++");
    } else {
        build.flag_if_supported("-std=c++14");
    }

    build
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_parsed_ir.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_parser.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp");

    // Ideally the GLSL compiler would be omitted here, but the HLSL and MSL compiler
    // currently inherit from it. So it's necessary to unconditionally include it here.
    build
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_GLSL");

    #[cfg(feature = "hlsl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_HLSL");

    #[cfg(feature = "msl")]
    build
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag("-DSPIRV_CROSS_WRAPPER_MSL");

    build.compile("spirv-cross-rust-wrapper");
}
<|endoftext|>


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

use std::{borrow::Cow, path::Path};

pub(super) fn has_newline_at_eof(_file: &Path, contents: &str) -> Result<(), Cow<'static, str>> {
    if !contents.ends_with('\n') {
        Err("missing a newline at EOF".into())
    } else {
        Ok(())
    }
}

pub(super) fn has_trailing_whitespace(
    _file: &Path,
    contents: &str,
) -> Result<(), Cow<'static, str>> {
    for (ln, line) in contents
        .lines()
        .enumerate()
        .map(|(ln, line)| (ln + 1, line))
    {
        if line.trim_end() != line {
            return Err(Cow::Owned(format!("trailing whitespace on line {}", ln)));
        }
    }

    if contents
        .lines()
        .rev()
        .take_while(|line| line.is_empty())
        .count()
        > 0
    {
        return Err("trailing whitespace at EOF".into());
    }

    Ok(())
}
<commit_msg>[x] skip whitespace lints for .exp files<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::{borrow::Cow, convert, ffi::OsStr, path::Path, str};

pub(super) fn has_newline_at_eof(file: &Path, contents: &str) -> Result<(), Cow<'static, str>> {
    if skip_whitespace_checks(file) {
        return Ok(());
    }

    if !contents.ends_with('\n') {
        Err("missing a newline at EOF".into())
    } else {
        Ok(())
    }
}

pub(super) fn has_trailing_whitespace(
    file: &Path,
    contents: &str,
) -> Result<(), Cow<'static, str>> {
    if skip_whitespace_checks(file) {
        return Ok(());
    }

    for (ln, line) in contents
        .lines()
        .enumerate()
        .map(|(ln, line)| (ln + 1, line))
    {
        if line.trim_end() != line {
            return Err(Cow::Owned(format!("trailing whitespace on line {}", ln)));
        }
    }

    if contents
        .lines()
        .rev()
        .take_while(|line| line.is_empty())
        .count()
        > 0
    {
        return Err("trailing whitespace at EOF".into());
    }

    Ok(())
}

fn skip_whitespace_checks(file: &Path) -> bool {
    match file
        .extension()
        .map(OsStr::to_str)
        .and_then(convert::identity)
    {
        Some("exp") => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>// Anima Engine. The quirky game engine
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;

use time::Duration;

use mrusty::*;

use super::game::Game;
use super::super::scripting;

/// A `struct` used to run games from mruby directly.
///
/// Make sure you point to an mruby file with a `Game` `Class` defined which implements a method
/// `update(dt)`, where `dt` is a `Float` representing the time since the last frame.
///
/// # Examples
///
/// ```no-run
/// let game = MrubyGame::new(Path::new("game.rb"));
///
/// GameLoop::new(game).run();
/// ```
pub struct MrubyGame {
    pub mruby: MrubyType,
    pub game: Value
}

impl MrubyGame {
    /// Creates a new `MrubyGame` from an mruby script.
    ///
    /// Make sure you point to an mruby file with a `Game` `Class` defined which implements a
    /// method `update(dt)`, where `dt` is a `Float` representing the time since the last frame.
    ///
    /// # Examples
    ///
    /// ```no-run
    /// let game = MrubyGame::new(Path::new("game.rb"));
    ///
    /// GameLoop::new(game).run();
    /// ```
    pub fn new(script: &Path) -> MrubyGame {
        let mruby = scripting::get_mruby();

        mruby.execute(script).unwrap();

        let game = match mruby.run("Game.new") {
            Ok(game) => game,
            Err(_)   => panic!("Game class must be defined in mruby")
        };

        MrubyGame {
            mruby: mruby,
            game: game
        }
    }
}

impl Game for MrubyGame {
    fn update(&self, dt: Duration) -> bool {
        let seconds = dt.num_seconds() as f64;
        let nanoseconds = match dt.num_nanoseconds() {
            Some(nanoseconds) => nanoseconds as f64 / 1.0e+9,
            None              => 0f64
        };

        let dt = self.mruby.float(seconds + nanoseconds);

        self.game.call("update", vec![dt]).unwrap().to_bool().unwrap()
    }
}
<commit_msg>Replaced match with unwrap.<commit_after>// Anima Engine. The quirky game engine
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;

use time::Duration;

use mrusty::*;

use super::game::Game;
use super::super::scripting;

/// A `struct` used to run games from mruby directly.
///
/// Make sure you point to an mruby file with a `Game` `Class` defined which implements a method
/// `update(dt)`, where `dt` is a `Float` representing the time since the last frame.
///
/// # Examples
///
/// ```no-run
/// let game = MrubyGame::new(Path::new("game.rb"));
///
/// GameLoop::new(game).run();
/// ```
pub struct MrubyGame {
    pub mruby: MrubyType,
    pub game: Value
}

impl MrubyGame {
    /// Creates a new `MrubyGame` from an mruby script.
    ///
    /// Make sure you point to an mruby file with a `Game` `Class` defined which implements a
    /// method `update(dt)`, where `dt` is a `Float` representing the time since the last frame.
    ///
    /// # Examples
    ///
    /// ```no-run
    /// let game = MrubyGame::new(Path::new("game.rb"));
    ///
    /// GameLoop::new(game).run();
    /// ```
    pub fn new(script: &Path) -> MrubyGame {
        let mruby = scripting::get_mruby();

        mruby.execute(script).unwrap();

        let game = mruby.run("Game.new")
                        .unwrap_or_else(|_| { panic!("Game class must be defined in mruby") });

        MrubyGame {
            mruby: mruby,
            game: game
        }
    }
}

impl Game for MrubyGame {
    fn update(&self, dt: Duration) -> bool {
        let seconds = dt.num_seconds() as f64;
        let nanoseconds = match dt.num_nanoseconds() {
            Some(nanoseconds) => nanoseconds as f64 / 1.0e+9,
            None              => 0f64
        };

        let dt = self.mruby.float(seconds + nanoseconds);

        self.game.call("update", vec![dt]).unwrap().to_bool().unwrap()
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Hamming_numbers
// port of one of the scala solutions
extern crate num;
use num::bigint::BigUint;
use std::cmp::min;
use std::sync::spsc_queue::Queue;

fn int_to_biguint(i: int) -> BigUint {
    FromPrimitive::from_int(i).unwrap()
}

#[cfg(not(test))]
fn main() {
    let mut hamming = Hamming::new(1691);

    println!("first 20 Hamming numbers")
    for _ in range_inclusive(0,19) {
        print!("{} ", hamming.next().unwrap());
    }

    println!("\n\n1691st Hamming number");
    println!("{}",hamming.nth(1691-20).unwrap())
}

struct Hamming {
    q2: Queue<BigUint>,
    q3: Queue<BigUint>,
    q5: Queue<BigUint>
}

impl Hamming {
    fn new(n: uint) -> Hamming {
        let h = Hamming {
            q2: Queue::new(n),
            q3: Queue::new(n),
            q5: Queue::new(n)
        };

        h.q2.push(int_to_biguint(1));
        h.q3.push(int_to_biguint(1));
        h.q5.push(int_to_biguint(1));

        h
    }

    fn enqueue(&self, n: BigUint) {
        self.q2.push(n * int_to_biguint(2));
        self.q3.push(n * int_to_biguint(3));
        self.q5.push(n * int_to_biguint(5));
    }

}

impl Iterator<BigUint> for Hamming {
    fn next(&mut self) -> Option<BigUint> {
        let (head2, head3, head5) =
            (   self.q2.peek().unwrap(),
                self.q3.peek().unwrap(),
                self.q5.peek().unwrap());

        let n = min(head2.clone(), min(head3.clone(), head5.clone()));

        if *head2 == n {self.q2.pop();}
        if *head3 == n {self.q3.pop();}
        if *head5 == n {self.q5.pop();}

        self.enqueue(n.clone());
        Some(n)
    }
}

#[test]
fn create() {
    let h = Hamming::new(5);
    h.q2.push(int_to_biguint(1));
    h.q2.push(int_to_biguint(2));
    h.q2.push(int_to_biguint(4));

    let _ = h.q2.peek();
    assert!(h.q2.pop().unwrap() == int_to_biguint(1));
}

#[test]
fn try_enqueue() {
    let h = Hamming::new(5);
    h.enqueue(int_to_biguint(1));
    h.enqueue(int_to_biguint(2));
    h.enqueue(int_to_biguint(3));

    assert!(h.q2.pop().unwrap() == int_to_biguint(1));
    assert!(h.q3.pop().unwrap() == int_to_biguint(1));
    assert!(h.q5.pop().unwrap() == int_to_biguint(1));
    assert!(h.q2.pop().unwrap() == int_to_biguint(2));
    assert!(h.q3.pop().unwrap() == int_to_biguint(3));
    assert!(h.q5.pop().unwrap() == int_to_biguint(5));
 }

#[test]
fn hamming_iter() {
    let mut hamming = Hamming::new(20);
    assert!(hamming.nth(19).unwrap() == int_to_biguint(36));
}<commit_msg>corrected range (was printing the first 19 numbers instead of 20). use range_inclusive<commit_after>// Implements http://rosettacode.org/wiki/Hamming_numbers
// port of one of the scala solutions
extern crate num;
use num::bigint::BigUint;
use std::cmp::min;
use std::sync::spsc_queue::Queue;
use std::iter::range_inclusive;

fn int_to_biguint(i: int) -> BigUint {
    FromPrimitive::from_int(i).unwrap()
}

#[cfg(not(test))]
fn main() {
    let mut hamming = Hamming::new(1691);

    println!("first 20 Hamming numbers")
    for _ in range_inclusive(0,19) {
        print!("{} ", hamming.next().unwrap());
    }

    println!("\n\n1691st Hamming number");
    println!("{}",hamming.nth(1691-20).unwrap())
}

struct Hamming {
    q2: Queue<BigUint>,
    q3: Queue<BigUint>,
    q5: Queue<BigUint>
}

impl Hamming {
    fn new(n: uint) -> Hamming {
        let h = Hamming {
            q2: Queue::new(n),
            q3: Queue::new(n),
            q5: Queue::new(n)
        };

        h.q2.push(int_to_biguint(1));
        h.q3.push(int_to_biguint(1));
        h.q5.push(int_to_biguint(1));

        h
    }

    fn enqueue(&self, n: BigUint) {
        self.q2.push(n * int_to_biguint(2));
        self.q3.push(n * int_to_biguint(3));
        self.q5.push(n * int_to_biguint(5));
    }

}

impl Iterator<BigUint> for Hamming {
    fn next(&mut self) -> Option<BigUint> {
        let (head2, head3, head5) =
            (   self.q2.peek().unwrap(),
                self.q3.peek().unwrap(),
                self.q5.peek().unwrap());

        let n = min(head2.clone(), min(head3.clone(), head5.clone()));

        if *head2 == n {self.q2.pop();}
        if *head3 == n {self.q3.pop();}
        if *head5 == n {self.q5.pop();}

        self.enqueue(n.clone());
        Some(n)
    }
}

#[test]
fn create() {
    let h = Hamming::new(5);
    h.q2.push(int_to_biguint(1));
    h.q2.push(int_to_biguint(2));
    h.q2.push(int_to_biguint(4));

    let _ = h.q2.peek();
    assert!(h.q2.pop().unwrap() == int_to_biguint(1));
}

#[test]
fn try_enqueue() {
    let h = Hamming::new(5);
    h.enqueue(int_to_biguint(1));
    h.enqueue(int_to_biguint(2));
    h.enqueue(int_to_biguint(3));

    assert!(h.q2.pop().unwrap() == int_to_biguint(1));
    assert!(h.q3.pop().unwrap() == int_to_biguint(1));
    assert!(h.q5.pop().unwrap() == int_to_biguint(1));
    assert!(h.q2.pop().unwrap() == int_to_biguint(2));
    assert!(h.q3.pop().unwrap() == int_to_biguint(3));
    assert!(h.q5.pop().unwrap() == int_to_biguint(5));
 }

#[test]
fn hamming_iter() {
    let mut hamming = Hamming::new(20);
    assert!(hamming.nth(19).unwrap() == int_to_biguint(36));
}<|endoftext|>


<commit_before>extern crate cc;

#[cfg(windows)]
mod windows {
    use std::error::Error;
    use std::{env, fmt, fs, io, process};

    pub fn opencv_include() -> String {
        if let Ok(dir) = env::var("OPENCV_DIR") {
            format!("{}\\include", dir)
        } else {
            eprint!("%OPENCV_DIR% is not set.");
            process::exit(0x0100);
        }
    }

    pub fn opencv_link() {
        if let Err(e) = try_opencv_link() {
            eprint!("Error while building cv-rs: {:?}.", e);
            process::exit(0x0100);
        }
    }

    fn try_opencv_link() -> Result<(), Box<Error>> {
        let opencv_dir = env::var("OPENCV_LIB")?;
        let files = fs::read_dir(&opencv_dir)?.collect::<Vec<_>>();
        let opencv_world = get_opencv_lib_path(files.iter(), "world")?;
        let img_hash = get_opencv_lib_path(files.iter(), "img_hash")?;

        println!("cargo:rustc-link-search=native={}", opencv_dir);
        println!("cargo:rustc-link-lib={}", opencv_world);
        println!("cargo:rustc-link-lib={}", img_hash);
        Ok(())
    }

    fn get_opencv_lib_path<'a, T: Iterator<Item = &'a io::Result<fs::DirEntry>>>(
        files: T,
        name: &str,
    ) -> Result<String, Box<Error>> {
        let opencv_world_entry = files.filter_map(|entry| entry.as_ref().ok()).find(|entry| {
            let file_name = entry.file_name().to_string_lossy().into_owned();
            (file_name.starts_with(&format!("opencv_{}", name))
                || file_name.starts_with(&format!("libopencv_{}", name)))
                && !file_name.ends_with("d.lib")
        });
        let lib = opencv_world_entry.ok_or_else(|| {
            BuildError::new(format!(
                "Cannot find opencv_{} file in provided %OPENCV_LIB% directory",
                name
            ))
        })?;
        let lib = lib.file_name();
        let lib = lib
            .into_string()
            .map_err(|e| BuildError::new(format!("Cannot convert path '{:?}' to string", e)))?;
        // we expect filename to be something like 'open_world340.lib' or
        // 'open_world.340.dll.a', so we just consider everything after the
        // version number is an extension
        let lib_without_extension = lib.trim_end_matches(|c: char| !c.is_numeric());
        Ok(lib_without_extension.into())
    }

    #[derive(Debug)]
    struct BuildError {
        details: String,
    }

    impl BuildError {
        fn new<T: Into<String>>(details: T) -> Self {
            Self {
                details: details.into(),
            }
        }
    }

    impl Error for BuildError {
        fn description(&self) -> &str {
            &self.details
        }
    }

    impl fmt::Display for BuildError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.details)
        }
    }
}

#[cfg(unix)]
mod unix {
    use std::env;

    pub fn opencv_include() -> String {
        if let Ok(dir) = env::var("OPENCV_DIR") {
            format!("{}/include", dir)
        } else {
            "/usr/local/include".into()
        }
    }

    pub fn opencv_link() {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
        println!("cargo:rustc-link-lib=opencv_core");
        println!("cargo:rustc-link-lib=opencv_features2d");
        println!("cargo:rustc-link-lib=opencv_xfeatures2d");
        println!("cargo:rustc-link-lib=opencv_highgui");
        println!("cargo:rustc-link-lib=opencv_img_hash");
        println!("cargo:rustc-link-lib=opencv_imgcodecs");
        println!("cargo:rustc-link-lib=opencv_imgproc");
        println!("cargo:rustc-link-lib=opencv_objdetect");
        println!("cargo:rustc-link-lib=opencv_text");
        println!("cargo:rustc-link-lib=opencv_videoio");
        println!("cargo:rustc-link-lib=opencv_video");
        if cfg!(feature = "cuda") {
            println!("cargo:rustc-link-lib=opencv_cudaobjdetect");
        }
    }
}

#[cfg(windows)]
use windows::*;

#[cfg(unix)]
use unix::*;

fn main() {
    let files = get_files("native");

    let mut opencv_config = cc::Build::new();
    opencv_config
        .cpp(true)
        .files(files)
        .include("native")
        .include(opencv_include());

    if cfg!(not(target_env = "msvc")) {
        opencv_config.flag("--std=c++11");
    }

    if cfg!(feature = "cuda") {
        let cuda_files = get_files("native/cuda");
        opencv_config.files(cuda_files);
    }

    opencv_config.compile("libopencv-wrapper.a");
    opencv_link();
}

fn get_files(path: &str) -> Vec<std::path::PathBuf> {
    std::fs::read_dir(path)
        .unwrap()
        .into_iter()
        .filter_map(|x| x.ok().map(|x| x.path()))
        .filter(|x| x.extension().map(|e| e == "cc").unwrap_or(false))
        .collect::<Vec<_>>()
}
<commit_msg>Allow UNIX users to use the `OPENCV_LIB` environment variable. (#104)<commit_after>extern crate cc;

#[cfg(windows)]
mod windows {
    use std::error::Error;
    use std::{env, fmt, fs, io, process};

    pub fn opencv_include() -> String {
        if let Ok(dir) = env::var("OPENCV_DIR") {
            format!("{}\\include", dir)
        } else {
            eprint!("%OPENCV_DIR% is not set.");
            process::exit(0x0100);
        }
    }

    pub fn opencv_link() {
        if let Err(e) = try_opencv_link() {
            eprint!("Error while building cv-rs: {:?}.", e);
            process::exit(0x0100);
        }
    }

    fn try_opencv_link() -> Result<(), Box<Error>> {
        let opencv_dir = env::var("OPENCV_LIB")?;
        let files = fs::read_dir(&opencv_dir)?.collect::<Vec<_>>();
        let opencv_world = get_opencv_lib_path(files.iter(), "world")?;
        let img_hash = get_opencv_lib_path(files.iter(), "img_hash")?;

        println!("cargo:rustc-link-search=native={}", opencv_dir);
        println!("cargo:rustc-link-lib={}", opencv_world);
        println!("cargo:rustc-link-lib={}", img_hash);
        Ok(())
    }

    fn get_opencv_lib_path<'a, T: Iterator<Item = &'a io::Result<fs::DirEntry>>>(
        files: T,
        name: &str,
    ) -> Result<String, Box<Error>> {
        let opencv_world_entry = files.filter_map(|entry| entry.as_ref().ok()).find(|entry| {
            let file_name = entry.file_name().to_string_lossy().into_owned();
            (file_name.starts_with(&format!("opencv_{}", name))
                || file_name.starts_with(&format!("libopencv_{}", name)))
                && !file_name.ends_with("d.lib")
        });
        let lib = opencv_world_entry.ok_or_else(|| {
            BuildError::new(format!(
                "Cannot find opencv_{} file in provided %OPENCV_LIB% directory",
                name
            ))
        })?;
        let lib = lib.file_name();
        let lib = lib
            .into_string()
            .map_err(|e| BuildError::new(format!("Cannot convert path '{:?}' to string", e)))?;
        // we expect filename to be something like 'open_world340.lib' or
        // 'open_world.340.dll.a', so we just consider everything after the
        // version number is an extension
        let lib_without_extension = lib.trim_end_matches(|c: char| !c.is_numeric());
        Ok(lib_without_extension.into())
    }

    #[derive(Debug)]
    struct BuildError {
        details: String,
    }

    impl BuildError {
        fn new<T: Into<String>>(details: T) -> Self {
            Self {
                details: details.into(),
            }
        }
    }

    impl Error for BuildError {
        fn description(&self) -> &str {
            &self.details
        }
    }

    impl fmt::Display for BuildError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.details)
        }
    }
}

#[cfg(unix)]
mod unix {
    use std::env;

    pub fn opencv_include() -> String {
        if let Ok(dir) = env::var("OPENCV_DIR") {
            format!("{}/include", dir)
        } else {
            "/usr/local/include".into()
        }
    }

    pub fn opencv_link() {
        let cargo_rustc_link_search = env::var("OPENCV_LIB").unwrap_or("/use/local/lib".into());

        println!("cargo:rustc-link-search=native={}", cargo_rustc_link_search);
        println!("cargo:rustc-link-lib=opencv_core");
        println!("cargo:rustc-link-lib=opencv_features2d");
        println!("cargo:rustc-link-lib=opencv_xfeatures2d");
        println!("cargo:rustc-link-lib=opencv_highgui");
        println!("cargo:rustc-link-lib=opencv_img_hash");
        println!("cargo:rustc-link-lib=opencv_imgcodecs");
        println!("cargo:rustc-link-lib=opencv_imgproc");
        println!("cargo:rustc-link-lib=opencv_objdetect");
        println!("cargo:rustc-link-lib=opencv_text");
        println!("cargo:rustc-link-lib=opencv_videoio");
        println!("cargo:rustc-link-lib=opencv_video");
        if cfg!(feature = "cuda") {
            println!("cargo:rustc-link-lib=opencv_cudaobjdetect");
        }
    }
}

#[cfg(windows)]
use windows::*;

#[cfg(unix)]
use unix::*;

fn main() {
    let files = get_files("native");

    let mut opencv_config = cc::Build::new();
    opencv_config
        .cpp(true)
        .files(files)
        .include("native")
        .include(opencv_include());

    if cfg!(not(target_env = "msvc")) {
        opencv_config.flag("--std=c++11");
    }

    if cfg!(feature = "cuda") {
        let cuda_files = get_files("native/cuda");
        opencv_config.files(cuda_files);
    }

    opencv_config.compile("libopencv-wrapper.a");
    opencv_link();
}

fn get_files(path: &str) -> Vec<std::path::PathBuf> {
    std::fs::read_dir(path)
        .unwrap()
        .into_iter()
        .filter_map(|x| x.ok().map(|x| x.path()))
        .filter(|x| x.extension().map(|e| e == "cc").unwrap_or(false))
        .collect::<Vec<_>>()
}
<|endoftext|>